图2.创建Win32 Application工程
Win32 Application工程与Win32 Console Application工程有很大的不同(图2)。其主函数是WinMain()函数。创建一个经典的”Hello,World!”工程,就会有已经写好的WinMain()函数。WinMain()函数是整个程序的入口,虽然区区几行。不需要改动什么,但确实最主要的函数。函数定义如下:
APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR int lpCmdLine,int nCmdShow)
在创建好的工程中,还有注册窗口函数和窗口过程函数。
ATOM MyRegisterClass(HINSTANCE hInstance)
注册窗口函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
窗口过程函数
实现贪吃蛇游戏的算法就写在窗口过程函数中。
3.2游戏界面控制
贪吃蛇游戏的游戏界面包括墙的绘制、蛇身体的绘制、蛇移动范围的绘制、食物的绘制、分数框和注释的绘制等等。其中贪吃蛇的身体的绘制,是本程序中的核心算法。
3.2.1墙、框体的绘制
在win32 application工程中,有很多绘制图形的函数。这里最多使用到的是Rectangle()函数绘制矩形。通过坐标控制矩形的两对角点来确定矩形的长、宽、高,通过在窗口中添加画笔和画刷,使用不同的线条颜色和样式,画出所需的图框。如下是墙的绘制:
hpen=CreatePen(PS_SOLID,1,RGB(255,255,255)); hbru=CreateSolidBrush(RGB(255,255,255));
hpenold=(HPEN)SelectObject(hdc,hpen);
hbruold=(HBRUSH)SelectObject(hdc,hbru); Rectangle(hdc,rt.left,rt.top,rt.right,rt.bottom);
SelectObject(hdc,hpenold);
SelectObject(hdc,hbruold); hpen=CreatePen(PS_SOLID,1,RGB(255,100,0));
hpenold=(HPEN)SelectObject(hdc,hpen);
Rectangle(hdc,45,35,615,465);
hbru=CreateSolidBrush(RGB(255,100,0));
hbruold=(HBRUSH)SelectObject(hdc,hbru);
hbruold=(HBRUSH)SelectObject(hdc,hbru); for(i=50;i<=600;i+=10) //画围墙 {
Rectangle(hdc,i,40,i+10,49); //上边 Rectangle(hdc,i,451,i+10,460); //下边 }
for(i=40;i<=450;i+=10) {
Rectangle(hdc,50,i,59,i+10);
Rectangle(hdc,601,i,610,i+10); }
SelectObject(hdc,hbruold); SelectObject(hdc,hpenold);
//创建无色的画笔 //创建无色的画刷
//绘制背景 //恢复笔 //恢复画刷
//创建一支砖红色的笔 //把砖红色的笔选进画板 //创建一支砖红色的画刷 //把砖红色的画刷选进画板 //把砖红色的画刷选进画板
//左边 //右边
程序代码中,各种函数的功能已经备注的很详细,这里不再赘述。在写程序的初期,围墙是用小方格围成的(图3),后来在此基础上做了改动(图4),最后生
成的效果,改变一下画笔,完全可用几句代码来代替,如下: hpen=CreatePen(PS_SOLID,10,RGB(255,100,0));
hpenold=(HPEN)SelectObject(hdc,hpen);
Rectangle(hdc,50,40,610,460);
//创建一支砖红色的笔,只是在画刷的粗
//细上做了改动
//把砖红色的笔选进画板 //画围墙
图3
图4
分数框和注释框是用RoundRect()倒角矩形函数绘制的,和前面的矩形函数用法相同。
3.2.2蛇身的绘制
贪吃蛇的身体的绘制,是程序中的核心算法。包括蛇身的移动、吃食物后增
长、颜色的改变。
首先我们创建了蛇的类,蛇的位置是由坐标控制的,蛇的每一节是10×10
的小方格,x[i],y[i]表示蛇每一节的坐标,node表示蛇的节数,direction表示蛇的方向,life为蛇的生命(0存活1死亡)。开始游戏时,蛇身为两节,在固定的位置出现,然后控制时间移动。蛇的移动放发就是在原先的蛇头前加一节,在用无色的画刷绘制此时的蛇尾,用来“擦出”最后一节,这样便形成了蛇的移动。
old_pos_x=snake.x[snake.node-1]; old_pos_y=snake.y[snake.node-1];
//保存移动前蛇尾x的坐标 //保存移动前蛇尾y的坐标
hpen=CreatePen(PS_SOLID,1,RGB(255,255,255)); //创建一支无色的笔 hbru=CreateSolidBrush(RGB(255,255,255)); hpenold=(HPEN)SelectObject(hdc,hpen);
//创建一支无色的画刷
//把无色的笔选进画板
hbruold=(HBRUSH)SelectObject(hdc,hbru);
//把无色的画刷选进画板
Rectangle(hdc,old_pos_x,old_pos_y,old_pos_x+10,old_pos_y-10); //用无色的笔绘制蛇尾
Rectangle(hdc,old_pos_x,old_pos_y,old_pos_x+10,old_pos_y-10); //用了无色的画刷绘制背景 SelectObject(hdc,hpenold); //恢复有色的笔 SelectObject(hdc,hbruold); //恢复画刷
for(i=snake.node-1;i>0;i--) //蛇的每个环节往前移动 { snake.x[i]=snake.x[i-1]; snake.y[i]=snake.y[i-1]; }
当蛇头的坐标和食物的坐标重合,就表明蛇吃到食物了,此时蛇要增长,将原来的食物用无色的笔“擦除”,node+1。如下:
if(snake.x[0]==food.x&&snake.y[0]==food.y) {
//吃到食物后
}
hpen=CreatePen(PS_SOLID,1,RGB(255,255,255));//创建一支无色的笔 hpenold=(HPEN)SelectObject(hdc,hpen); //把无色的笔选进画板
Rectangle(hdc,food.x,food.y,food.x+10,food.y-10);//用无色的笔绘制食物以取消 //被吃掉的食物 SelectObject(hdc,hpenold); //恢复有色笔
在程序完成之后,我又添加了闯关模式的功能,其中每过一关,蛇的颜色就会改变,这是使用switch-case语句,每一关都改变绘制蛇的画笔和画刷来实现的。
3.2.3食物的绘制
确定用坐标绘制贪吃蛇蛇身以后,贪吃蛇的食物如何达到随机出现,蛇吃完食物后再次出现的食物不与蛇身相重合,并且能够按照网格式与蛇头无偏差相接就是一个亟待解决的问题。
随机出现应采用rand()函数来实现,使食物随机出现在蛇可以运动的范围内;使用语句“food.x=rand()@0+60;food.y=rand()50+60;”,让食物的坐标产生在墙内来;而食物与蛇头无偏差相接则用if语句判断生成的坐标是否可用最小网格的间距整除处理。使随机出现的点能够整除最小网格,也就是使食物与蛇头无偏
差相接。
在游戏运行的过程中,经常会出现新出现的食物与蛇身重叠的情况,让玩家看不清食物到底在哪。经过认真的考虑,解决这个问题的办法就是,每次随机出现食物坐标时,用循环语句判断要出现的食物坐标是否与蛇身某一节的坐标重合,若是重合,重新生成一组随机数,再次判断,直到不重合时在画面上显示新食物。代码如下:
for(i=2;i food.x=rand()@0+60; food.y=rand()50+60; if(food.x!=snake.x[i]) break; } 再由食物坐标(food.x,food.y)与蛇头坐标是否相同判断蛇是否“吃”到了食物,设置判断标签food.yes,如果吃到了,food.yes为0,则再出现下一个食物,反之,如果没吃到,则不出现食物直到标签为0为止。 代码如下: //随机数发生器 //食物标记:1表示需要出现新食物,0表示已存在食物 //需要出现新食物 srand((unsigned)time(NULL)); food.yes=1; if(food.yes==1) { food.x=rand()@0+60; food.y=rand()50+60; while(food.x!=0)//食物随机出现后必须让食物能在整格内,这样才能让蛇吃到 food.x++; while(food.y!=0) food.y++; food.yes=0; //画面上有食物了 } hpen=CreatePen(PS_SOLID,1,RGB(255,255,255)); //创建一只无色的笔 hbru=CreateSolidBrush(RGB(0,0,0)); //创建一支黑色的画刷 hpenold=(HPEN)SelectObject(hdc,hpen); //把无色的笔选进画板 hbruold=(HBRUSH)SelectObject(hdc,hbru); //把黑色的画刷选进画板 if(food.yes==0) //画面上有食物就显示 { Rectangle(hdc,food.x,food.y,food.x+10,food.y-10); }