Win32 贪吃蛇游戏

#include<windows.h>
#include <time.h>
#include "resource.h"

#define WIN_WIDTH  830           // 窗口宽度
#define WIN_DEPTH  540           // 窗口长度

#define GAMEZONE_LEFT   10       // 游戏区域左
#define GAMEZONE_TOP    10       // 游戏区域顶
#define GAMEZONE_RIGHT  690      // 游戏区域右
#define GAMEZONE_BUTTOM 490      // 游戏区域底

#define TIPZONE_LEFT    700      // 提示区域左
#define TIPZONE_RIGHT   800      // 提示区域右
#define TIPZONE_TOP     10       // 提示区域顶
#define TIPZONE_BUTTOM  490      // 提示区域底

#define BOXSIZE   10             // 盒子大小

#define LEFT      1001           // 左移
#define RIGHT     1002           // 右移
#define UP        1003           // 上移
#define DOWN      1004           // 下移

#define MAXSIZE    1000           // 最大长度
#define START_X    50            // 开始区域
#define START_Y    50            // 开始区域

#define SCORE_PER_FOOD 10        // 每吃一个食物所得分数

/*   变量声明   */
typedef struct{
	int num;
	int pos_x, pos_y;
	int dir;
	int color_r, color_g, color_b;
}SNAKE;
static SNAKE snake[MAXSIZE];                              // 蛇数组
static int snake_length = 3;                              // 蛇开始长度
static BOOL bump_flag = 0;                                // 撞车标志
static int gameZome[GAMEZONE_RIGHT][WIN_DEPTH];           // 游戏区域
static SNAKE Food;                                        // 食物位置
static int makefoodflag = 1;                              // 产生食物
HWND hwndBut1,hwndBut2,hwndBut3;                          // 按钮
HWND hwndEdit1, hwndEdit2, hwndEdit3;					  // 静态文本框
static int score = 0;                                     // 分数
static int current_speed = 100;                           // 当前速度
TCHAR szbuf[50] = L"";
                                  // 
/******          函数说明        *******/
void DrawBk(HDC);                                                     // 画背景
void AddNode(SNAKE);                                                  // 添加结点
SNAKE SetNode(int x,int y, int dir, int r,int g, int b);              // 获得一个新接点
void DrawBox(HDC, SNAKE);                                             // 画小方块
void MoveSnake();                                                     // 移动蛇
void DrawSnake(HDC);                                                  // 画蛇
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);                 // 窗口回调函数
BOOL IsBump();                                                        // 判断是否撞击,如果撞击返回1,否则返回0
void InitGame();                                                      // 初始化游戏
void DrawGameZone(HDC);                                               // 画出游戏区域(test)
BOOL IsBump();                                                        // 判断是否相撞
void MakeFood();                                                      // 随机在游戏区域内产生一个结点  

// 主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	HWND hwnd;
	MSG msg;
	TCHAR szAppName[] = L"Win32";
	WNDCLASS wndcls;

	wndcls.style = CS_HREDRAW | CS_VREDRAW|CS_NOCLOSE;
	wndcls.cbClsExtra = 0;
	wndcls.cbWndExtra = 0;
	wndcls.hInstance = hInstance;
	wndcls.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));         // 手动添加资源
	wndcls.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));   // 手动添加资源
	wndcls.hbrBackground = static_cast<HBRUSH>(GetStockObject(LTGRAY_BRUSH));
	wndcls.lpfnWndProc = WinProc;
	wndcls.lpszMenuName = NULL;
	wndcls.lpszClassName = szAppName;

	if (!RegisterClass(&wndcls)){
		MessageBox(NULL, L"注册窗口失败,该程序必须运行在windows操作系统下!", L"Tips", MB_ICONINFORMATION);
		return 0;
	}

	hwnd = CreateWindow(szAppName,
		L"Snake", WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX^WS_THICKFRAME,
		50, 50, WIN_WIDTH, WIN_DEPTH, NULL, NULL, hInstance, NULL);
	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return static_cast<int>(msg.wParam);
}


LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
	HDC hdc;
	PAINTSTRUCT ps;
	TEXTMETRIC tm;
	SNAKE sk;
	static HINSTANCE hInstance;
	static int time_counter = 0;
	static int keydown = 0;

	static int cxChar, cyChar, cxCaps;
	switch (message){
	case WM_CREATE:
		srand(time(0));
		hwndBut1  = CreateWindow(L"BUTTON", L"新游戏",WS_CHILD | WS_VISIBLE, GAMEZONE_RIGHT + 20, TIPZONE_TOP + 20, 80, 20, hwnd, (HMENU)1, hInstance, NULL);
		hwndBut2  = CreateWindow(L"BUTTON", L"暂停",WS_CHILD | WS_VISIBLE, GAMEZONE_RIGHT + 20, TIPZONE_TOP + 60, 80, 20, hwnd, (HMENU)2, hInstance, NULL);
		hwndBut3  = CreateWindow(L"BUTTON", L"退出", WS_CHILD | WS_VISIBLE, GAMEZONE_RIGHT + 20, GAMEZONE_TOP + 100, 80, 20, hwnd, (HMENU)3, hInstance, NULL);
		hwndEdit1 = CreateWindow(L"EDIT", L"分数:0", WS_CHILD | WS_VISIBLE | ES_READONLY, GAMEZONE_RIGHT + 20, TIPZONE_TOP + 200, 80, 20, hwnd, (HMENU)4, hInstance, NULL);
		hwndEdit2 = CreateWindow(L"EDIT", L"关卡:1", WS_CHILD | WS_VISIBLE | ES_READONLY, GAMEZONE_RIGHT + 20, TIPZONE_TOP + 240, 80, 20, hwnd, (HMENU)5, hInstance, NULL);
		hwndEdit3 = CreateWindow(L"EDIT", L"时间:0", WS_CHILD | WS_VISIBLE | ES_READONLY, GAMEZONE_RIGHT + 20, TIPZONE_TOP + 280, 80, 20, hwnd, (HMENU)6, hInstance, NULL);
		InitGame();                                  // 初始化游戏区域
		hdc = GetDC(hwnd);
		SetTimer(hwnd, 1, current_speed, NULL);
		ReleaseDC(hwnd, hdc);
	return 0;
	case WM_COMMAND:{
						switch (LOWORD(wParam)){
						case 1: {// 新游戏
									KillTimer(hwnd, 1);
									int sel = MessageBox(hwnd, L"开始新游戏?", L"新游戏", MB_OKCANCEL | MB_ICONQUESTION);
									if (sel == IDOK){
										memset(snake, 0, sizeof(snake) / sizeof(SNAKE));
										RECT rect;
										GetClientRect(hwnd, &rect);
										InitGame();
										score = 0;
										SetTimer(hwnd, 1, current_speed, NULL);
										SetWindowText(hwndEdit1, L"分数:0");
										InvalidateRect(hwnd, &rect, TRUE);
									}
									else {
										SetTimer(hwnd, 1, current_speed, NULL);
										SetFocus(hwnd);
									}
						}break;
						case 2: 
							GetDlgItemText(hwnd, 2, szbuf, 50);
							if (lstrcmp(szbuf, L"暂停") == 0){
								KillTimer(hwnd, 1);
								SetDlgItemText(hwnd, 2, L"开始");
							}
							else if (lstrcmp(szbuf, L"开始") == 0){
								SetTimer(hwnd, 1, current_speed,NULL);
								SetDlgItemText(hwnd, 2, L"暂停");
								SetFocus(hwnd);
							}
							break;
						case 3:{ // 退出
								   KillTimer(hwnd, 1);
								   int sel = MessageBox(hwnd, L"退出游戏?", L"退出", MB_OKCANCEL|MB_ICONINFORMATION);
								   if (sel == IDOK){
									   PostQuitMessage(0);
									   return 0;
								   }
								   SetTimer(hwnd, 1, current_speed, NULL);
								   SetFocus(hwnd);
						}break;
						case 4:
						case 5:
						case 6: SetFocus(hwnd); break;
						}
	}return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);	
		DrawBk(hdc);
		GetTextMetrics(hdc, &tm);
		SetTextColor(hdc, RGB(57, 50, 244));
		SetBkColor(hdc, RGB(22, 123, 22));
		cyChar = tm.tmHeight;
		TextOut(hdc, GAMEZONE_RIGHT + 13, 390, szbuf, wsprintf(szbuf, L"游戏规则:"));
		TextOut(hdc, GAMEZONE_RIGHT + 13, 400 + cyChar, szbuf, wsprintf(szbuf, L"    按↑↓←→"));
		TextOut(hdc, GAMEZONE_RIGHT + 13, 400 + 2 * cyChar, szbuf, wsprintf(szbuf, L"来控制蛇移动"));
		TextOut(hdc, GAMEZONE_RIGHT + 13, 400 + 3 * cyChar, szbuf, wsprintf(szbuf, L"的方向"));
		DrawBox(hdc, Food);
		EndPaint(hwnd, &ps);
		return 0;
	case WM_KEYDOWN:{
					  if (keydown) break;
					   switch (wParam){
					   case VK_LEFT:
						   if (snake[0].dir != RIGHT){
							   snake[0].dir = LEFT;
							   keydown = 1;
						   }break;
					   case VK_RIGHT:
						   if (snake[0].dir != LEFT){
							   snake[0].dir = RIGHT;
							   keydown = 1;
						   }break;
					   case VK_UP:
						   if (snake[0].dir != DOWN){
							   snake[0].dir = UP;
							   keydown = 1;
						   }break;
					   case VK_DOWN:
						   if (snake[0].dir != UP){
							   snake[0].dir = DOWN;
							   keydown = 1;
						   }break;
					   }
	}return 0;
	case WM_TIMER:	{ 
						KillTimer(hwnd, 1);
						// 如果按键按下置0
						if (keydown) keydown = 0;

						// 提示游戏时间
						static int counter = 1000 / current_speed;
						if (counter-- == 0){
							counter = 1000 / current_speed;
							time_counter++;
							wsprintf(szbuf, L"时间:%d", time_counter);
							SetWindowText(hwndEdit3, szbuf);
						}

						// 产生新食物
						if (makefoodflag == 1){
							makefoodflag = 0;
							hdc = GetDC(hwnd);
							MakeFood();
							DrawBox(hdc, Food);
							DeleteDC(hdc);
						}

						// 判断是否碰撞
						if (bump_flag == 1 || bump_flag == 2){
							KillTimer(hwnd, 1);
							MessageBox(hwnd, L"游戏结束!", L"结束", MB_ICONINFORMATION);
							SetDlgItemText(hwnd, 1, L"");Sleep(150);
							SetDlgItemText(hwnd, 1, L"新游戏");Sleep(150);
							SetDlgItemText(hwnd, 1, L"");Sleep(150);
							SetDlgItemText(hwnd, 1, L"新游戏");Sleep(150);
							SetDlgItemText(hwnd, 1, L""); Sleep(150);
							SetDlgItemText(hwnd, 1, L"新游戏");
							return 0;
						}

						// 移动蛇
						hdc = GetDC(hwnd);
						MoveSnake();
						DrawSnake(hdc);
						DeleteDC(hdc);
						SetTimer(hwnd, 1, current_speed, NULL);
	}return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

