win 32sdk编写贪吃蛇(附源代码)

本文介绍了作者利用Win32 SDK编写贪吃蛇游戏的过程,通过创建链表来保存蛇的移动路径,并将屏幕划分为小方格进行坐标管理。文章鼓励读者动手实践,分享了项目的源代码,包括snake_list.h、snake_list.c、resource.h和snake.c等文件。


       某天晚上闲着无聊就写了个贪吃蛇链表,然后第二天就开始就主程序了,很快就写完了,所以大家如果有好的思路,不妨也动动手嘛。好记性不如烂笔头嘛。贪吃蛇的思路挺简单的,就是用一个链表来保存蛇的路线,不过这个链表是经过特殊构造的,主要思路就是把客户区分成若干个小方格子,然后链表会保存x和y坐标,这个算是最重要的了,其它的都挺简单的,在这里就不赘述了。

打开vc6,然后新建一个win32空项目就可以了。

 

这个是运行截图

这个是snake_list.h

 

#ifndef SNAKE_LIST_H
#define SNAKE_LIST_H

#define CLIENT_WIDTH	600
#define CLIENT_HEIGHT	600
#define ARRAY_COUNT		1600
#define ARRAY_WIDTH		40
#define ARRAY_HEIGHT	40
#define SANKE_UNIT		15
#define SNAKE_NUM		5

//定制版贪吃蛇链表
typedef struct Snake_List{
	int x;//x坐标
	int y;//y坐标
	struct Snake_List* next;
}snake_list;

extern void init_snake(snake_list** head, char* snake_array);//初始化蛇
extern int add_head_hit(const int* x, const int* y, snake_list** head, char* snake_array);//撞上蛇
extern int add_head_no_hit(const int* x, const int* y, snake_list** head, char* snake_array);//没撞上蛇
extern void destory(snake_list* head);//清空蛇
extern void get_head_info(snake_list* head, int *x, int *y);//获取蛇头

#endif


这个是snake_list.c

#include "snake_list.h"
#include <stdio.h>
#include <stdlib.h>

static snake_list* snake_tail;//蛇伪尾巴
static void set_snake_tail(snake_list* head);//设置新的蛇伪尾巴

void init_snake(snake_list** head, char* snake_array)
{
	snake_list *p, *q;
	int i, max_num;

	max_num = 18 + SNAKE_NUM;
	for (i = 18; i < max_num; i++) {//默认蛇长5个单位 坐标从20*ARRAY_WIDTH 13开始
		p = (snake_list* )malloc(sizeof(snake_list));
		if (i == 18) {
			*head = p;
		} else {
			q->next = p;
			if (i == max_num - 2) {
				snake_tail = p;//设置伪尾巴
			}
		}
		p->x = 30;
		p->y = i;
		snake_array[p->x*ARRAY_WIDTH+p->y] = 1;//更改蛇数组的位
		q = p;
	}
	p->next = NULL;
}

//x, y是撞击的位置坐标,撞击后头部改变,尾巴不变
int add_head_hit(const int* x, const int* y, snake_list** head, char* snake_array)
{
	snake_list *p, *q;
	p = (snake_list*)malloc(sizeof(snake_list));
	q = *head;
	*head = p;
	(*head)->x = *x;
	(*head)->y = *y;
	(*head)->next = q;
	snake_array[*x*ARRAY_WIDTH+*y] = 1;

	return 1;
}
//x, y是前进的位置坐标,前进后头部改变,尾巴改变
int add_head_no_hit(const int* x, const int* y, snake_list** head, char* snake_array)
{
	snake_list *p, *q;
	p = (snake_list*)malloc(sizeof(snake_list));
	q = *head;
	*head = p;
	(*head)->x = *x;
	(*head)->y = *y;
	(*head)->next = q;
	snake_array[*x*ARRAY_WIDTH+*y] = 1;
	p = snake_tail;//设置新的尾巴
	q = p->next;
	p->next = NULL;
	snake_array[q->x*ARRAY_WIDTH+q->y] = 0;
	free(q);
	set_snake_tail(*head); 
	return 1;
}

void destory(snake_list* head)
{
	snake_list *p, *q;

	p = head;
	while (p) {
		q = p->next;
		free (p);
		p = q;
	}
}

void get_head_info(snake_list* head, int *x, int *y)
{
	*x = head->x;
	*y = head->y;
}

static void set_snake_tail(snake_list* head)
{
	snake_list* temp;

	temp = head;
	while (temp->next->next) {//找到到第二个位置
		temp = temp->next;
	}
	snake_tail = temp;
}




 

