windowsSDK贪吃蛇

上几天看了人家用c语言在控制台上面写俄罗斯方块,觉得自己应该能在SDK上写个贪吃蛇出来。毕竟贪吃蛇比俄罗斯方块简单一点吧。


运用知识
1.GUI绘图
2.计时器
3.键盘控制

思路
一)蛇的产生机制
1.蛇身体的绘制(n个正方形,创建结构体存放4个点坐标,创建结构体数组)
2.运用键盘改变蛇的前进方向(其实改变的只有头尾,并递推改变数组)

(二)食物的产生机制
1.获取当前窗口大小
2.利用随机函数产生x,y为食物(用正方形或圆形函数绘制)的左上角坐标
3.绘制食物

(三)吃食物机制
1.必须验证是蛇头吃到食物
2.吃到食物后食物消失并且重新产生食物(重新产生的食物最好不与蛇的身体重合)
3.蛇的身体的增长(与当前蛇前进的方向有关,数组的扩增)

(四)死亡机制
1.蛇头碰到自己的身体就算死亡
2.蛇头超过窗口就算死亡


因为以前写过模拟钢琴游戏和随机数生成器,所以写起来还是比较顺手的,下面是代码:

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

#define ID_TIMER  1

struct own_rectangle{	//蛇身体的结构体
	int xLeft   ;
	int xRight  ;
	int yTop    ;
	int yBottom ;
}rect[255];

struct Snake_Food{		//食物结构体
	int	x;
	int	y;
}Food;