// 初始化游戏区域
void InitGame(){	
    // 清0
	memset(gameZome, 0, sizeof(gameZome) / sizeof(int)); 

	// 添加初始结点
	SNAKE sk;
	sk = SetNode(START_X, START_Y, RIGHT, 255, 0, 0);  // 设置头结点
	snake[0] = sk;
	sk.pos_x = snake[0].pos_x - BOXSIZE;
	snake[1] = sk;
	sk.pos_x = snake[1].pos_x - BOXSIZE;
	sk.color_b = sk.color_g = sk.color_r = 0;
	snake[2] = sk;

	snake_length = 3;

	// 未撞车
	bump_flag = 0;
	// 左边框
	for (int i = 0; i < GAMEZONE_LEFT; i++){                     
		for (int j = 0; j < WIN_DEPTH; j++)
			gameZome[i][j] = 1;
	}
    // 下边框
	for (int i = 0; i < GAMEZONE_RIGHT; i++){              
		for (int j = GAMEZONE_BUTTOM; j < WIN_DEPTH; j++)
			gameZome[i][j] = 1;
	}
    // 上边框
	for (int i = 0; i < GAMEZONE_TOP; i++){                
		for (int j = GAMEZONE_LEFT; j < GAMEZONE_RIGHT; j++)
			gameZome[j][i] = 1;
	}
    // 右边框
	for (int j = GAMEZONE_RIGHT-10; j < TIPZONE_LEFT; j++){    
		for (int i = GAMEZONE_TOP; i < GAMEZONE_BUTTOM; i++)
			gameZome[j][i] = 1;
	}
}

// 画小盒子
void DrawBox(HDC hdc,SNAKE s){
	HPEN pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));   // 改变矩形边框的颜色
	SelectObject(hdc, pen);
	HBRUSH br = CreateSolidBrush(RGB(s.color_r, s.color_g, s.color_b));
	SelectObject(hdc, br);
	Rectangle(hdc, s.pos_x, s.pos_y, s.pos_x + BOXSIZE, s.pos_y + BOXSIZE);
	DeleteObject(pen);
	DeleteObject(br);
}

// 添加结点
void AddNode(SNAKE newNode){	
	// 插入到原来的黑色结点中
	snake[snake_length - 1].color_r = newNode.color_r;
	snake[snake_length - 1].color_g = newNode.color_g;
	snake[snake_length - 1].color_b = newNode.color_b;
	
	// 添加一个黑色结点
	snake[snake_length] = snake[snake_length - 1];
	snake[snake_length].color_r = snake[snake_length].color_g = snake[snake_length].color_b = 0;
	switch (snake[snake_length-1].dir){
	case LEFT:snake[snake_length].pos_x +=  BOXSIZE;break;
	case RIGHT:snake[snake_length].pos_x -= BOXSIZE; break;
	case UP:snake[snake_length].pos_y += BOXSIZE; break;
	case DOWN:snake[snake_length].pos_y -= BOXSIZE; break;
	}
	// 长度加1
	snake_length++;
}

