小游戏贪吃蛇的学习

这几天跟别人学习制作了一个小游戏,现在分享一下.
贪吃蛇,一个经典的小游戏,

开发环境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;

效果:

在这里插入图片描述

在这里插入图片描述

当然还有很多少足处,比如蛇的头可以从身体中穿过.
在这里插入图片描述

这些以后再弄了,先学习学习嘛

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值