该项目适合刚学完C语言结构体,有一定C语言基础的练习,该小项目可以帮助自己锻练的面向对象编程思想。
1.游戏实现思想
要想实现贪吃蛇游戏,根据面向对象的思想,要实现出以下几个模块
1. 定义蛇对象、食物对象 2. 初始化蛇、初始化食物 3. 控制流程: 1) 蛇头和墙壁的碰撞 2) 蛇头和蛇身体的碰撞 3) 蛇头和食物的碰撞 1> 蛇身增长 2> 食物消失 -- 新食物产生 3> 分数累加 4> 移动速度增大 4)蛇的移动 自动移动 手动控制移动: ASWD --- 左下上右 5)显示分数 排行榜 4. 图形界面。
(1)定义蛇对象
蛇对象实现方式原理是坐标,而设置X,Y分别表示横坐标与纵坐标,身体使用数组方式表示可以body[0],表示蛇头,其他表示蛇身,蛇的大小会根据吃的食物个数而增加。
代码语言:javascript复制struct BODY {
int x;
int Y;
};
struct SNAKE {
struct BODY body[20*60]; // 蛇身 。 body[0] -- 蛇头
int size; // 蛇的大小
}snake;
(2)食物对象
食物对象实现和蛇对象实现同理
代码语言:javascript复制struct FOOD {
int X;
int Y;
}food;
(3)分数:
代码语言:javascript复制 int score;
(4)初始化蛇
封装一个函数 完成蛇的初始,蛇的初始大小为2,分别表示蛇身和蛇头
代码语言:javascript复制 void initSnake(void)
{
snake.size = 2;
snake.body[0].X = WIDE/2; // 初始化好了蛇头
snake.body[0].Y = HiGH/2;
snake.body[1].X = WIDE/2 - 1; // 初始化一节蛇身
snake.body[1].Y = HIGH/2;
}
(5)初始化食物
代码语言:javascript复制void initFood(void)
{
food.X = rand() % WIDE; // 0-59
food.Y = rand() % HIGH; // 0-59
return;
}
(6)修改控制台光标位置
会将光标位置,定位到 初始化好的蛇头位置(WIDE/2, HIGH/2). 屏幕中间 。注意实现下面代码要用到头文件:#include <conio.h>,#include <Windows.h>
代码语言:javascript复制COORD coord; // COORD --> 结构体, 有两个成员变量:x,y 坐标
coord.X = snake.body[0].X;
coord.Y = snake.body[0].Y;
setConsoleCursorPositon(GetStdHandle(STD_OUTPUT_HANDLE), coord);
(7)画出蛇和食物
“@”表示蛇头,“*”表示蛇身。“#”表示食物
代码语言:javascript复制封装函数, initUI()
COORD coord = {0}; // 光标移动的位置。
// 画蛇
for (size_t i = 0; i < snake.size; i )
{
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
if (i == 0)
putchar('@');
else
putchar('*');
}
// 画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar('#');
(8)蛇的移动控制
键盘输入
W:(0, -1) --> 影响蛇头。 s:(0, 1) A:(-1, 0) D:( 1, 0)
不回显:可以让键盘打的asdw不显示在输入界面
getch() 接收用户输入。 char key = getch(); 编译时出错,尝试使用 _getch();
不阻塞:可以让输入的小蛇光标不阻塞
kbhit(); 不阻塞判断用户输入。 有用户输入,返回 “真”, 否则返回“假”值。 编译时出错,尝试使用 _kbhit();
(9)开始游戏
代码语言:javascript复制void playGame(void)
{
char key = 'd'; // 默认蛇向右移动
// 蛇头和墙壁的碰撞:
while ( 判断是否撞墙 ) {
// 重画蛇身 intiUI
// 接收用户键盘输入。
在全局 添加:kx, ky --》 根据 asdw 按键得不同坐标,影响蛇头
// 蛇头和身体的碰撞
// 蛇与食物的碰撞
// 蛇身体移动 : 前一节给后一节赋值,蛇头收 kx ky 的影响。
system("cls"); 清屏 -- 去除蛇尾。
}
}
蛇头和墙壁的碰撞
判断条件
代码语言:javascript复制snake.body[0].X > 0 && snake.body[0].X < WIDE
&&
snake.body[0].Y > 0 && snake.body[0].Y < HIGH
蛇头和身体的碰撞
蛇头的坐标 和 任意一节身体的坐标 完全一致。
代码语言:javascript复制for(i = 1; i < snake.size; i )
{
if (snake.body[0].X == snake.body[i].X && snake.body[0].Y == snake.body[i].Y )
{
终止游戏。
return ;
}
}
蛇头和食物的碰撞
代码语言:javascript复制if (snake.body[0].X == food.X && snake.body[0].Y == food.Y)
{
蛇身增长: snake.size ;
食物消失:(产生一个新食物)initFood()
加分:score = 10;
加速:sleepSecond -= 20;
}
(10)蛇移动
前一节身体给后一节身体赋值。 蛇头按照 aswd 换算的坐标值 进行变换。
代码语言:javascript复制 for (size_t i = snake.size-1; i > 0; i--)
{
snake.body[i].X = snake.body[i - 1].X;
snake.body[i].Y = snake.body[i - 1].Y;
}
snake.body[0].X = kx; // 蛇头坐标根据用户按键,修改。
snake.body[0].Y = ky;
(11)画墙
代码语言:javascript复制void initWall(void)
{
for (size_t i = 0; i <= HIGH; i ) // 多行
{
for (size_t j = 0; j <= WIDE; j ) // 一行中的多列
{
if (j == WIDE)
{
printf("|");
}
else if (i == HIGH)
{
printf("_");
}
else
{
printf(" ");
}
}
printf("n");
}
}
(12)去除蛇尾
蛇移动之前保存蛇尾坐标。
定义全局变量 :lastX, lastY;
lastX = snake.body[snake.size-1].X ; lastY = snake.body[snake.size-1].Y ;
在initUI中, 将蛇尾 替换为 ' '
代码语言:javascript复制coord.X = lastX;
coord.Y = lastY;
setConsoleCursorPosition(GetSTDHandler(STD_OUTPUT_HANDLE), coord);
putchar(' ');
(13)去除光标
取消显示的光标:请按任意位置继续,使得界面更美观
代码语言:javascript复制typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize; // 大小
BOOL bVisible; // 是否可见。
} CONSOLE_CURSOR_INFO;
定义结构体变量:
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE; // 0 假 --- 不可见
设置光标不可见生效:
setConsoleCursorInfo(GetSTDHandler(STD_OUTPUT_HANDLE), &cci);
在main函数中,调用一次即可生效。
(14)显示分数
playGame调用结束时,打印 全局score 值。
(15)加速
全局定义变量: sleepSecond = 400;
Sleep(sleepSecond);
成功吃食物, sleepSecond -= 20;
2.游戏实现代码和头文件
游戏使用建议使用VS编辑器,不建议初学者使用dev编辑器,下面有完整代码和实现好的exe文件,感兴趣的可以打包带走。
下图是代码实现后