这个是resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by resource.rc
//
#define IDB_BITMAP1                     101
#define IDI_ICON1                       102

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1000
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif


 

这个是snake.c

 

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

#define bool  int
#define true  1
#define false 0
#define TIMERID 201314

static HINSTANCE ghInstance;
static UINT		 gDirection;
static RECT		 gClientRect;
static POINT	 gSnakeFood;//食物
static bool		 gStop;//是否暂停
static snake_list* gSnakeHead;//蛇头
static bool		   gGameStart;//游戏是否开始
static char		   gSnakeArray[ARRAY_HEIGHT*ARRAY_WIDTH];//保存蛇

的路径

void Init(HWND hwnd);//初始化一些变量
void HandleMove(HWND hwnd, UINT keyCode);//处理上下左右键消息
void HandleQuit(HWND hwnd);//处理用户是否退出
void DrawSnake(HWND hwnd);//绘制蛇的身体
void GenerateFood();//随机产生食物
void AutoForward(HWND hwnd);//自动前进
LRESULT CALLBACK WinProc(HWND hwnd,UINT uMsg,WPARAM wpara,LPARAM lpara);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR 

lpCmdLine, int nShowCmd )
{
	WNDCLASS wndclass;
	MSG msg;
	HWND hwnd;
	RECT windowRect, clientRect;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
	wndclass.hCursor = LoadCursor(hInstance, IDC_UPARROW);//光标属性
	wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE

(IDI_ICON1));//图标
	wndclass.hInstance = hInstance;
	wndclass.lpfnWndProc = WinProc;
	wndclass.lpszClassName = "snake";
	wndclass.lpszMenuName = NULL;//无菜单
	wndclass.style = CS_HREDRAW | CS_VREDRAW;//窗口风格
	ghInstance = hInstance;
	
	//注册窗口
	RegisterClass(&wndclass);
	
	
	//创建窗口
	hwnd = CreateWindow("snake", "Snake-by-inconsolablev", 

WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX, 0, 0,
		CLIENT_WIDTH, CLIENT_HEIGHT, NULL, NULL, ghInstance, 

NULL);
	//调整客户区的大小
	GetWindowRect(hwnd,&windowRect);
	GetClientRect(hwnd,&clientRect);
	windowRect.right += CLIENT_WIDTH - clientRect.right + 

clientRect.left;
	windowRect.bottom += CLIENT_HEIGHT - clientRect.bottom + 

clientRect.top;
	MoveWindow(hwnd, (GetSystemMetrics(SM_CXSCREEN) - 

windowRect.right + windowRect.left) / 2, windowRect.top, 
		windowRect.right - windowRect.left, windowRect.bottom - 

windowRect.top, true);
	Init(hwnd);
	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	
	return 0;
}

