1.创建一个基于对话框的程序
2.添加如下所示的编辑框,文本框
并设置这几个按钮位置属性如下
3.准备一张背景图,放入res文件夹内,这样,准备工作就做好了,现在来添加代码了
4.添加Gdi+支持(见前文)
5.在主对话框类中添加两个结构
struct Snake
{
int x;//位置
int y;
int direction;//方向
};
struct Food
{
int x;
int y;//位置
};
添加共有成员int m_width;//游戏区宽度
int m_height ;//游戏区高度
Image* img;//背景图
list<Snake>snake;//蛇
Food food;//食物
别忘记添加对list的支持
#include<list>
using std::list;
初始化背景图
在主对话框构造函数中
img = Image::FromFile(_T("res/bkg.jpg"));
6.添加宏,4个方向宏,2个蛇大小宏
#define SNAKE_LEFT 3
#define SNAKE_UP 1
#define SNAKE_RIGHT 2
#define SNAKE_DOWN 0
#define SNAKE_WIDTH 20
#define SNAKE_HEIGHT 20
7.添加定时器消息,初始化在InitInstance()函数中
SetTimer(0, 1000, NULL);
srand(300);
//蛇位置初始化
Snake snakes;
snakes.x = rand() % 300;
snakes.y = rand() % 300;
snakes.direction = rand() % 3;
for (int i = 0; i < 5; i++)
{
snakes.x += SNAKE_WIDTH;
snake.push_back(snakes);
}
//食物初始化
srand(2000);
food.x = rand() % m_width;
food.y = rand() % m_height;
8.添加绘制蛇主体和食物的函数DrawSnake()
void CSnakeDlg::DrawSnake(Graphics & gh)
{
SolidBrush brush(Color(120,0,0,0));
IsHit();
gh.FillRectangle(&brush, RectF(food.x, food.y, SNAKE_WIDTH, SNAKE_HEIGHT));//绘制食物
for (auto &i : snake)
{
gh.FillRectangle(&brush, RectF(i.x, i.y, SNAKE_WIDTH, SNAKE_HEIGHT));//绘制蛇
}
}
再添加碰撞检测函数IsHit()
void CSnakeDlg::IsHit()
{
SnakeRun();
Snake head = snake.back();
if (head.x<0 || head.x>m_width || head.y<0 || head.y>m_height)//撞墙判断
OnCancel();
}
每一帧蛇移动一次,只动蛇头和蛇尾void CSnakeDlg::SnakeRun()
{
//只动蛇头和蛇尾,推断出下一步蛇头的位置,压入列表中 ,然后删除蛇尾
//蛇头是尾元素
Snake snakes = snake.back();
Snake head;
switch (snakes.direction)
{
case SNAKE_LEFT:
head.direction = snakes.direction;
head.x = snakes.x - SNAKE_WIDTH;
head.y = snakes.y;
break;
case SNAKE_DOWN:
head.direction = snakes.direction;
head.x = snakes.x;
head.y = snakes.y+ SNAKE_HEIGHT;
break;
case SNAKE_RIGHT:
head.direction = snakes.direction;
head.x = snakes.x + SNAKE_WIDTH;
head.y = snakes.y;
break;
case SNAKE_UP:
head.direction = snakes.direction;
head.x = snakes.x ;
head.y = snakes.y- SNAKE_HEIGHT;
break;
}
snake.push_back(head);
if(!IsEat())//没有吃到食物就弹出头部
snake.pop_front();
}
是否吃到食物判断bool CSnakeDlg::IsEat()
{
Snake snakes = snake.back();
PointF ptCenter1, ptCenter2;
ptCenter1.X = snakes.x + SNAKE_WIDTH/2;
ptCenter1.Y = snakes.y + SNAKE_HEIGHT/2;
ptCenter2.X = food.x + SNAKE_WIDTH/2;
ptCenter2.Y = food.y + SNAKE_HEIGHT/2;
PointF pt = ptCenter1 - ptCenter2;
if(pt.X<SNAKE_WIDTH&&pt.X>-SNAKE_WIDTH&&pt.Y<SNAKE_HEIGHT&&pt.Y>-SNAKE_HEIGHT)
{
food.x = rand() % m_width;
food.y = rand() % m_height;
return true;
}
return false;
}
9.添加WM_SIZE消息
获取对话框的大小并保存
void CSnakeDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
m_width = cx-100;
m_height = cy;
// TODO: 在此处添加消息处理程序代码
}
10,添加对按键的支持
添加虚函数PreTranslateMessage(),该函数在Windows处理之前拦截按键消息
BOOL CSnakeDlg::PreTranslateMessage(MSG* pMsg)
{
Snake &head = snake.back();
// TODO: 在此添加专用代码和/或调用基类
switch (pMsg->wParam)
{
case VK_LEFT:
if (head.direction != SNAKE_RIGHT)//方向不能相反
head.direction = SNAKE_LEFT;
break;
case VK_RIGHT:
if (head.direction != SNAKE_LEFT)
head.direction = SNAKE_RIGHT;
break;
case VK_UP:
if (head.direction != SNAKE_DOWN)
head.direction = SNAKE_UP;
break;
case VK_DOWN:
if (head.direction != SNAKE_UP)
head.direction = SNAKE_DOWN;
break;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
11.利用双缓冲将该游戏绘制出来
void CSnakeDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDC* pDC = this->GetDC();
CBitmap bmp;
CDC m_dcMemory;
m_dcMemory.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, m_width, m_height);
m_dcMemory.SelectObject(&bmp);
Graphics gh(m_dcMemory.GetSafeHdc());
{
gh.DrawImage(img, 0, 0, m_width, m_height);//背景
DrawSnake(gh);
}
pDC->BitBlt(0, 0, m_width, m_height, &m_dcMemory, 0, 0, SRCCOPY);
CDialogEx::OnPaint();
}
}
12.利用计时器将做出流畅游戏
void CSnakeDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
OnPaint();
CDialogEx::OnTimer(nIDEvent);
}
游戏完成
该游戏还有许多不完善的地方
得分功能没有设计;小蛇自我碰撞检测没有设计,游戏开始暂停也没有设计
效果