文章目录
该篇环境为Visual Studio2022
游戏简述 :在控制终端绘画出一个矩阵表示游戏界面(围墙),“ @ ”表示蛇头,“ * ”表示蛇身,“ # ”表示食物。通过向控制终端输入"a"、“s”、“w”、"d"分别表示贪吃蛇向左、向下、向上、向右移动,食物为随机出现(同一时刻只有一个食物出现),每吃掉一块食物,蛇的移动速度加快且游戏分数+10,若蛇撞到墙或吃到自身会导致游戏结束并打印游戏分数在终端上。
一、定义结构体对象
该游戏可划分为俩个对象,“贪吃蛇”和“食物”对象
而“贪吃蛇”对象 又可划分为“一节蛇头”和“多节蛇身”
1. 定义蛇身结构体
struct BODY {
int X; //x 和 y 表示蛇身的一个位置点(坐标)
int Y;
};
2. 定义蛇对象
其中 body[0]为蛇头,其余都表示蛇身
struct SNAKE {
struct BODY body[WIDE * HIGH]; //WIDE和HIGH表示游戏界面的宽和高
int size;
}snake;
3. 定义食物对象
struct FOOD {
int X; //表示食物的位置点
int Y;
}food;
二、游戏初始化
1. 蛇初始化
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;
return;
}
2. 食物初始化
void initFood(void) {
food.X = rand() % WIDE;
food.Y = rand() % HIGH;
return;
}
3. 围墙初始化
//画墙
void initWall(void) {
for (size_t i = 0; i <= HIGH; i++)
{
for (size_t j = 0; j <= WIDE; j++)
{
if (j == WIDE)
cout << "|";
else if (i == HIGH)
cout << "_";
else
cout << " ";
}
cout << endl;
}
}
4. 界面初始化
void initUI(void) {
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 = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar(' ');
//画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar('#');
}
三、逻辑编程
1. 启动游戏
void playGame(void) {
char key = 'd';
//判断蛇撞墙
while (snake.body[0].X >= 0 && snake.body[0].X < WIDE
&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH) {
initUI(); //更新蛇
//接收用户按键输入
if (_kbhit()) {
//为真时,说明用户按下按键 _kbhit()不阻塞判断用户输入
key = _getch(); // _getch()不回显读取一个字符
}
switch (key) {
case 'w': kx = 0; ky = -1; break;
case 's': kx = 0; ky = +1; break;
case 'a': kx = -1; ky = 0; break;
case 'd': kx = +1; ky = 0; break;
default: break;
}
//蛇头撞身体 蛇头==任一一节身体
for (size_t i = 1; i < snake.size; i++)
{
if (snake.body[0].X == snake.body[i].X && snake.body[0].Y == snake.body[i].Y)
return; //游戏结束
}
//蛇头撞食物
if (snake.body[0].X == food.X && snake.body[0].Y == food.Y) {
initFood(); //食物消失
snake.size++; //身体增长
score += 10; //加分
sleepSecond -= 25;//加速
}
//存储蛇尾坐标
lastX = snake.body[snake.size - 1].X;
lastY = snake.body[snake.size - 1].Y;
//蛇移动,前一节身体给后一节身体赋值
for (size_t k = snake.size - 1; k > 0; k--)
{
snake.body[k].X = snake.body[k - 1].X;
snake.body[k].Y = snake.body[k - 1].Y;
}
snake.body[0].X += kx; //蛇头坐标根据用户按键 修改
snake.body[0].Y += ky;
Sleep(sleepSecond);
}
return;
}
2. 打印成绩
void showScore(void) {
//将光标默认位置移动至 不干扰游戏的位置
COORD coord;
coord.X = 0;
coord.Y = HIGH + 2;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
cout << "Game Over!!!" << endl;
cout << "成绩为:" << score << endl<<endl<<endl;
}
3. main函数
int main(void) {
//去除光标
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE; //设置为false则光标不可见
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
srand(time(NULL)); //播种随机数种子
initWall(); //画墙
initSnake(); //初始化蛇
initFood(); //初始化食物
initUI(); //画蛇和食物
playGame(); //启动游戏
showScore(); //打印分数
system("pause");
return 0;
}
四、细节处理
在该游戏的制作过程中,有以下几个方面的细节处理:
- 1. 绘画问题
每绘画蛇和食物图像时,都需要将光标移动到指定地方才能成功绘画。
COORD 为光标移动处理结果体
COORD coord;
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
- 2. 去除光标闪烁问题
CONSOLE_CURSOR_INFO 为光标显示处理结构体
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE; //设置为false则光标不可见
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
- 3. 蛇尾隐藏
蛇每吃掉一块食物,蛇身便会增长一节,急需对蛇尾做隐藏处理
//存储蛇尾坐标
lastX = snake.body[snake.size - 1].X;
lastY = snake.body[snake.size - 1].Y;
coord.X = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); //移动光标
putchar(' '); //用“ ”覆盖蛇尾
- 4. 接收用户按键输入
_kbhit()不阻塞判断用户输入
_getch()不回显读取一个字符
if (_kbhit()) {
//为真时,说明用户按下按键
key = _getch();
}
- 5. 延迟
若不对移动时进行Sleep处理,则蛇移动速度飞快,游戏一下就结束了。
Sleep(sleepSecond);
五、程序源码
若需程序源码可留言邮箱至评论区或直接私信 即可。