贪吃蛇游戏通常由以下几个要素组成:
- 蛇头:玩家控制的蛇的头部,用来移动和吃食物。
- 蛇身:蛇头后面连接的一系列方块,长度会随着吃到食物而增加。
- 食物:随机出现在游戏区域内的食物,蛇需要吃掉它来增长身体长度。
- 边界:游戏区域的边界,蛇不能穿过边界。
- 游戏得分:吃到食物后,玩家的得分会增加。
玩家通过控制蛇头的移动方向来操纵整条蛇的移动。通常可以使用键盘上的方向键或者滑动屏幕来改变蛇头的移动方向。当蛇头碰到食物时,蛇的长度会增加,并且在新的位置上生成一个新的食物。如果蛇头碰到自己的身体或者撞到边界,游戏结束。
首先是要打印游戏界面。
这里我们就要使用Windows库函数,包含头文件#include<windows.h>,使用GetStdHandle(STD_OUTPUT_HANDLE)函数来获取标准输出的句柄的位置信息,使用SetConsoleCursorPosition(handle, pos)函数来设置标准输出的光标的位置。
获取到我们想要的位置后就可以打印我们想要的信息了,然后使用system("pause")和system("cls")函数分别为屏幕暂停和清除屏幕,组合使用可以实现多页信息打印。
其次,就要设计游戏的空间范围和游戏规则。
第一,规划好蛇的移动范围,横坐标为58,纵坐标为27。
第二,用宽字符来充当墙,包含头文件#include<locale.h>#define wall L'□'。#define body L'●'。 #define food L'★'。
第三,规则设计:蛇撞墙寄,吃到自己寄,空格游戏暂停,esc键退出游戏,F3游戏加速,F4游戏减速,使用↑↓← → 来控制蛇的移动。
接下来开始对游戏进行一步步地设计
1、初始化蛇
void InitSnake(pSnake pc)
{
pSnakeNode nod = NULL;
//创建蛇节点
int i = 0;
for (i = 0; i < 5; i++)
{
nod = (pSnakeNode)malloc(sizeof(SnakeNode));
if (nod == NULL)
{
perror("InitSnake():()malloc");
return;
}
nod->next = NULL;
nod->x = POS_X + i * 2;
nod->y = POS_Y;
//头插
if (pc->_pSnake == NULL)
{
pc->_pSnake = nod;
}
else
{
nod->next = pc->_pSnake;
pc->_pSnake = nod;
}
}
//打印蛇身
nod = pc->_pSnake;
while (nod)
{
SetPos(nod->x, nod->y);
wprintf(L"%lc", body);
nod = nod->next;
}
//初始化蛇的其他数据
pc->_Score=0;
pc->_Add=10;
pc->_SleepTime=200;
pc->_Status = OK;
pc->_Dri = RIGHT;
}
2、打印地图
void CreatMap()
{
int i = 0;
SetPos(0, 0);
for (i = 0; i < 58; i += 2)
{
wprintf(L"%lc", wall);
}
SetPos(0, 26);
for (i = 0; i < 58; i += 2)
{
wprintf(L"%lc", wall);
}
for (i = 1; i < 26; i++)
{
SetPos(0, i);
wprintf(L"%lc", wall);
}
for (i = 1; i < 26; i++)
{
SetPos(56, i);
wprintf(L"%lc", wall);
}
}
3、打印提示信息
void PrintHelpInfo()
{
//打印提⽰信息
SetPos(64, 15);
printf("不能穿墙,不能咬到自己");
SetPos(64, 16);
printf("用↑.↓.←.→分别控制蛇的移动.");
SetPos(64, 17);
printf("F3 为加速,F4 为减速");
SetPos(64, 18);
printf("ESC :退出游戏.space:暂停游戏.");
SetPos(64, 20);
printf("江氏@版权");
}
4、食物的设计
void CreatFood(pSnake pc)
{
int x = 0;
int y = 0;
again:
do
{
x = rand() % 53 + 2;
y = rand() % 25 + 1;
} while (x % 2 != 0);
pSnakeNode nod = pc->_pSnake;
while (nod)
{
if (nod->x == x && nod->y == y)
{
goto again;
}
nod = nod->next;
}
pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
if (Food == NULL)
{
perror("CreatFood():()malloc");
return;
}
else
{
Food->x = x;
Food->y = y;
SetPos(Food->x, Food->y);
wprintf(L"%lc", food);
pc->_pFood = Food;
}
}
以上是为游戏的运行做准备。
游戏的运行
1、打印游戏的相关信息
//打印有用信息
PrintHelpInfo();
2、使用do-while函数,以蛇的状态为条件维持运行。这里我们使用了一个键盘按键的使用情况获取函数KEY_PRESS(),某一个按键未按下时,该按键使用情况用0表示,已经按过用1表示。
do {
SetPos(64, 10);
printf("得分:%d", pc->_Score);
SetPos(64, 11);
printf("每个食物得分:%2d", pc->_Add);
if (KEY_PRESS(VK_UP) && pc->_Dri != DOWN)
{
pc->_Dri = UP;
}
else if (KEY_PRESS(VK_DOWN) && pc->_Dri != UP)
{
pc->_Dri = DOWN;
}
else if (KEY_PRESS(VK_RIGHT) && pc->_Dri != LEFT)
{
pc->_Dri = RIGHT;
}
else if (KEY_PRESS(VK_LEFT) && pc->_Dri != RIGHT)
{
pc->_Dri = LEFT;
}
else if (KEY_PRESS(VK_ESCAPE))
{
pc->_Status = ESC_NOMAL;
break;
}
else if (KEY_PRESS(VK_SPACE))
{
puse();
}
else if (KEY_PRESS(VK_F3))
{
if (pc->_SleepTime >= 50)
{
pc->_SleepTime -= 30;
pc->_Add += 2;
}
}
else if (KEY_PRESS(VK_F4))
{
if (pc->_SleepTime <= 350)
{
pc->_SleepTime += 30;
pc->_Add -= 2;
if (pc->_SleepTime == 350)
{
pc->_Add = 1;
}
}
}
Sleep(pc->_SleepTime);
SnakeMove(pc);
} while (pc->_Status==OK);
最后就是游戏的结束
上一环节蛇的状态为条件跳出do-while循环后,便进入游戏结束环节。
pSnakeNode nod = pc->_pSnake;
SetPos(24, 12);
switch (pc->_Status)
{
case KILL_BY_WALL:
printf("您撞墙了,游戏结束!\n");
break;
case KILL_BY_SELF:
printf("您吃到自己了,游戏结束!\n");
break;
case ESC_NOMAL:
printf("您主动退出游戏!\n");
break;
}
游戏结束后需要把游戏中的有关信息释放
//释放蛇身
while (nod)
{
pSnakeNode cur = nod;
nod = nod->next;
free(cur);
}
以上内容是该游戏的设计思路与主题结构设计
下面是贪吃蛇游戏的全部代码
//Snake.h文件代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<locale.h>
#define wall L'□'
#define body L'●'
#define food L'★'
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1:0)
enum DERECTION
{
UP=1,
DOWN,
LEFT,
RIGHT
};
enum GAME_STATUS
{
OK,
KILL_BY_WALL,
KILL_BY_SELF,
ESC_NOMAL
};
//蛇节点定义
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode* next;
}SnakeNode,* pSnakeNode;
typedef struct Snake
{
pSnakeNode _pSnake;//维护蛇的指针
pSnakeNode _pFood;//维护食物的指针
int _Score;//当前分数
int _Add;//每个食物默认分数
enum DERECTION _Dri;//蛇头方向
enum GAME_STATUS _Status;//游戏状态
int _SleepTime;//默认睡眠时间
}Snake,* pSnake;
//蛇的初始位置
#define POS_X 24
#define POS_Y 5
void SetPos(short x, short y);
void InitSnake(pSnake pc);
void Welcome();
void CreatMap();
void CreatFood(pSnake pc);
void PrintHelpInfo();
void puse();
int NextIsFood(pSnakeNode node, pSnake pc);
void EatFood(pSnakeNode nod, pSnake pc);
void NoFood(pSnakeNode nod, pSnake pc);
int KillByWall(pSnake pc);
int KillBySelf(pSnake pc);
void SnakeMove(pSnake pc);
//游戏开始
void GameStart(pSnake pc);
//游戏运行
void GameRun(pSnake pc);
//游戏结束
void GameOver(pSnake pc);
//Snake.c文件代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Snake.h"
void SetPos(short x, short y)
{
COORD pos = { x,y };
//获取标准输出的句柄
HANDLE handle = NULL;
handle = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出光标的位置为pos
SetConsoleCursorPosition(handle, pos);
}
void InitSnake(pSnake pc)
{
pSnakeNode nod = NULL;
//创建蛇节点
int i = 0;
for (i = 0; i < 5; i++)
{
nod = (pSnakeNode)malloc(sizeof(SnakeNode));
if (nod == NULL)
{
perror("InitSnake():()malloc");
return;
}
nod->next = NULL;
nod->x = POS_X + i * 2;
nod->y = POS_Y;
//头插
if (pc->_pSnake == NULL)
{
pc->_pSnake = nod;
}
else
{
nod->next = pc->_pSnake;
pc->_pSnake = nod;
}
}
//打印蛇身
nod = pc->_pSnake;
while (nod)
{
SetPos(nod->x, nod->y);
wprintf(L"%lc", body);
nod = nod->next;
}
//初始化蛇的其他数据
pc->_Score=0;
pc->_Add=10;
pc->_SleepTime=200;
pc->_Status = OK;
pc->_Dri = RIGHT;
}
void Welcome()
{
SetPos(40, 15);
printf("欢迎来到贪吃蛇小游戏");
SetPos(40, 25);
system("pause");
system("cls");
SetPos(25,12);
printf("使用 ↑↓← → 来控制蛇的移动,F3为加速,F4为减速\n");
SetPos(25, 13);
printf("加速可以获取更高分\n");
SetPos(40, 25);
system("pause");
system("cls");
}
void CreatMap()
{
int i = 0;
SetPos(0, 0);
for (i = 0; i < 58; i += 2)
{
wprintf(L"%lc", wall);
}
SetPos(0, 26);
for (i = 0; i < 58; i += 2)
{
wprintf(L"%lc", wall);
}
for (i = 1; i < 26; i++)
{
SetPos(0, i);
wprintf(L"%lc", wall);
}
for (i = 1; i < 26; i++)
{
SetPos(56, i);
wprintf(L"%lc", wall);
}
}
void CreatFood(pSnake pc)
{
int x = 0;
int y = 0;
again:
do
{
x = rand() % 53 + 2;
y = rand() % 25 + 1;
} while (x % 2 != 0);
pSnakeNode nod = pc->_pSnake;
while (nod)
{
if (nod->x == x && nod->y == y)
{
goto again;
}
nod = nod->next;
}
pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
if (Food == NULL)
{
perror("CreatFood():()malloc");
return;
}
else
{
Food->x = x;
Food->y = y;
SetPos(Food->x, Food->y);
wprintf(L"%lc", food);
pc->_pFood = Food;
}
}
void PrintHelpInfo()
{
//打印提⽰信息
SetPos(64, 15);
printf("不能穿墙,不能咬到自己");
SetPos(64, 16);
printf("用↑.↓.←.→分别控制蛇的移动.");
SetPos(64, 17);
printf("F3 为加速,F4 为减速");
SetPos(64, 18);
printf("ESC :退出游戏.space:暂停游戏.");
SetPos(64, 20);
printf("江氏@版权");
}
void puse()
{
while (1)
{
Sleep(300);
if (KEY_PRESS(VK_SPACE))
{
break;
}
}
}
int NextIsFood(pSnakeNode node, pSnake pc)
{
return node->x == pc->_pFood->x && node->y == pc->_pFood->y;
}
void EatFood(pSnakeNode nod, pSnake pc)
{
nod->next = pc->_pSnake;
pc->_pSnake = nod;
pSnakeNode cur = pc->_pSnake;
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", body);
cur = cur->next;
}
pc->_Score += pc->_Add;
free(pc->_pFood);
CreatFood(pc);
}
void NoFood(pSnakeNode nod, pSnake pc)
{
nod->next = pc->_pSnake;
pc->_pSnake = nod;
pSnakeNode cur = pc->_pSnake;
while (nod->next->next)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", body);
nod = nod->next;
}
SetPos(nod->next->x, nod->next->y);
printf(" ");
free(nod->next);
nod->next = NULL;
}
int KillByWall(pSnake pc)
{
if (pc->_pSnake->x == 0 ||
pc->_pSnake->x == 56 ||
pc->_pSnake->y == 0 ||
pc->_pSnake->y == 26) {
pc->_Status = KILL_BY_WALL;
return 1;
}
return 0;
}
int KillBySelf(pSnake pc)
{
pSnakeNode nod = pc->_pSnake->next;
while (nod)
{
if (pc->_pSnake->x == nod->x &&
pc->_pSnake->y == nod->y)
{
pc->_Status = KILL_BY_SELF;
return 1;
}
nod = nod->next;
}
return 0;
}
void SnakeMove(pSnake pc)
{
pSnakeNode nod = NULL;
nod = (pSnakeNode)malloc(sizeof(SnakeNode));
if (nod == NULL) {
perror("SnakeNode():malloc");
return;
}
switch (pc->_Dri)
{
case UP:
{
nod->x = pc->_pSnake->x;
nod->y = pc->_pSnake->y - 1;
}
break;
case DOWN:
{
nod->x = pc->_pSnake->x;
nod->y = pc->_pSnake->y +1;
}
break;
case LEFT:
{
nod->x = pc->_pSnake->x-2;
nod->y = pc->_pSnake->y ;
}
break;
case RIGHT:
{
nod->x = pc->_pSnake->x+2;
nod->y = pc->_pSnake->y ;
}
break;
}
//判断下一个节点是不是食物
if (NextIsFood(nod,pc))
{
EatFood(nod, pc);
}
else
{
NoFood(nod, pc);
}
KillByWall(pc);
KillBySelf(pc);
}
void GameStart(pSnake pc)
{
//设置控制台窗口的大小
system("mode con cols=100 lines=30");
//设置窗口名字
system("title 贪吃蛇");
//获取句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//隐藏光标
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台窗口光标信息
//影藏控制台光标信息
CursorInfo.bVisible = false;
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
//打印欢迎界面
Welcome();
//打印地图
CreatMap();
//初始化蛇
InitSnake(pc);
//创造食物
CreatFood(pc);
}
void GameRun(pSnake pc)
{
//打印有用信息
PrintHelpInfo();
do {
SetPos(64, 10);
printf("得分:%d", pc->_Score);
SetPos(64, 11);
printf("每个食物得分:%2d", pc->_Add);
if (KEY_PRESS(VK_UP) && pc->_Dri != DOWN)
{
pc->_Dri = UP;
}
else if (KEY_PRESS(VK_DOWN) && pc->_Dri != UP)
{
pc->_Dri = DOWN;
}
else if (KEY_PRESS(VK_RIGHT) && pc->_Dri != LEFT)
{
pc->_Dri = RIGHT;
}
else if (KEY_PRESS(VK_LEFT) && pc->_Dri != RIGHT)
{
pc->_Dri = LEFT;
}
else if (KEY_PRESS(VK_ESCAPE))
{
pc->_Status = ESC_NOMAL;
break;
}
else if (KEY_PRESS(VK_SPACE))
{
puse();
}
else if (KEY_PRESS(VK_F3))
{
if (pc->_SleepTime >= 50)
{
pc->_SleepTime -= 30;
pc->_Add += 2;
}
}
else if (KEY_PRESS(VK_F4))
{
if (pc->_SleepTime <= 350)
{
pc->_SleepTime += 30;
pc->_Add -= 2;
if (pc->_SleepTime == 350)
{
pc->_Add = 1;
}
}
}
Sleep(pc->_SleepTime);
SnakeMove(pc);
} while (pc->_Status==OK);
}
void GameOver(pSnake pc)
{
pSnakeNode nod = pc->_pSnake;
SetPos(24, 12);
switch (pc->_Status)
{
case KILL_BY_WALL:
printf("您撞墙了,游戏结束!\n");
break;
case KILL_BY_SELF:
printf("您吃到自己了,游戏结束!\n");
break;
case ESC_NOMAL:
printf("您主动退出游戏!\n");
break;
}
//释放蛇身
while (nod)
{
pSnakeNode cur = nod;
nod = nod->next;
free(cur);
}
}
//text.c文件代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Snake.h"
void text()
{
char ch;
Snake snake = { 0 };
do {
GameStart(&snake);
GameRun(&snake);
GameOver(&snake);
SetPos(24, 15);
printf("再来一局吗(Y/N)>:");
scanf("%c", &ch);
} while (ch == 'Y' || ch == 'y');
SetPos(0, 27);
}
int main()
{
srand((unsigned int)time(NULL));
setlocale(LC_ALL, "");
text();
return 0;
}