C语言实现简易贪吃蛇(详细版)(2)
欢迎回到本博客!如果你已经阅读了我们之前的文章,你就知道我们已经完成了一些基础工作,包括创建游戏窗口、Win32 API 介绍, 定位使用光标,初始化游戏界面。如果你还没有看过,别担心,你可以点击这里查看或主页看。
话不多说,咱们继续:
目录
-
C语言实现简易贪吃蛇(详细版)(2) -
主体部分 - 蛇的移动
- 函数名称: CreateFood
- 碰撞检测
- 函数名称: CreateOver
- 游戏运行及分数计算
- 函数名称: PrintHelpInfo
- 函数名称: GameRun
-
主体部分
蛇的移动:根据用户输入控制蛇的移动方向,以及是否吃到了食物,并更新游戏地图。
碰撞检测:检测蛇头是否与边界或蛇身相撞。
游戏运行及分数计算:根据蛇吃到的食物数量计算玩家的得分。
void SnakeMove(Snake* ps)
{
// 创建一个新节点,表示蛇即将到达的下一个位置
Body P = (Body)malloc(sizeof(body));
// 根据当前蛇的移动方向更新新节点的位置
switch (ps->_dir)
{
case UP:
P->x = ps->_pSnake->x;
P->y = ps->_pSnake->y - 1;
break;
case DOWN:
P->x = ps->_pSnake->x;
P->y = ps->_pSnake->y + 1;
break;
case LEFT:
P->x = ps->_pSnake->x - 2;
P->y = ps->_pSnake->y;
break;
case RIGHT:
P->x = ps->_pSnake->x + 2;
P->y = ps->_pSnake->y;
break;
}
// 将新节点插入到蛇的头部
P->next = ps->_pSnake;
ps->_pSnake = P;
// 在控制台上显示蛇的身体
SetPos(P->x, P->y);
wprintf(L"%lc", BODY);
// 判断下一个节点是否是食物
Body T = ps->_pSnake;
while (T->next->next)
{
T = T->next;
}
if (P->x == ps->_pFood->x && P->y == ps->_pFood->y)
{
// 如果蛇头碰到食物,则增加得分并创建新的食物
ps->_score += ps->_food_weight;
CreateFood(ps);
}
else
{
// 如果蛇头没有碰到食物,则移除蛇尾的节点,使蛇移动
SetPos(T->next->x, T->next->y);
printf(" ");
free(T->next);
T->next = NULL;
}
}
void GameOver(pSnake ps)
{
// 检查蛇头是否碰到墙壁,如果是,则游戏状态为被墙壁杀死
if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 || ps->_pSnake->y == 0 || ps->_pSnake->y == 27)
ps->_status = KILL_BY_WALL;
// 遍历蛇的身体,检查是否蛇头碰到了自己的身体
Body B = ps->_pSnake->next;
while (B)
{
if (B->x == ps->_pSnake->x && B->y == ps->_pSnake->y)
{
// 如果蛇头碰到了自己的身体,则游戏状态为被自己杀死
ps->_status = KILL_BY_SELF;
break;
}
B = B->next;
}
}
void PrintHelpInfo()
{
//打印提⽰信息
SetPos(64, 15);
printf("不能穿墙,不能咬到自己.\n");
SetPos(64, 16);
printf("用↑.↓.←.→.分别控制蛇的移动\n");
SetPos(64, 17);
wprintf(L"F3 为加速,F4 为减速\n");
SetPos(64, 18);
wprintf(L"ESC;退出游戏. space;暂停游戏.\n");
SetPos(64, 20);
}
void Pause()
{
// 进入暂停循环,直到按下空格键
while (1)
{
Sleep(200);
// 检查是否按下了空格键
if (KEY_PRESS(VK_SPACE))
{
// 退出暂停循环
break;
}
}
}
void GameRun(pSnake ps)
{
// 打印帮助信息
PrintHelpInfo();
// 游戏循环
do
{
// 打印游戏状态信息
SetPos(64, 10);
printf("总分数:%d\n", ps->_score);
SetPos(64, 11);
printf("当前食物的分数:%2d\n", ps->_food_weight);
// 调用宏定义函数,根据按键控制蛇的移动方向
if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
{
ps->_dir = UP;
}
else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
{
ps->_dir = DOWN;
}
else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
{
ps->_dir = LEFT;
}
else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
{
ps->_dir = RIGHT;
}
else if (KEY_PRESS(VK_SPACE))
{
// 暂停游戏
Pause();
}
else if (KEY_PRESS(VK_ESCAPE))
{
// 游戏状态为正常退出游戏
ps->_status = END_NORMAL;
}
else if (KEY_PRESS(VK_F3))
{
// 加速
if (ps->_sleep_time > 80)
{
ps->_sleep_time -= 30;
ps->_food_weight += 2;
}
}
else if (KEY_PRESS(VK_F4))
{
// 减速
if (ps->_food_weight > 2)
{
ps->_sleep_time += 30;
ps->_food_weight -= 2;
}
}
// 蛇移动一步
SnakeMove(ps);
// 刷新速度
Sleep(ps->_sleep_time);
// 检查游戏是否结束
GameOver(ps);
} while (ps->_status == OK);
// 打印游戏结束信息
SetPos(25, 13);
printf("游戏结束!");
}
在本篇博客中,我们学习了如何实现蛇的移动控制、碰撞检测以及游戏运行及分数计算等关键功能。通过这些功能的实现,我们的游戏已经具备了基本的可玩性,在下一篇文章中我们将完成最后的封装,以及探讨如何优化游戏体验,包括增加更多的游戏元素、优化界面设计以及添加音效等内容。敬请期待!