某天晚上闲着无聊就写了个贪吃蛇链表,然后第二天就开始就主程序了,很快就写完了,所以大家如果有好的思路,不妨也动动手嘛。好记性不如烂笔头嘛。贪吃蛇的思路挺简单的,就是用一个链表来保存蛇的路线,不过这个链表是经过特殊构造的,主要思路就是把客户区分成若干个小方格子,然后链表会保存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);
}
就写到这里把,明天还得早起呢。
本文介绍了作者利用Win32 SDK编写贪吃蛇游戏的过程,通过创建链表来保存蛇的移动路径,并将屏幕划分为小方格进行坐标管理。文章鼓励读者动手实践,分享了项目的源代码,包括snake_list.h、snake_list.c、resource.h和snake.c等文件。
&spm=1001.2101.3001.5002&articleId=8670401&d=1&t=3&u=b0242839b84845fcb4e7315c9a5f5963)
6790

被折叠的 条评论
为什么被折叠?