int			Keyboard_Flag = 1;//键盘标志
int			NUM = 3;	// 蛇身体长度,默认从3开始
RECT		Rect_Window;//获得窗口客户区大小

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
					PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT ("GreedySnake") ;
	HWND         hwnd ;
	MSG          msg ;
	WNDCLASS     wndclass ;

	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc   = WndProc ;
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance     = hInstance ;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName  = NULL ;
	wndclass.lpszClassName = szAppName ;

	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
			szAppName, MB_ICONERROR) ;
		return 0 ;
	}

	hwnd = CreateWindow (szAppName,            
		TEXT ("GreedySnake"), 
		WS_OVERLAPPEDWINDOW,     
		CW_USEDEFAULT,           
		CW_USEDEFAULT,            
		CW_USEDEFAULT,           
		CW_USEDEFAULT,             
		NULL,                       
		NULL,                      
		hInstance,                 
		NULL) ;                     

	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;

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

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC         hdc ;
	PAINTSTRUCT ps ;
	int			j;

	switch (message)
	{
	case WM_CREATE:
		SetTimer (hwnd, ID_TIMER, 200, NULL) ;//设置时间
		GetClientRect(hwnd, &Rect_Window);	  //获取窗口大小
		rect[0].xLeft    =  400   ;			  //初始化蛇身体
		rect[0].xRight   =  420   ;
		rect[0].yTop     =  200   ;
		rect[0].yBottom  =  220   ;
		for (j = 1; j < NUM; j++)
		{
			rect[j].xLeft    = rect[j-1].xLeft  + 20   ;
			rect[j].xRight   = rect[j-1].xRight + 20   ;
			rect[j].yTop     = rect[0].yTop            ;
			rect[j].yBottom  = rect[0].yBottom         ;
		}
		srand(time(0));
		Food.x =  (rand() % Rect_Window.right) / 20 * 20 ;  //保证产生的食物与蛇可以连接
		Food.y = (rand() % Rect_Window.bottom) / 20 * 20;
		return 0 ;

	case WM_PAINT:

		hdc = BeginPaint (hwnd, &ps);
		for (j = 0; j < NUM-1; j++)		//画蛇
			Rectangle(hdc, rect[j].xLeft, rect[j].yTop, rect[j].xRight, rect[j].yBottom);

		SelectObject(hdc, (HBRUSH)GetStockObject (GRAY_BRUSH));			
		Rectangle(hdc, rect[NUM-1].xLeft, rect[NUM-1].yTop, rect[NUM-1].xRight, rect[NUM-1].yBottom);
		Ellipse(hdc, Food.x, Food.y, Food.x+20, Food.y+20);//画食物
	
		EndPaint(hwnd, &ps);
		return 0;

	case WM_TIMER:

		//键盘操作对应改变蛇的形状

		//1对应处理向右
		if (1 == Keyboard_Flag)
		{
			for (j = 0; j < NUM-1; j++)
			{
				rect[j].xLeft    =  rect[j+1].xLeft   ;
				rect[j].xRight   =  rect[j+1].xRight  ;
				rect[j].yBottom  =  rect[j+1].yBottom  ;
				rect[j].yTop     =  rect[j+1].yTop  ;
			}
			rect[NUM-1].xLeft    += 20;
			rect[NUM-1].xRight   += 20;
		}
		//2对应处理向下
		else if (2 == Keyboard_Flag)
		{
			for (j = 0; j < NUM-1; j++)
			{
				rect[j].xLeft    =  rect[j+1].xLeft   ;
				rect[j].xRight   =  rect[j+1].xRight  ;
				rect[j].yTop     =  rect[j+1].yTop  ;
				rect[j].yBottom  =  rect[j+1].yBottom  ;
			}
			rect[NUM-1].yBottom  += 20;
			rect[NUM-1].yTop     += 20;
		}
		//3对应处理向左
		else if (3 == Keyboard_Flag)
		{
			for (j = 0; j < NUM-1; j++)
			{
				rect[j].xLeft    =  rect[j+1].xLeft   ;
				rect[j].xRight   =  rect[j+1].xRight  ;
				rect[j].yTop     =  rect[j+1].yTop  ;
				rect[j].yBottom  =  rect[j+1].yBottom  ;
			}
			rect[NUM-1].xLeft    -= 20;
			rect[NUM-1].xRight   -= 20;
		}
		//4对应处理向上
		else if (4 == Keyboard_Flag)
		{
			for (j = 0; j < NUM-1; j++)
			{
				rect[j].xLeft    =  rect[j+1].xLeft   ;
				rect[j].xRight   =  rect[j+1].xRight  ;
				rect[j].yTop     =  rect[j+1].yTop  ;
				rect[j].yBottom  =  rect[j+1].yBottom  ;
			}
			rect[NUM-1].yTop     -= 20;
			rect[NUM-1].yBottom  -= 20;
		}
		//判断蛇头是否吃到食物
		if (rect[NUM-1].xLeft  == Food.x && rect[NUM-1].yTop == Food.y)
		{

			if (1 == Keyboard_Flag)//向右吃到食物
			{
				NUM++;
				for (j = NUM-1; j > 0 ; j--)
				{
					rect[j].xLeft    =  rect[j-1].xLeft   ;
					rect[j].xRight   =  rect[j-1].xRight  ;
					rect[j].yTop     =  rect[j-1].yTop  ;
					rect[j].yBottom  =  rect[j-1].yBottom  ;
				}
				rect[0].xLeft  -= 20; 
				rect[0].xRight -= 20; 
				Food.x =  (rand() % Rect_Window.right) / 20 * 20 ;  //蛇吃到后食物坐标改变
				Food.y = (rand() % Rect_Window.bottom) / 20 * 20;
			}
			else if	(2 == Keyboard_Flag)//向下吃到食物
			{
				NUM++;
				for (j = NUM-1; j > 0 ; j--)
				{
					rect[j].xLeft    =  rect[j-1].xLeft   ;
					rect[j].xRight   =  rect[j-1].xRight  ;
					rect[j].yTop     =  rect[j-1].yTop  ;
					rect[j].yBottom  =  rect[j-1].yBottom  ;
				}
				rect[0].yTop  -= 20; 
				rect[0].yBottom -= 20; 
				Food.x =  (rand() % Rect_Window.right) / 20 * 20 ;  //蛇吃到后食物坐标改变
				Food.y = (rand() % Rect_Window.bottom) / 20 * 20;
			}

			else if	(3 == Keyboard_Flag)//向左吃到食物
			{
				NUM++;
				for (j = NUM-1; j > 0 ; j--)
				{
					rect[j].xLeft    =  rect[j-1].xLeft   ;
					rect[j].xRight   =  rect[j-1].xRight  ;
					rect[j].yTop     =  rect[j-1].yTop  ;
					rect[j].yBottom  =  rect[j-1].yBottom  ;
				}
				rect[0].xLeft  += 20; 
				rect[0].xRight += 20; 
				Food.x =  (rand() % Rect_Window.right) / 20 * 20 ;  //蛇吃到后食物坐标改变
				Food.y = (rand() % Rect_Window.bottom) / 20 * 20;
			}

			else if	(4 == Keyboard_Flag)//向上吃到食物
			{
				NUM++;
				for (j = NUM-1; j > 0 ; j--)
				{
					rect[j].xLeft    =  rect[j-1].xLeft   ;
					rect[j].xRight   =  rect[j-1].xRight  ;
					rect[j].yTop     =  rect[j-1].yTop  ;
					rect[j].yBottom  =  rect[j-1].yBottom  ;
				}
				rect[0].yTop  += 20; 
				rect[0].yBottom += 20; 
				Food.x =  (rand() % Rect_Window.right) / 20 * 20 ;  //蛇吃到后食物坐标改变
				Food.y = (rand() % Rect_Window.bottom) / 20 * 20;
			}
		}
			//SnakeBody_Longer(&rect, NUM);

		//死亡机制

		//触碰边界而死
		if (rect[NUM-1].xLeft < 0 || rect[NUM-1].xRight >  Rect_Window.right ||
			rect[NUM-1].yTop < 0 ||rect[NUM-1].yBottom > Rect_Window.bottom )
		{
			KillTimer(hwnd, ID_TIMER);
			MessageBox(hwnd, TEXT("Game Over!"), TEXT("Sorry,You Died, Never Give Up!"), MB_OK);
			return 0;
		}
		//触碰自己而死
		for (j = 0; j < NUM-1; j++)
		{
			if (rect[NUM-1].xLeft == rect[j].xLeft && rect[NUM-1].xRight == rect[j].xRight &&
				rect[NUM-1].yTop == rect[j].yTop && rect[NUM-1].yBottom == rect[j].yBottom)
			{
				KillTimer(hwnd, ID_TIMER);
				MessageBox(hwnd, TEXT("Game Over!"), TEXT("Sorry,You Died, Never Give Up!"), MB_OK);
				return 0;
			}
		}

		
		InvalidateRect(hwnd, NULL, TRUE);
		return 0;
	case WM_KEYDOWN:		//处理键盘消息
		switch(wParam)
		{
		case VK_LEFT:
			Keyboard_Flag = 3;
		break;
		case VK_RIGHT:
			Keyboard_Flag = 1;
		break;
		case VK_UP:
			Keyboard_Flag = 4;
		break;
		case VK_DOWN:
			Keyboard_Flag = 2;
		break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}
这里我用 NUM 表示蛇身体的长度

rect[num-1]表示的是蛇头,很多处理都用到了这个。

windowsSDK贪吃蛇_第1张图片

写的时候可能代码有点乱,是按照顺序写下来的,关键代码都放在VM_TIMER里面了

也没有写函数,所以看起来确实有点乱的。

具体的话写了点注释,应该不难理解吧。


还有不完善的地方可以修改:

1.身体增长机制

 我是根据方向在尾部增长的,有时候看起来比较突兀,这里可以改进


2食物产生机制

产生食物的时候食物可能会落在窗口外面,这个时候蛇无论如何也吃不到食物了,这里有个BUG委屈


3.难度控制

可以写个菜单,调节蛇的速度


4.窗口应该设置为固定的


5.结束机制

结束后选择重新玩,或者退出游戏



不过这个只是实现了基本功能,还不能称为游戏。我觉得应该把它称作  "移动和增长方块"比较合适吧

如果想称之为游戏,那必须还得添加一些可玩因素,比如

1.积分机制

2.过关机制

3.蛇的移动速度调节

4.食物的种类,不同类型食物可以增加身体长度不同,增加分数不同

5.背景音乐

6.把蛇画的好看点

7.其他的创意因子

暂时想到的可玩因素就只有这些了。大家有兴趣的话也可以去写个玩玩。最后说明,偶只是个新手,高手勿喷,呵呵


你可能感兴趣的:(游戏,timer,null,callback,keyboard,winapi)