这个练习仍然是3.1键盘消息和3.3定时器消息的组合;所谓贪吃蛇半部指的是我们只做一半,因为完整的需要比较多的时间,至少是个把小时,我们的基础练习尽量在10~20分钟内能够完成,目前还不适合涉及太多的琐碎的地方。
练习主要分2大部分来完成,具体步骤如下:
1. 完成一个字符的定时移动,键盘控制方向:
1.1 定义全局变量 ,自定义格点与pix之间的比例关系,例如 20pix为1个格点,设定游戏区范围是20*16格点,从(10,10)开始,则相对坐标为 (10+20* x)
1.2 处理WM_PAINT消息,在其中先画一个边框(画笔HPEN的使用练习),再画出单个字符(在游戏区的中心位置)
1.3 在WM_CREATE中,开启定时器SetTimer
1.4 处理WM_TIMER消息,根据当前x向和y向及正负,使用字符移动一个格点
1.5 处理键盘消息,实现根据上下左右按键改变运动方向
int gx = 10, gy = 8; //中心位置
int vx = 1, vy = 0; //默认向右移动
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
HPEN hPen = CreatePen(0,3, RGB(0,255,0));
HPEN hOld = (HPEN)SelectObject(hdc, hPen);
Rectangle(hdc, 10,10, 20*20+10, 20*16+10); //画边框
DeleteObject(SelectObject(hdc, hOld));
TextOut(hdc, 10+ 20 *gx, 10 + 20*gy, "*",1); //画字符
EndPaint(hwnd, &ps);
}
break;
case WM_TIMER:
{
gx+=vx;
gy+=vy;
InvalidateRect(hwnd, NULL, TRUE); //重绘
}
break;
case WM_KEYDOWN:
{
switch(wParam)
{
case VK_LEFT: vx = -1; vy = 0; break;
case VK_RIGHT: vx = 1; vy = 0; break;
case VK_UP: vx = 0; vy = -1; break;
case VK_DOWN: vx = 0; vy = 1; break;
default:
break;
}
InvalidateRect(hwnd, NULL, TRUE);
}
break;
2. 完成多个字符(组成一条蛇)的移动,键盘控制方向:
2.1 单个字符的键盘响应移动已经奠定了基础,在此基础上再进一步就需要把蛇的身体(几个字符)造出来,如果是想练习链表就用链表做,需要练习数组就用数组做,练习C++类就用class来做,这次的练习我们来建一个SNAKE的类,成员变量为节数,并用vector相当于建立2个动态数组,分别存放每个节点的x和y的格点值;
2.2 在主函数之前,用SNAKE(i) 创建对象并构造有i个字符的蛇;
2.3 在SNAKE类,建一个showSnake()的成员函数,传递hdc即可
2.4 在WM_PAINT处理中,将TextOut单个字符改换成调用showSnake()进行蛇身各节点的绘制
2.5 在SNAKE类,建一个moveSnake()的成员函数,由于在这个函数将在定时器消息中使用,需要把hdc声明为全局
2.6 在WM_TIMER中,调用moveSnake()函数,实现整条蛇的移动
class SNAKE
{
int size;//蛇的节数
vector <int> vecx, vecy; //使用vector容器
public:
SNAKE(){};
SNAKE(int num)//构造蛇各节
{
size = num;
int x = 10, y = 5;
for (int i = 0; i< num; i++)
{
vecx.push_back(x);
vecy.push_back(y + i);
}
}
};
SNAKE s(8);
void showSnake(HDC hdc)
{
for (int i = 0; i< size; i++)
{
TextOut(hdc, 10+ 20* vecx[i], 10 + 20* vecy[i], "&", 1);
}
}
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
HPEN hPen = CreatePen(0,3, RGB(0,255,0));
HPEN hOld = (HPEN)SelectObject(hdc, hPen);
Rectangle(hdc, 10,10, 20*20+10, 20*16+10); //画边框
DeleteObject(SelectObject(hdc, hOld));
// TextOut(hdc, 10+ 20 *gx, 10 + 20*gy, "*",1); //画字符
s.showSnake(hdc); //画蛇
EndPaint(hwnd, &ps);
}
void moveSnake()
{
for (int i = size-1; i>0;i-- )
{
vecx[i] = vecx[i-1];
vecy[i] = vecy[i-1];
}
vecx[0] = vecx[0] + vx;
vecy[0] = vecy[0] + vy;
}
case WM_TIMER:
{
//gx+=vx;
//gy+=vy;
s.moveSnake(hdc);
InvalidateRect(hwnd, NULL, TRUE); //重绘
}
break;
至此,贪吃蛇的创建、移动以及根据按键改变方向的功能就完成了,当然完整的程序后面还有碰撞检测(包含碰边界死亡、碰自身死亡、碰豆子增加一节...)以及随机放豆子等功能就不在这里练习了。
从3.5,3.6两节练习可以看到,定时器+键盘的灵活搭配,已经可以制作简单的可玩耍的游戏了,这些立竿见影的基本功,还不多多练习?