这几天跟别人学习制作了一个小游戏,现在分享一下.
贪吃蛇,一个经典的小游戏,
开发环境vs2017
在WinMain函数中,窗口创建显示完成后添加一句SendMessage(hWnd,WM_SIZE,0,0)来调整窗口的大小,
//主函数WinMain()
int WINAPI WinMain(In HINSTANCE hInstance, In_opt HINSTANCE hPrevInstance,
In LPSTR lpCmdLine, In int nShowCmd)
{
//类名
TCHAR cls_name[] = TEXT("MyWinClass");
//设计窗口类
WNDCLASSEX wce = { 0 };
wce.cbSize = sizeof(WNDCLASSEX);
wce.style = CS_HREDRAW | CS_VREDRAW;
wce.lpfnWndProc = WindowProc;
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hInstance = hInstance;
wce.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wce.hIconSm = wce.hIcon;
wce.hCursor = LoadCursor(NULL, IDC_ARROW);
wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);/*::GetStockObject(BLACK_BRUSH)*/ /*黑色刷子*/
wce.lpszMenuName = NULL;
wce.lpszClassName = cls_name;
//注册窗口类
//ATOM nres = RegisterClassEx(&wce);
if (FALSE == RegisterClassEx(&wce))
return 1;
//创建窗口
HWND hWnd = CreateWindowEx(
WS_EX_APPWINDOW,
cls_name,
TEXT("我的窗口"),
WS_OVERLAPPEDWINDOW,
200, 120, 600, 400,
NULL, NULL, hInstance,
NULL);
//回调函数要写上默认的处理DefWindowProc,不然创建失败
if (!hWnd)
return 1;
//显示,更新窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//调整窗口大小
SendMessage(hWnd, WM_SIZE, 0, 0);
//添加加速键表
HACCEL hAccel = NULL;/*::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1);*/
//消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hWnd, hAccel, &msg))//有加速键表时用这,没有就不用
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
2.在WM_SIZE消息中
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
{
hdc = GetDC(hWnd);
RECT crc, wrc;
GetClientRect(hWnd, &crc);
GetWindowRect(hWnd, &wrc);
int bordrewidth=(wrc.right - wrc.left) - (crc.right - crc.left);
int bordreheight = (wrc.bottom - wrc.top) - (crc.bottom - crc.top);
SetWindowPos(hWnd, NULL, 0, 0,
600 + bordrewidth, 600 + bordreheight, SWP_NOMOVE);
OnStart(hWnd); //启动游戏
ReleaseDC(hWnd, hdc);
}break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
这样就固定了窗口大小,不能改变.
3.在窗口上划分格子(我只分了横竖20)
定义全局变量
HDC hdc;
int row = 20; //20行
int col = 20; //20列
#define WIDTH 30 //格子的宽度
#define HEIGHT 30 //格子的高度
#define MAXSIZE 50 //蛇身最大长度
POINT m_food; //随机食物坐标
//定义贪吃蛇的结构体
struct Snake
{
POINT m_pos[MAXSIZE]; //身体每个格子的坐标
int len; //身体个数
int m_direction; //前进方向
}m_snake;
在WM_PAINT消息中添加MyPaint()函数画格子
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = ::BeginPaint(hWnd, &ps);
{
MyPaint(hdc);
}
EndPaint(hWnd, &ps);
}break;
下面就是MyPaint函数的实现
void MyPaint(HDC hdc)
{
HBRUSH hbr = CreateSolidBrush(RGB(255, 0, 0)); //定义红色画刷
HGDIOBJ hOldBrh = SelectObject(hdc, hbr);
for (int y=0;y<row;y++)
{
for (int x=0;x<col;x++)
{
Rectangle(hdc, xWIDTH, yHEIGHT, (x + 1)*WIDTH, (y + 1)*HEIGHT); //画格了,行20,列20
}
}
SelectObject(hdc, hOldBrh);
HBRUSH bhrgreen = CreateSolidBrush(RGB(0, 255, 0)); //绿色画刷
hOldBrh = SelectObject(hdc, bhrgreen);
for (int n=0;n<m_snake.len;n++)
{
Rectangle(hdc, m_snake.m_pos[n].x*WIDTH, m_snake.m_pos[n].y*HEIGHT,
(m_snake.m_pos[n].x+1)*WIDTH,(m_snake.m_pos[n].y+1)*HEIGHT); //画蛇的身体
}
SelectObject(hdc, hOldBrh);
HBRUSH hbrblue = CreateSolidBrush(RGB(0, 0, 255)); //蓝色画刷
hOldBrh = SelectObject(hdc, hbrblue);
Rectangle(hdc, m_food.x*WIDTH, m_food.y*HEIGHT,
(m_food.x + 1)*WIDTH, (m_food.y + 1)*HEIGHT); //画随机食物
}
//随机食物坐标
void generatefood()
{
srand((unsigned)time(NULL));
m_food.x = rand() % 20;
m_food.y = rand() % 20;
}
//初始化蛇
void init_snake()
{
m_snake.len = 3;
m_snake.m_pos[0].x = 0;
m_snake.m_pos[0].y = 0;
m_snake.m_direction = 1;
for (int n = 1; n < MAXSIZE; n++)
{
m_snake.m_pos[n].x = -1;
m_snake.m_pos[n].y = -1;
}
generatefood();
}
下面就是启动游戏了
void OnStart(HWND hWnd)
{
init_snake();
SetTimer(hWnd, 1, 300, NULL); //设置时间
}
在WM_TIMER消息中
case WM_TIMER:
{
//循环输出蛇身位置
for (int n = m_snake.len - 1; n >= 1; n–)
{
m_snake.m_pos[n] = m_snake.m_pos[n - 1];
}
//判断前进方向
if (0 == m_snake.m_direction)//向上
m_snake.m_pos[0].y = m_snake.m_pos[0].y - 1;
if (1 == m_snake.m_direction)//向右
m_snake.m_pos[0].x = m_snake.m_pos[0].x + 1;
if (2 == m_snake.m_direction)//向下
m_snake.m_pos[0].y = m_snake.m_pos[0].y + 1;
if (3 == m_snake.m_direction)//向左
m_snake.m_pos[0].x = m_snake.m_pos[0].x - 1;
//碰到食物蛇身+1,重新随机食物坐标
if (m_snake.m_pos[0].x == m_food.x&&m_snake.m_pos[0].y == m_food.y)
{
m_snake.len++;
generatefood();
}
//判断蛇头碰墙,就Game over
if (m_snake.m_pos[0].x > 19 || m_snake.m_pos[0].y > 19 || m_snake.m_pos[0].x < 0 || m_snake.m_pos[0].y < 0)
{
KillTimer(hWnd, 1);
if (IDYES == MessageBox(hWnd, TEXT(“Game over,你想重新开始吗?”),
TEXT(“提示”), MB_YESNO))
{
OnStart(hWnd);
}
else
{
PostQuitMessage(0);
}
}
hdc = GetDC(hWnd);
MyPaint(hdc);//重绘窗口所有数据
ReleaseDC(hWnd, hdc);
}break;
接下来还有方向控制了,这简单
在WM_KEYDOWN消息中给蛇的m_direction赋值就行了
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_UP:
m_snake.m_direction = 0;
break;
case VK_RIGHT:
m_snake.m_direction = 1;
break;
case VK_DOWN:
m_snake.m_direction = 2;
break;
case VK_LEFT:
m_snake.m_direction = 3;
break;
}
}break;
效果:
当然还有很多少足处,比如蛇的头可以从身体中穿过.
这些以后再弄了,先学习学习嘛