一、数据分析
1、窗口显示
基本的思路是:让GameApp从WinApp派生,里面有一个m_pMainWnd指针,然后在InitInstance()中new一个GameWnd对象,m_pMainWnd指向它。
然后m_pMainWnd调用显示窗口、更新窗口的函数。
2、全局数据及读取
GameWnd::GameWnd()//进行相关的数据初始化
{
Create(NULL,"创建窗口");
bitmap->m_hObject=LoadImage()//加载位图数据
....
}
二、行走分析
OnKeyDown()来处理人物上、下、左、右的走动。它会做这样的处理,case vk_**,比如**=3,当方向不是这个方向时,dir = **,index = 0; 置初始图片bitmap[dir,index],这样的话,从A方向跳到B方向,这时是B方向初始图片的第一个位置。
参考15.32
用链表保存行走路径并回放的方法:
struct list
{
int m;//入口格的行数
int n;//入口格的列数
int x;//x方向移动的值
int y;//y方向移动的值
struct list *next;//前节点
struct list *back;//后节点
CBitmap* bitmap;//保存人物图像的地址
}list* ptr,*preptr,*first;//当前节点地址,上一个节点的地址,第一个节点的地址
//--------------------
//在窗口类构造函数,初始化
ptr->m = m;//全局变量,人物的初始格子所在行
ptr->n = n;//人物初始格子所在列
ptr->bitmap = bitmap[0][0];//人物的初始图片
ptr->next = NULL;
prt->back = NULL;
first = prt;//链表的首节点
//-----------------
//OnKeyDown中,用ptr记录当前人物的位置
//下面之前的代码已经计算了,方向键按下时,x,y的值,还有索引图片的dir,index值
ptr->next = (list*)malloc(sizeof(list));
prt->next->m = m;//初始值
ptr->next->n = n;
ptr->next->x=x;
ptr->next->y=y;
ptr->next->bitmap=bitmap[dir][index];
preptr=ptr;//上一个节点值,first
ptr->next->next=NULL;//ptr-next是当前要加入的节点
ptr = ptr->next;//preptr已经指向了当前节点,ptr可正式指向要加入的节点
ptr ->back=preptr;//ptr当前节点的上一个节点是preptr
//----------------
//回放功能实现:在OnKeyDown出口判断处,置bool变量go=TRUE;在OnTimer函数中,作为一个判断的标志,再调用回放功能函数Go();
//回放函数Go()的实现,里面会由OnTimer自动调用
m = first->m
n = first->n
x = first->x
y = first->y;
mdc->SelectObject(wall);//选背景图到内存dc
for()//循环遍历maze[i][j],=1时,说明是墙壁,
dc.BitBlt(j*93,i*100,93,100,mdc,0,0,SRCCOPY);
mdc->SelectObject(first->bitmap)
if(first->back !=NULL)
dc.BitBlt(first->back->n*93+first->back->x,first->back->m*100+first->back->y,93,100,mdc,0,0,WHITENESS);//显示白色,涂抹掉前面的图片
dc.BitBlt(first->n*93+first->x,first->m*100+first->y,93,100,mdc,0,0,SRCCOPY);
if(first->next=NULL)
{
go = false;
}
else
first = first->next;//取下一个节点值,first已经是记录最后的一个节点了,再次走时,走到出口处,将从这里开始再次回放。
2、判断障碍功能的实现
void GameWnd::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
nChar==VK_DOWN;//根据这个标记,判断方向键是否按下
//1. 计算下一步的显示的位置,即改变x,y,
//2. 通过x,y计算其所在maze[8][8]的格,获取maze[Index_x][Index_y]的索引值
//3. 判断索引值是否是空格标记,如果不是,在不改变x,y
}
三、其他分析
第一次响应WM_PAINT,应该是创建窗口之后的,UpdateWindow()发送的,其调用OnPaint(),必须调用CPaintDC dc(this);其中构造函数中有,EndPaint,来通知系统无效区域解除,否则系统将WM_PAINT移除队列,会不断发送WM_PAINT消息。
CClientDC局部变量在析构时,不会向窗口发送WM_PAINT。在该游戏中,CClientDC在绘制时,只不过是时间落后与OnPaint()而已。CPaintDC会调用EndPaint,而改成CClientDC不会,从而在局部销毁时不断发送WM_PAINT消息
BeginPaint独占显示卡,最后必须调用EndPaint释放掉独占的显示卡
1.1~1.4,下走4幅图片
2.1~2.4,左走4幅图片
3.1~3.4,右走4幅图片
4.1~4.4,向上走4副图片
char ch[8];保存图片名称
sprintf(ch,"%d.%d.bmp",i+1,j+1);//这样将图片的文件名转化成字符串ch[8]中,
三、总结
1、在窗口类GameWnd的构造函数中,就把所有数据加载到内存当中,并对全局数据进行初始化。
2、在窗口结束时,都没有释放掉句柄,最终由操作系统来释放。
3、将链表list的数据结构直接写到了游戏的代码中,这样不用去写一个链表list类。
参考:1、从新手到高手:C++全方位学习15.1