虽然上面我们已经写了很多代码了,也能显示背景了,但是有时候会经常改以前的东西,甚至推翻重做。
下面是读取游戏的要拼的图片了。
首先
,
我们要确定逻辑保存方式
,
我采用的是一个一维数组表示。而且为了可以切割成任意块数,所以定义成了一个指针类型。这是在
CPuzzleLogic
里定义的
- int* m_Block;
- int m_BlockNum;
因为拼图是一个正方形的,所以只用了一个表示横向的有多少块的变量
还要进行初始化,在
CPuzzleLogic
里添加了一个初始化函数,当然现在的函数还做不到真正初始化,只是提供了一种测试方法。
-
- bool CPuzzleLogic::InitLogic(int BlockNum)
- {
- m_BlockNum = BlockNum;
- m_Block = new int[BlockNum*BlockNum];
- for(int i=0; i
- {
- for(int j=0; j
- {
- int num = BlockNum - i -1;
- m_Block[i*BlockNum+j] = num*10+j;
- }
- }
- return true;
- }
-
而且,修改了一个初始化的函数,增加了读取其他图片的功能。不仅仅是读取背景图片了
然后就是
CPuzzleView
类里的内容了。改动较大。请仔细看。
下面还定义了很多必要的变量,主要是表示坐标等等。
-
- bool InitView(HWND hWnd, int BlockNum=3);
- private:
-
- HBITMAP m_hBmpGame;
-
- HBITMAP m_hBmpGameSmall;
-
- static const int m_Small_x=560;
- static const int m_Small_y=70;
- static const int m_Small_width=200;
- static const int m_Small_height=200;
-
- static const int m_Game_x = 70;
- static const int m_Game_y = 100;
- static const int m_Game_width = 400;
- static const int m_Game_height = 400;
- int m_FrameNum;
- int* m_Block;
- bool m_IsGameStarted;
- public:
-
- bool LoadBMPList(int *Block);
-
- void SetGameStarted(bool bStarted);
然后初始化的函数有所改动,增加了一个参数,里面又读取了其他的几个图片。这里面也没什么要特别说明的。
- #define GETX(x) (x+70)
- #define GETY(y) (y+100)
-
- bool CPuzzleView::InitView(HWND hWnd, int BlockNum)
- {
- ……
-
- m_hBmpGame = (HBITMAP)LoadImage(NULL, _T("res//game.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE);
- if(m_hBmpBack == NULL)
- {
- MessageBox(NULL, _T("读取图案文件失败"), _T("Error"), MB_OK);
- return false;
- }
- m_hBmpGameSmall = (HBITMAP)LoadImage(NULL, _T("res//gamesmall.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE);
- if(m_hBmpGameSmall == NULL)
- {
- MessageBox(NULL, _T("读取小图案文件失败"), _T("Error"), MB_OK);
- return false;
- }
- m_FrameNum = BlockNum;
- m_Block = new int[m_FrameNum*m_FrameNum];
- OnPaint();
- return true;
- }
-
- 下一个是以下两个函数,也没什么特别说明的。
-
-
- bool CPuzzleView::LoadBMPList(int *Block)
- {
- memcpy(m_Block, Block, sizeof(int)*m_FrameNum*m_FrameNum);
-
-
- return true;
- }
-
-
-
- void CPuzzleView::SetGameStarted(bool bStarted)
- {
- m_IsGameStarted = bStarted;
- OnPaint();
- }
最关键的是重绘函数,彻底的更改了,上次的教程里只是为了显示一下背景,而现在要显示的东西多了,就不能再用原来的那个了。先看代码:
-
- void CPuzzleView::OnPaint(void)
- {
- HDC hdcMem;
- HDC hdcScr = GetDC(m_hWnd);
- hdcMem = CreateCompatibleDC(hdcScr);
- SelectObject(hdcMem, m_hBmpBack);
-
- HDC hdcSmallMem = CreateCompatibleDC(hdcMem);
- SelectObject(hdcSmallMem, m_hBmpGameSmall);
- BitBlt(hdcMem, m_Small_x, m_Small_y, m_Small_width, m_Small_height, hdcSmallMem, 0, 0, SRCCOPY);
- DeleteDC(hdcSmallMem);
-
- HDC hdcGameMem = CreateCompatibleDC(hdcMem);
- SelectObject(hdcGameMem, m_hBmpGame);
- if(m_IsGameStarted==true)
- {
- for(int i=0; i
- {
- for(int j=0; j
- {
- int x=j*m_Game_width/m_FrameNum;
- int y=i*m_Game_height/m_FrameNum;
- int width=m_Game_width/m_FrameNum;
- int height=m_Game_height/m_FrameNum;
- int srcX=m_Block[j+m_FrameNum*i]%10*(m_Game_width/m_FrameNum);
- int srcY=m_Block[j+m_FrameNum*i]/10*(m_Game_height/m_FrameNum);
- BitBlt(hdcMem, GETX(x), GETY(y), width, height, hdcGameMem, srcX, srcY, SRCCOPY);
- }
- }
- }
- else
- {
- BitBlt(hdcMem, m_Game_x, m_Game_y, m_Game_width, m_Game_height, hdcGameMem, 0, 0, SRCCOPY);
- }
- DeleteDC(hdcGameMem);
-
- if(m_IsGameStarted==true)
- {
-
- HBRUSH hbrNew = CreateSolidBrush(RGB(0x00, 0x00, 0x00));
- HBRUSH hbrOld = (HBRUSH)SelectObject(hdcMem, hbrNew);
- for(int i=0; i<=m_FrameNum; ++i)
- {
- int x=(m_Game_width/m_FrameNum)*(i)-2;
- Rectangle(hdcMem, GETX(x), GETY(0), GETX(x+4), GETY(m_Game_width));
- }
- for(int i=0; i<=m_FrameNum; ++i)
- {
- int y=(m_Game_height/m_FrameNum)*(i)-2;
- Rectangle(hdcMem, GETX(0), GETY(y), GETX(m_Game_height), GETY(y+4));
- }
- SelectObject(hdcMem, hbrOld);
- }
- BitBlt(hdcScr, 0, 0, 800, 600, hdcMem, 0, 0, SRCCOPY);
- DeleteDC(hdcMem);
- DeleteDC(hdcScr);
- }
函数很长,先说一下流程,这个采用的是所谓的“双缓冲”技术。先说说这个“双缓冲”技术,一般的画图的话,就是在屏幕上反复画,而系统画的时候是先清除我们的目标位置,然后再画上去,这种情况如果要画的内容很少,或者不频繁的时候,我们感觉不到什么问题,但是如果在屏幕上画很多东西,比如我们这个,要先画背景,再画右上角的图,再画中间游戏区的很多份图像,如果直接画的话,就会有很大的闪动情况,这个时候,就出现了“双缓冲”技术。
采用“双缓冲”就是先在内存中创建一块区域,使其兼容屏幕,也就是和屏幕一样的,相当于一块画布,我们所有的绘图工作都在这块画布上进行,当画好一张后,直接把整张的画布复制到屏幕上,这样,我们看到的屏幕就只进行了一次重绘工作,画了整个窗口,就不会感觉到闪动了。
大部分代码都有注释,可以看明白,
-
-
- HDC hdcSmallMem = CreateCompatibleDC(hdcMem);
- SelectObject(hdcSmallMem, m_hBmpGameSmall);
- BitBlt(hdcMem, m_Small_x, m_Small_y, m_Small_width, m_Small_height, hdcSmallMem, 0, 0, SRCCOPY);
- DeleteDC(hdcSmallMem);
就是这样的过程。
最麻烦的就是中间游戏区部分。因为我们要把顺序打乱,所以不能直接显示出来那一整张图,要分块显示。如果分块太多,肯定影响性能,因为循环是平方级的。比如分
3
块就是循环
9
次。
来说说这个过程,首先,要在
CPuzzleLogic
类里对逻辑里进行初始化,然后复制给
CPuzzleView
类的
m_Block
,以下就只说
CPuzzleView
类了。
这个
m_Block
是
int
类型的,用十位和个位分别表示纵坐标和横坐标,比如
12
就是横向第
3
块,纵向第
2
块(记住,这些都是从
0
开始的,所以
00
是第一块),因此我们最多只能是
9*9
的分块。
然后就是根据这些数字计算在图片的坐标位置。
因为是顺序从左上角到右下角存储数字,所以根据
i,j
可以得到对应的在窗口上的坐标位置,根据分的块数,计算出来每块的大小。
然后循环显示出来各个小图。
再然后画上分隔的线框。
因为我们要能看出来一共有多少个框,而实际上框没有什么用,在一次游戏中是一样的,其实画线就可以了,不过为了粗细,我实际上是画的矩形。关于函数的具体用法,随便搜一下就有了,我就不解释了。
Rectangle(hdcMem, GETX(x), GETY(0), GETX(x+4), GETY(m_Game_width));//
GET
(
X
)和
GET
(
Y
)是两个宏定义,就是加上了偏移量,这样我们就不用自己每次都去计算坐标了。
在这代码前,你会看到一个绑定画刷的语句。
- HBRUSH hbrNew = CreateSolidBrush(RGB(0x00, 0x00, 0x00));
- HBRUSH hbrOld = (HBRUSH)SelectObject(hdcMem, hbrNew);
- ……
- SelectObject(hdcMem, hbrOld);
我们通过
CreateSolidBrush
函数创建了一个画刷,画刷的作用就是在接下来的画图工作中,每次绘图的颜色,里面的参数是一个
RGB
颜色,想用什么颜色自己设定吧,我写的是
16
进制的形式,写
10
进制也没问题的。
创建了之后将其绑定到内存
DC
中,以后画图的时候就是这个颜色了,等画完图还要把原来的画刷绑定回来。这是个好习惯。
大家会发现我用到了
m_IsGameStarted
变量,是
bool
类型的,我用它来表示游戏是否已经开始。因为只有开始的时候才应该把图片打乱,还有一个在
CPuzzleLogic
里的
m_IsPlaying
的
bool
类型的变量,这个是表示是否在游戏中。
呵呵,这两个变量是不一样的。第一个只表示开始,还是结束,第二个也可以表示,但是最主要的可以表示是否暂停。感觉好乱啊,我也承认。
想想我们的游戏规则,一般的就是开始的时候显示一张完整的图,那个就是我们上面代码里绘制游戏区里的
else
的工作,并且没有线框,所以在绘制线框前也判断了一次。开始后是打乱顺序,然后少一块,所以可以看出来,绘图工作还是有点问题的,不过,那个将是我们下一步的工作。我们也要反复修改代码,尤其是初学者,不可能一次写出完美的代码。
最后等完成的时候,我们再去做一些优化工作,比如哪些函数需要公有,哪些要改成私有的等等。
今天就先到这里吧,如果仅仅是复制代码,或者下载代码,很简单就能结束,不过,那样就达不到学习的目的了,对不?如果只想要个程序,随便去网上下个拼图,人家做的还更好看。
今天的比较长,大家耐心点,有不明白的地方,欢迎和我讨论。
今天的代码:
http://download.csdn.net/source/2700843
-----------------------------------------------------
相关文章:
[原创+连载]一步一步做拼图游戏,C++版(一) student.csdn.net/space.php
[原创+连载]一步一步做拼图游戏,C++版(二)student.csdn.net/space.php
相关代码:download.csdn.net/source/2700843