LRESULT CALLBACK WinProc(HWND hwnd,UINT uMsg,WPARAM wpara,LPARAM lpara)
{
	switch (uMsg)
	{
	case WM_KEYDOWN:
		if (wpara == VK_SPACE && gGameStart == false) {
			gGameStart = true;
			GenerateFood();
			SetTimer(hwnd, TIMERID, 150, NULL);
		} else if (wpara == VK_RETURN && gGameStart == true) 

{//Enter 暂停
			KillTimer(hwnd, TIMERID);
			gStop = true;
			InvalidateRect(hwnd, &gClientRect, false);
		} else if (wpara == VK_SPACE && gStop == true) {
			//继续游戏
			gStop = false;
			SetTimer(hwnd, TIMERID, 150, NULL);
		} else if (gGameStart == true && gStop == false) {
			HandleMove(hwnd, wpara);
		}
		break;
	case WM_TIMER:
		HandleMove(hwnd, gDirection);
		break;
	case WM_PAINT:
		DrawSnake(hwnd);
		break;
	case WM_CLOSE:
		if (IDYES == MessageBox(hwnd,"是否真的结

束?","snake",MB_YESNO))
		{
			KillTimer(hwnd, TIMERID);
			DestroyWindow(hwnd);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd,uMsg,wpara,lpara);
	}
	
	return (LRESULT)NULL;
}

void Init(HWND hwnd)
{
	gGameStart = false;
	gStop = false;
	gDirection = VK_LEFT;//默认左边
	memset(gSnakeArray, 0, ARRAY_HEIGHT*ARRAY_WIDTH);
	GetClientRect(hwnd, &gClientRect);
	init_snake(&gSnakeHead, gSnakeArray);
}

void HandleQuit(HWND hwnd)
{
	KillTimer(hwnd, TIMERID);
	destory(gSnakeHead);
	Init(hwnd);
	InvalidateRect(hwnd, &gClientRect, false);
}
void HandleMove(HWND hwnd, UINT keyCode)
{
	static POINT basePoint;
	char	temp;
	
	get_head_info(gSnakeHead, &basePoint.x, &basePoint.y);
	switch (keyCode){
	case VK_UP:
		if (basePoint.x != 0) {//没到达最顶端就可以继续
			basePoint.x--;
			temp = gSnakeArray

[basePoint.x*ARRAY_WIDTH+basePoint.y];
			if (temp == 0) {
				//无障碍物
				gDirection = VK_UP;
				add_head_no_hit(&basePoint.x, 

&basePoint.y, &gSnakeHead, gSnakeArray);
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 2) {
				//碰到食物 吃掉
				gDirection = VK_UP;
				add_head_hit(&basePoint.x, &basePoint.y, 

&gSnakeHead, gSnakeArray);
				GenerateFood();
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 1) {
				if (gDirection != VK_DOWN) {//蛇绕成一团 

而不是后退
					HandleQuit(hwnd);
				}
			}
		} else {
			HandleQuit(hwnd);
		}
		break;
	case VK_DOWN:
		if (basePoint.x != ARRAY_HEIGHT - 1) {//没到达最下端就可

以继续
			basePoint.x++;
			temp = gSnakeArray

[basePoint.x*ARRAY_WIDTH+basePoint.y];
			if (temp == 0) {
				//无障碍物
				gDirection = VK_DOWN;
				add_head_no_hit(&basePoint.x, 

&basePoint.y, &gSnakeHead, gSnakeArray);
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 2) {
				//碰到食物 吃掉
				gDirection = VK_DOWN;
				add_head_hit(&basePoint.x, &basePoint.y, 

&gSnakeHead, gSnakeArray);
				GenerateFood();
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 1) {
				if (gDirection != VK_UP) {//蛇绕成一团 而

不是后退
					HandleQuit(hwnd);
				}
			}
		} else {
			HandleQuit(hwnd);
		}
		break;
	case VK_LEFT:
		if (basePoint.y != 0) {//没到达最左端就可以继续
			basePoint.y--;
			temp = gSnakeArray

[basePoint.x*ARRAY_WIDTH+basePoint.y];
			if (temp == 0) {
				//无障碍物
				gDirection = VK_LEFT;
				add_head_no_hit(&basePoint.x, 

&basePoint.y, &gSnakeHead, gSnakeArray);
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 2) {
				//碰到食物 吃掉
				gDirection = VK_LEFT;
				add_head_hit(&basePoint.x, &basePoint.y, 

&gSnakeHead, gSnakeArray);
				GenerateFood();
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 1) {
				if (gDirection != VK_RIGHT) {//蛇绕成一团 

而不是后退
					HandleQuit(hwnd);
				}
			}
		} else {
			HandleQuit(hwnd);
		}
		break;
	case VK_RIGHT:
		if (basePoint.y != ARRAY_WIDTH - 1) {//没到达最右端就可以

继续
			basePoint.y++;
			temp = gSnakeArray

[basePoint.x*ARRAY_WIDTH+basePoint.y];
			if (temp == 0) {
				//无障碍物
				gDirection = VK_RIGHT;
				add_head_no_hit(&basePoint.x, 

&basePoint.y, &gSnakeHead, gSnakeArray);
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 2) {
				//碰到食物 吃掉
				gDirection = VK_RIGHT;
				add_head_hit(&basePoint.x, &basePoint.y, 

&gSnakeHead, gSnakeArray);
				GenerateFood();
				InvalidateRect(hwnd, &gClientRect, 

false);
			} else if (temp == 1) {
				if (gDirection != VK_LEFT) {//蛇绕成一团 

而不是后退
					HandleQuit(hwnd);
				}
			}
		} else {
			HandleQuit(hwnd);
		}
		break;
	default:
		break;
	}
}

void GenerateFood()
{
	int i = 0, j = 0;
	static short int temp[ARRAY_COUNT];

	for (i = 0; i < ARRAY_COUNT; i++) {
		if (gSnakeArray[i] == 0) {
			temp[j++] = i;//保存是0的位置
		}
	}
	//然后在这些元素是0里面取一个就行了
	srand((unsigned)time(NULL));
	j = rand() % j; //随机获取一个是0的元素
	gSnakeFood.x = temp[j] / ARRAY_WIDTH;
	gSnakeFood.y = temp[j] % ARRAY_WIDTH;
	gSnakeArray[gSnakeFood.x*ARRAY_WIDTH+gSnakeFood.y] = 2;//食物标记
}
void DrawSnake(HWND hwnd)
{
	static HDC hMemDC, hDC;
	static HBRUSH  hBrush, hOldBrush;
	static HBITMAP hBitmap, hOldBitmap;
	static HFONT	hFont, hOldFont;
	static LOGFONT	logFont;
	POINT tempPoint;
	snake_list* temp;
	PAINTSTRUCT ps;
	static RECT	fontRect;
	char str[25];
	
	temp = gSnakeHead;
	hDC = BeginPaint(hwnd, &ps);
	hMemDC = CreateCompatibleDC(hDC);
	hBitmap = (HBITMAP)LoadBitmap(ghInstance, MAKEINTRESOURCE

(IDB_BITMAP1));
	hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//保存旧的位

图
	hBrush = CreateSolidBrush(RGB(87, 66, 189));
	hOldBrush = (HBRUSH)SelectObject(hMemDC, hBrush);//保存旧的画刷
	SetBkMode(hMemDC, TRANSPARENT);
	while (temp) {//遍历整个蛇 绘制蛇身
		tempPoint.x = temp->y*SANKE_UNIT;//notify this place
		tempPoint.y = temp->x*SANKE_UNIT;
		Rectangle(hMemDC, tempPoint.x, tempPoint.y, 

tempPoint.x+SANKE_UNIT, tempPoint.y+SANKE_UNIT);
		temp = temp->next;
	}
	if (gGameStart == false) {//游戏未开始 写提示
		sprintf(str, "Press Space To Start!");
		SetTextColor(hMemDC, RGB(255, 0, 0));
		ZeroMemory(&logFont,   sizeof(LOGFONT));   
		logFont.lfCharSet = ANSI_CHARSET;   
		logFont.lfHeight = 30;      //设置字体的大小
		logFont.lfWidth	= 15;
		logFont.lfWeight = 10;
		hFont = CreateFontIndirect(&logFont);   
		fontRect.left = 150;
		fontRect.right = fontRect.left+400;
		fontRect.top = 100;
		fontRect.bottom = 400;
		hOldFont = (HFONT)SelectObject(hMemDC,hFont);//保存旧的的

字体
		DrawText(hMemDC, str, strlen(str), &fontRect, DT_BOTTOM);
	} else {
		if (gStop == true) {
			//暂停游戏
			sprintf(str, "Press Space to Continue!");
			SetTextColor(hMemDC, RGB(255, 0, 0));
			hFont = CreateFontIndirect(&logFont);   
			hOldFont = (HFONT)SelectObject(hMemDC,hFont);//保

存旧的的字体
			DrawText(hMemDC, str, strlen(str), &fontRect, 

DT_BOTTOM);
		} else {
			//继续游戏
			sprintf(str, "Press Enter to Stop!");
			SetTextColor(hMemDC, RGB(255, 0, 0));
			hFont = CreateFontIndirect(&logFont);   
			hOldFont = (HFONT)SelectObject(hMemDC,hFont);//保

存旧的的字体
			DrawText(hMemDC, str, strlen(str), &fontRect, 

DT_BOTTOM);
		}//绘制食物
		DeleteObject(hBrush);
		hBrush = CreateSolidBrush(RGB(55, 208, 47));
		hOldBrush = (HBRUSH)SelectObject(hMemDC, hBrush);
		tempPoint.x = gSnakeFood.y*SANKE_UNIT;//notify this place
		tempPoint.y = gSnakeFood.x*SANKE_UNIT;
		Rectangle(hMemDC, tempPoint.x, tempPoint.y, 

tempPoint.x+SANKE_UNIT, tempPoint.y+SANKE_UNIT);
	}
	BitBlt(hDC, 0, 0, gClientRect.right - gClientRect.left, 

gClientRect.bottom - gClientRect.top, hMemDC, 0, 0, SRCCOPY);
	SelectObject(hMemDC, hOldFont);//选回旧的
	SelectObject(hMemDC, hOldBitmap);
	SelectObject(hMemDC, hOldBrush);
	EndPaint(hwnd,&ps);
	DeleteDC(hMemDC);//释放资源
	DeleteDC(hDC);
	DeleteObject(hBitmap);
	DeleteObject(hFont);
	DeleteObject(hBrush);
}

就写到这里把,明天还得早起呢。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值