// 获取一个新结点
SNAKE SetNode(int x,int y, int dir, int r, int g, int b){
	SNAKE s;
	s.pos_x = x;
	s.pos_y = y;
	s.color_r = r;
	s.color_g = g;
	s.color_b = b;
	s.dir = dir;
	return s;
}

// 画背景
void DrawBk(HDC hdc){
	HBRUSH brBk;

	// 画整个板面
	brBk = CreateSolidBrush(RGB(245, 245,245));
	SelectObject(hdc, brBk);
	Rectangle(hdc, 0, 0, WIN_WIDTH, WIN_DEPTH);

	// 画游戏区域
	brBk = CreateSolidBrush(RGB(0, 0, 0));	
	SelectObject(hdc, brBk);
	Rectangle(hdc, GAMEZONE_LEFT, GAMEZONE_TOP,GAMEZONE_RIGHT ,GAMEZONE_BUTTOM);

	// 画提示区域
	HPEN hpen = CreatePen(PS_SOLID, 1, RGB(22,123,22));
	SelectObject(hdc, hpen);
	for (int i = TIPZONE_TOP; i < TIPZONE_BUTTOM; i++){
		MoveToEx(hdc, TIPZONE_LEFT,i, NULL);
		LineTo(hdc, TIPZONE_RIGHT,i);
	}
	DeleteObject(hpen);
	DeleteObject(brBk);
}

// 画出蛇
void DrawSnake(HDC hdc){
	for (int i = 0; i < snake_length; i++){
		DrawBox(hdc, snake[i]);
	}
}

// 移动
void MoveSnake(){
	for (int i = 0; i < snake_length; i++){
		switch (snake[i].dir){
		case LEFT:
			snake[i].pos_x -= BOXSIZE;
			break;
		case RIGHT:
			snake[i].pos_x += BOXSIZE;
			break;
		case UP:
			snake[i].pos_y -= BOXSIZE;
			break;
		case DOWN:
			snake[i].pos_y += BOXSIZE;
			break;
		}
	}

	bump_flag = IsBump();
	if (snake[0].pos_x == Food.pos_x && snake[0].pos_y == Food.pos_y)
	{
		AddNode(Food);
		makefoodflag = 1;
		score += SCORE_PER_FOOD;
		wsprintf(szbuf, L"分数:%d", score);
		SetWindowText(hwndEdit1, szbuf);
	}

	for (int i = snake_length - 1; i >= 1; i--){
		snake[i].dir = snake[i - 1].dir;
	}
	//snake[snake_length - 1].color_b = snake[snake_length - 1].color_g = snake[snake_length - 1].color_r = 0;
}

// 画游戏区域
void DrawGameZone(HDC hdc){
	for (int i = 0; i < GAMEZONE_RIGHT; i++){
		for (int j = 0; j < WIN_DEPTH;j++)
		if (gameZome[i][j] == 1) SetPixel(hdc, i, j, RGB(0, 0, 255));
		else if (gameZome[i][j] == 2) SetPixel(hdc, i, j, RGB(255, 0, 0));
		else SetPixel(hdc, i, j, RGB(0, 255, 0));
	}
}

BOOL IsBump(){
	// 判断蛇是否撞
	int cur_x = snake[0].pos_x, cur_y = snake[0].pos_y;
	if (gameZome[cur_x][cur_y] == 1) return 1;

	for (int i = 2; i < snake_length - 1; i++){
		if (cur_x == snake[i].pos_x && cur_y == snake[i].pos_y)           // ←
			return 2;
	}
	return 0;
}

// 随机在游戏区域内产生一个结点
void MakeFood(){
	Food.pos_x = GAMEZONE_LEFT + rand() % (GAMEZONE_RIGHT - GAMEZONE_LEFT-10);
	Food.pos_y = GAMEZONE_TOP + rand() % (GAMEZONE_BUTTOM - GAMEZONE_TOP-10);
	Food.color_r = 10 + rand() % 255;
	Food.color_g = 10 + rand() % 255;
	Food.color_b = 10 + rand() % 255;
	if (Food.pos_x % 10 != 0){
		Food.pos_x += 10 - Food.pos_x % 10;
	}
	if (Food.pos_y % 10 != 0){
		Food.pos_y += 10 - Food.pos_y % 10;
	}
	// 如果产生的食物被覆盖
	for (int i = 0; i < snake_length; i++){
		if (Food.pos_x == snake[i].pos_x && Food.pos_y == snake[i].pos_y)
			makefoodflag = 1;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值