C++做拼图游戏.docx
《C++做拼图游戏.docx》由会员分享,可在线阅读,更多相关《C++做拼图游戏.docx(66页珍藏版)》请在冰豆网上搜索。
![C++做拼图游戏.docx](https://file1.bdocx.com/fileroot1/2023-1/31/adbe959a-40b4-4066-8e7c-042b5fcaebe3/adbe959a-40b4-4066-8e7c-042b5fcaebe31.gif)
C++做拼图游戏
一步一步做拼图游戏,C++版
首先,我们就要抛弃控制台的黑洞洞的窗口了,我们必须要先创建一个Windows的窗口。
创建的方法有很多,不过呢,要先确定你将要使用的编译器,VC6.0,VS2005,VS2008,VS2010,DEV-C++,Code:
:
Block等等,还有一个C++Builder和其他的不太一样。
我用的是VS2010Team版,Win7系统。
所以我就以VS2010为例子了。
其他的也差不多。
一、创建窗口:
1. 文件->新建->项目->Win32项目,写上名字,点确定。
如图
2. 在新窗口中点下一步,直接点完成也可以,直接点完成的就可以跳过第3步。
3. 在这个窗口中要选择windows应用程序,不要选空项目,再点确定,如图:
这些完了之后,就会出现Puzzle.cpp文件,里面就是代码。
解决方案管理器里会有其他的东西,如图所示:
可以看到有很多文件,双击打开后都有注释写着每个文件的用处,我们目前只用到Puzzle.cpp,当然,如果你起的是别的名字,就和我的不同了。
现在编译,运行就可以看到一个白色的窗口,里面什么都没有。
然后,我们还要进行一点其他的修改工作:
找到下面的一段代码
Code:
1.BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
2.{
3. HWND hWnd;
4.
5. hInst = hInstance; //
6.
7. hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX, //这里修改了,让WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX的目的是去掉最大化的按钮,同时禁止修改窗口大小
8. CW_USEDEFAULT, 0, /*CW_USEDEFAULT, 0*/800, 600, /*这里的800和600就是窗口的大小,我采用的是800*600的,大家自己根据实际情况改*/NULL, NULL, hInstance, NULL);
9.……
10.}
二、制作一些其他需要的资源
现在有窗口了,那么,我们要有其他的资源,比如各种图片,声音,还可以有鼠标指针。
我们先制作图片就行了,声音,鼠标指针以后再说。
因为图片资源是必须的,其他的是可选的。
我们需要一张背景图片。
随便找张图片,选个大小,我当然选的是800*600的。
然后打开PS去修改吧,我不教PS了,我改的结果是这样的,里面还有一些坐标要记下来的。
如图:
再来一张没坐标的,可以直接下载用。
不过因为CSDN的相册空间太小,所以给个地址吧,链接到XX相册,大家见谅。
记住,保存成BMP格式的,因为BMP的读取起来很容易,如果是JPG的,还要自己去写相应的读取函数。
转换的方法就是用画图打开图片,然后选择“文件->另存为->BMP(24位)”
然后,还要一张用来进行游戏的图,也就是要拼的图,这个更简单了,弄张400*400的就行了(因为我的游戏区大小是400*400)。
到现在为止,我们的准备工作已经完成了。
下面,就是编写代码的过程了。
三、设计功能
1.定义类
CPuzzleLogic,用来实现内部逻辑的行为
CPuzzleView, 用来实现视图显示方面的
CPuzzleMain 用来实现主程序,主要是把各部分的联系起来
如果还有其他需要的,以后再定义别的
创建类的时候可以用类向导,不过,VS2008和VS2005里没有,所以用以下方法:
先把解决方案管理器调到类视图里,在项目名称上单击鼠标右键,添加,类
选“C++类”,单击“添加”,在新窗口中写上类名,单击“确定”
如上图,再重复添加其他两个类。
在CPuzzleMain类的头文件上面的#pragmaonce后面加上
#include"PuzzleLogic.h"
#include"PuzzleView.h"
2.给类相应的功能
先在CPuzzleMain类里添加两个成员变量,分别是其他两个类的类型,用来以后引用里面的功能。
添加方法如下图:
在类视图里右键单击类名称,添加,添加变量
选成private可以防止类外访问到它,写上变量类型和变量名称,然后可以写几句注释
以同样的方法再添加另一个变量,当然,你也可以直接在头文件里写上,效果是一样的,只是这样的做法可以自动初始化系统有的类型,否则有时候会出错。
3.添加画图功能
我们设计一个画图的函数,这样的话,以后就不必每次都去写画图函数了
添加函数的方法:
在类视图里右键单击类名称,添加,添加函数,参考添加变量的图
在新窗口中输入返回类型,函数名,函数的参数,以及注释等等信息。
这样的好处是点击完成的时候,系统会自动添加到头文件中声明,和.cpp文件中的定义部分。
然后写代码吧。
(1)要先在CPuzzleView里加上两个成员变量
private:
HWNDm_hWnd;// 保存窗口句柄
HBITMAPm_hBmpBack;//保存背景图片
(2)把前面做好的图片复制到源代码文件夹的res文件夹里,如果没有的话,就自己新建一个,当然你也可以写别的名字,不过要自己记住,我这里就以res为例子。
(3)添加以下几个函数
Code:
1.// 画图,hBitmap表示指向图片的指针,x,y表示位图显示的横纵坐标,nWidth,nHeight位图的宽度和高度,srcX,srcY从位图的的哪个位置开始显示
2.void CPuzzleView:
:
DrawPic(HBITMAP hBitmap, int x, int y, int nWidth, int nHeight, const int srcX=0, const int srcY=0)
3.{
4. HDC hdcMem; //内存DC
5. HDC hdcScr = GetDC(m_hWnd); //获取屏幕的DC
6. hdcMem = CreateCompatibleDC(hdcScr); //创建兼容屏幕的内存DC
7. SelectObject( hdcMem, hBitmap ); //将图片绑定内存DC上
8. BitBlt( hdcScr, x, y, nWidth, nHeight, hdcMem, srcX, srcY, SRCCOPY ); //将内存DC里的东西画到屏幕上
9. DeleteDC(hdcMem); //清除两个DC
10. DeleteDC(hdcScr);
11.}
12.
13.// 初始化图像显示的对象
14.bool CPuzzleView:
:
InitView(HWND hWnd)
15.{
16. m_hWnd = hWnd; //将窗口句柄传进来
17. m_hBmpBack = (HBITMAP)LoadImage(NULL, _T("res\\background.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE);//读取图片文件
18. if(m_hBmpBack == NULL)
19. {
20. MessageBox(NULL, _T("读取背景文件失败"), _T("Error"), MB_OK);
21. return false;
22. }
23. DrawPic(m_hBmpBack, 0, 0, 800, 600);//画背景
24. return true;
25.}
26.
27.// 用于重绘
28.void CPuzzleView:
:
OnPaint(void)
29.{
30. DrawPic(m_hBmpBack, 0, 0, 800, 600);//重绘背景
31.}
在CPuzzleMain类里添加函数
Code:
1.// 执行初始化工作
2.bool CPuzzleMain:
:
InitMain(HWND hWnd)
3.{
4. m_View.InitView(hWnd);
5. return false;
6.}
7.// 用来重绘
8.void CPuzzleMain:
:
OnPaint(void)
9.{
10. m_View.OnPaint();
11.}
12.
然后,在Puzzle.cpp中,也就是系统自动生成的文件里添加全局变量及头文件引用
#include"PuzzleMain.h"
CPuzzleMaing_PuzzleMain;//保存游戏实例
在下面的BOOLInitInstance(HINSTANCEhInstance,intnCmdShow)函数中,return前加上游戏的初始化代码
g_PuzzleMain.InitMain(hWnd);
在消息循环的函数中,找到
Code:
1.LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2.{
3.…
4.case WM_PAINT:
5. hdc = BeginPaint(hWnd, &ps);
6. // TODO:
在此添加任意绘图代码...
7. g_PuzzleMain.OnPaint();//添加绘图代码
8. EndPaint(hWnd, &ps);
9. break;
10.…
11.}
好了,现在编译并运行程序,就可以显示出来背景了。
简单介绍一下,在OnPaint()里会看到HDC类型的变量,比如
HDChMem;这是声明了一个内存DC,所谓DC,网上说的是设备描述表(DeviceContext,DC),设备描述表(DeviceContext,DC)是一个信息结构体,包含物理输出设备及其驱动程序。
在Windows平台下,所有的图形操作都是通过它完成。
不用管他是什么结构体,只要知道用它可以操作图形图像,想显示在显示器里就要创建一个兼容显示设备的DC,然后就可以显示了,比如
Code:
1.HDC hdcMem;m; //内存DC
2. HDC hdcScr = GetDC(m_hWnd); //获取屏幕的DC
3. hdcMem = CreateCompatibleDC(hdcScr); //创建兼容屏幕的内存DC
4. SelectObject( hdcMem, hBitmap ); //将图片绑定内存DC上
5. BitBlt( hdcScr, x, y, nWidth, nHeight, hdcMem, srcX, srcY, SRCCOPY ); //将内存DC里的东西画到屏幕上
这个过程是先创建内存DC,然后获取了屏幕DC,再设置内存DC兼容屏幕DC,其实就是这两个的信息是一致的了,然后把图片绑定到内存DC里,这样,内存DC里就有了图片,但是,这时还看不到图片,我们最后用BitBlt函数把内存DC里的东西复制到屏幕DC上,这样就能显示出来,我们就看到了。
如果还是不明白的话,请上网XX,Google一下,有很多解释的。
Code:
1.case WM_PAINT:
2. hdc = BeginPaint(hWnd, &ps);
3. // TODO:
在此添加任意绘图代码...
4. g_PuzzleMain.OnPaint();//添加绘图代码
5. EndPaint(hWnd, &ps);
6. break;
WM_PAINT是windows应用程序的重绘消息,当收到这个消息的时候,就意味着屏幕要发生变化了,需要重绘,一般的,当你把窗口移到屏幕外,再移回来,就要发生重绘等等,我们在这加上重绘代码,使我们的程序在移动或者被覆盖的时候还能显示回来。
虽然上面我们已经写了很多代码了,也能显示背景了,但是有时候会经常改以前的东西,甚至推翻重做。
下面是读取游戏的要拼的图片了。
首先,我们要确定逻辑保存方式,我采用的是一个一维数组表示。
而且为了可以切割成任意块数,所以定义成了一个指针类型。
这是在CPuzzleLogic里定义的
Code:
1.int* m_Block; //用来保存当前局面的
2. int m_BlockNum; //保存此局横向要分成多少块
因为拼图是一个正方形的,所以只用了一个表示横向的有多少块的变量
还要进行初始化,在CPuzzleLogic里添加了一个初始化函数,当然现在的函数还做不到真正初始化,只是提供了一种测试方法。
Code:
1.// BlockNum为要切割的方块数,只在横向或纵向的
2.bool CPuzzleLogic:
:
InitLogic(int BlockNum)
3.{
4. m_BlockNum = BlockNum;
5. m_Block = new int[BlockNum*BlockNum];
6. for(int i=0; i7. {
8. for(int j=0; j9. {
10. int num = BlockNum - i -1;
11. m_Block[i*BlockNum+j] = num*10+j;
12. }
13. }
14. return true;
15.}
16.
而且,修改了一个初始化的函数,增加了读取其他图片的功能。
不仅仅是读取背景图片了
然后就是CPuzzleView类里的内容了。
改动较大。
请仔细看。
下面还定义了很多必要的变量,主要是表示坐标等等。
Code:
1.// 初始化图像显示的对象
2. bool InitView(HWND hWnd, int BlockNum=3);
3.private:
4. //保存图案
5. HBITMAP m_hBmpGame;
6. //保存小图案
7. HBITMAP m_hBmpGameSmall;
8. //右上角的坐标及大小
9. static const int m_Small_x=560;
10. static const int m_Small_y=70;
11. static const int m_Small_width=200;
12. static const int m_Small_height=200;
13. //图片游戏区的大小及坐标
14. static const int m_Game_x = 70;
15. static const int m_Game_y = 100;
16. static const int m_Game_width = 400;
17. static const int m_Game_height = 400;
18. int m_FrameNum;//表示要分隔的块数(一排的)
19. int* m_Block;//表示当前状态
20. bool m_IsGameStarted;//游戏是否已经开始
21.public:
22. // 读取图像列表(就是拆开图像)
23. bool LoadBMPList(int *Block);
24. // 设置游戏是否已经开始
25. void SetGameStarted(bool bStarted);
然后初始化的函数有所改动,增加了一个参数,里面又读取了其他的几个图片。
这里面也没什么要特别说明的。
Code:
1.#define GETX(x) (x+70)
2.#define GETY(y) (y+100)
3.// 初始化图像显示的对象
4.bool CPuzzleView:
:
InitView(HWND hWnd, int BlockNum)
5.{
6. ……
7. //读取图案
8. m_hBmpGame = (HBITMAP)LoadImage(NULL, _T("res\\game.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE);
9. if(m_hBmpBack == NULL) //判断是否读取图片成功
10. {
11. MessageBox(NULL, _T("读取图案文件失败"), _T("Error"), MB_OK);
12. return false;
13. }
14. m_hBmpGameSmall = (HBITMAP)LoadImage(NULL, _T("res\\gamesmall.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE);
15. if(m_hBmpGameSmall == NULL) //判断是否读取图片成功
16. {
17. MessageBox(NULL, _T("读取小图案文件失败"), _T("Error"), MB_OK);
18. return false;
19. }
20. m_FrameNum = BlockNum;
21. m_Block = new int[m_FrameNum*m_FrameNum];//这个就是申请内存空间
22. OnPaint();
23. return true;
24.}
25.
26.下一个是以下两个函数,也没什么特别说明的。
27.
28.// 读取图像列表(就是拆开图像)
29.bool CPuzzleView:
:
LoadBMPList(int *Block)
30.{
31. memcpy(m_Block, Block, sizeof(int)*m_FrameNum*m_FrameNum);
32. //m_Block = Block;
33. //OnPaint();
34. return true;
35.}
36.
37.
38.// 设置游戏是否已经开始
39.void CPuzzleView:
:
SetGameStarted(bool bStarted)
40.{
41. m_IsGameStarted = bStarted;
42. OnPaint();
43.}
最关键的是重绘函数,彻底的更改了,上次的教程里只是为了显示一下背景,而现在要显示的东西多了,就不能再用原来的那个了。
先看代码:
Code:
1.// 用于重绘
2.void CPuzzleView:
:
OnPaint(void)
3.{
4. HDC hdcMem; //内存DC
5. HDC hdcScr = GetDC(m_hWnd); //获取屏幕的DC
6. hdcMem = CreateCompatibleDC(hdcScr); //创建兼容屏幕的内存DC
7.