千家信息网

如何使用C++实现贪吃蛇游戏

发表于:2024-11-26 作者:千家信息网编辑
千家信息网最后更新 2024年11月26日,这篇文章给大家分享的是有关如何使用C++实现贪吃蛇游戏的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。贪吃蛇游戏键盘控制小蛇上、下、左、右移动,迟到食物后长度加1;蛇头碰到自
千家信息网最后更新 2024年11月26日如何使用C++实现贪吃蛇游戏

这篇文章给大家分享的是有关如何使用C++实现贪吃蛇游戏的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

贪吃蛇游戏

键盘控制小蛇上、下、左、右移动,迟到食物后长度加1;蛇头碰到自身或窗口边缘,游戏失败

程序框架

#include #include #include // 全局变量定义void startup()                       // 初始化函数{}void show()                          // 绘制函数{        }void updateWithoutInput()            // 与输入无关的更新{}void updateWithInput()               // 和输入有关的更新{}int main(){        startup();                       // 初始化函数,仅执行一次        while (1)        {                show();                      // 进行绘制                updateWithoutInput();        // 和输入无关的更新                updateWithInput();           // 和输入有关的更新        }        return 0;}

绘制游戏地图和蛇

绘制网格状的游戏地图,使用二维数组Blocks存储每个网格的信息。二维数组Blocks中也可以记录蛇的信息。设定元素值为0表示空,画出灰色的方格;元素值为1表示蛇头,蛇头后的蛇身依次为2、3、4、5等正整数,画出彩色的方格

int i, j;for (i = 0; i < HEIGHT; i++){        for (j = 0; j < WIDTH; j++)        {                if (Blocks[i][j] > 0)                {                        setfillcolor(HSVtoRGB(Blocks[i][j] * 10, 0.9, 1));                }                else                {                        setfillcolor(RGB(150, 150, 150));                }                fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);        }}

小蛇向右移动

假设小蛇初始元素值为54321,其中1位蛇头,5432位蛇身。首先将二维数组中所有大于0的元素加1,得到65432;然后将最大值6变成0,即去除了原来的蛇尾;最后将2右边的元素由0变成1,即实现了小蛇向右移动

void moveSnake(){        int i, j;        for (i = 0; i < HEIGHT; i++)        {                for (j = 0; j < WIDTH; j++)                {                        if (Blocks[i][j] > 0)                        {                                Blocks[i][j]++;                        }                }        }        int oldTail_i, oldTail_j, oldHead_i, oldHead_j;        int max = 0;        for (i = 0; i < HEIGHT; i++)        {                for (j = 0; j < WIDTH; j++)                {                        if (max < Blocks[i][j])                        {                                max = Blocks[i][j];                                oldTail_i = i;                                oldTail_j = j;                        }                        if (Blocks[i][j] == 2)                        {                                oldHead_i = i;                                oldHead_j = j;                        }                }        }        int newHead_i = oldHead_i;        int newHead_j = oldHead_j;        newHead_j = oldHead_j + 1;        Blocks[newHead_i][newHead_j] = 1;        Blocks[oldTail_i][oldTail_j] = 0;}void updateWithoutInput()            // 与输入无关的更新{        moveSnake();        Sleep(100);}

控制小蛇4个方向移动

变量oldHead_i、oldHead_j存储移动前的蛇头位置,newHead_i、newHead_j存储移动后的蛇头位置。小蛇向上移动,只需把新蛇头的坐标设为旧蛇头的上方即可

newHead_i = oldHead_i - 1;

让玩家用A、S、D、W键控制游戏角色移动,定义字符变量moveDirection表示小蛇运动方向,在moveSnake函数中对其值进行判断,取A向左运动、D向右运动、W向上运动、S向下运动:

if (moveDirection == 'A'){        newHead_j = oldHead_j - 1;}else if (moveDirection == 'D'){        newHead_j = oldHead_j + 1;}else if (moveDirection == 'W'){        newHead_i = oldHead_i - 1;}else if (moveDirection == 'S'){        newHead_i = oldHead_i + 1;}

在updateWithInput()函数中获得用户按键输入,如果是A、S、D、W键之一,就更新moveDirection变量,执行moveSnake()函数让小蛇向对应方向移动:

void updateWithInput()               // 和输入有关的更新{        if (_kbhit())        {                char input = _getch();                if (input == 'A' || input == 'S' || input == 'D' || input == 'W')                {                        moveDirection = input;                        moveSnake();                }        }}

时间控制的改进

在Sleep()函数运行时,整个程序都会暂停,包括用户输入模块。用户会感觉到卡顿

利用静态变量,将updateWithoutInput()修改如下:

void updateWithoutInput()            // 与输入无关的更新{        static int waitIndex = 1;        waitIndex++;                     // 每一帧加1        if (waitIndex == 10)        {                moveSnake();                waitIndex = 1;        }}

其中,updateWithoutInput()每次运行时,waitIndex加1,每隔10帧,才执行一次移动函数moveSnake()。这样可在不影响用户按键输入的情况下,降低小蛇的移动速度

失败判断与显示

定义全局变量isFailure表示游戏是否失败,初始化为0:

int isFailure = 0;

当小蛇碰到画面边界时,则认为游戏失败;当蛇头与蛇身发生碰撞时,游戏也失败。由于每次只有蛇头是新生成的位置,所以在moveSnake()函数中只需判断蛇头是否越过边界和碰撞:

     if (newHead_i >= HEIGHT || newHead_i < 0 || newHead_j >= WIDTH || newHead_j < 0 || Blocks[newHead_i][newHead_j] > 0)         {                isFailure = 1;                return;        }在show()函数中添加游戏失败后的显示信息:        if (isFailure)                   // 游戏失败        {                setbkmode(TRANSPARENT);      // 文字字体透明                settextcolor(RGB(255, 0, 0));                settextstyle(80, 0, _T("宋体"));                outtextxy(240, 220, _T("游戏失败"));        }

在updateWithoutInput()中添加代码,当isFailure为1时,直接返回:

void updateWithoutInput()            // 与输入无关的更新{ if (isFailure) {  return; } //...}

在updateWithInput()中,只有当按下键盘且isFailure为0时,才进行相应的处理:

void updateWithInput()               // 和输入有关的更新{ if (_kbhit() && isFailure == 0) {  // ... }}

添加食物

添加全局变量记录食物的位置:

int food_i, food_j;在startup()函数中初始化食物的位置:void startup()                       // 初始化函数{ food_i = rand() % (HEIGHT - 5) + 2; food_j = rand() % (WIDTH - 5) + 2;}

在show()函数中在食物位置处绘制一个绿色小方块:

setfillcolor(RGB(0, 255, 0));fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);

当新蛇头碰到食物时,只需保留原蛇尾,即可让蛇的长度加1。当吃到食物时,食物位置重新随机出现,蛇长度加1;当没有迟到食物时,旧蛇尾变成空白,蛇长度保持不变:

Blocks[newHead_i][newHead_j] = 1;// 新蛇头位置数值为1if (newHead_i == food_i && newHead_j == food_j) // 如果新蛇头碰到食物{ food_i = rand() % (HEIGHT - 5) + 2; // 食物重新随机位置 food_j = rand() % (WIDTH - 5) + 2;}else{ Blocks[oldTail_i][oldTail_j] = 0;   // 旧蛇尾变成空白}

完整代码

#include #include #include #define BLOCK_SIZE 20                // 每个小格子的长宽#define HEIGHT 30                    // 高度上一共30个小格子#define WIDTH 40                     // 宽度上一共40个小格子// 全局变量定义int Blocks[HEIGHT][WIDTH] = { 0 };char moveDirection;int isFailure = 0;int food_i, food_j;                  // 食物的位置void startup()                       // 初始化函数{ int i; Blocks[HEIGHT / 2][WIDTH / 2] = 1;  // 画面中间画蛇头 for (i = 1; i <= 4; i++)            // 向左依次4个蛇身 {  Blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1; } moveDirection = 'D'; food_i = rand() % (HEIGHT - 5) + 2; food_j = rand() % (WIDTH - 5) + 2; initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE); setlinecolor(RGB(200, 200, 200)); BeginBatchDraw();                   // 开始批量绘制}void show()                          // 绘制函数{ cleardevice(); int i, j; for (i = 0; i < HEIGHT; i++) {  for (j = 0; j < WIDTH; j++)  {   if (Blocks[i][j] > 0)   {    setfillcolor(HSVtoRGB(Blocks[i][j] * 10, 0.9, 1));   }   else   {    setfillcolor(RGB(150, 150, 150));   }   fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);  } } setfillcolor(RGB(0, 255, 0));    // 食物颜色为绿色 fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE); if (isFailure)                   // 游戏失败 {  setbkmode(TRANSPARENT);      // 文字字体透明  settextcolor(RGB(255, 0, 0));  settextstyle(80, 0, _T("宋体"));  outtextxy(240, 220, _T("游戏失败")); } FlushBatchDraw();                // 批量绘制}void moveSnake(){ int i, j; for (i = 0; i < HEIGHT; i++) {  for (j = 0; j < WIDTH; j++)  {   if (Blocks[i][j] > 0)     // 大于0的为小蛇元素   {    Blocks[i][j]++;   }  } } int oldTail_i, oldTail_j, oldHead_i, oldHead_j; // 存储旧蛇 int max = 0; for (i = 0; i < HEIGHT; i++) {  for (j = 0; j < WIDTH; j++)  {   if (max < Blocks[i][j])   {    max = Blocks[i][j];    oldTail_i = i;    oldTail_j = j;   }   if (Blocks[i][j] == 2)      // 旧蛇头   {    oldHead_i = i;    oldHead_j = j;   }  } } int newHead_i = oldHead_i;          // 设定变量存储新蛇头 int newHead_j = oldHead_j; if (moveDirection == 'A')           // 根据用户按键,设定新蛇头的位置 {  newHead_j = oldHead_j - 1; } else if (moveDirection == 'D') {  newHead_j = oldHead_j + 1; } else if (moveDirection == 'W') {  newHead_i = oldHead_i - 1; } else if (moveDirection == 'S') {  newHead_i = oldHead_i + 1; }  if (newHead_i >= HEIGHT || newHead_i < 0 || newHead_j >= WIDTH || newHead_j < 0 || Blocks[newHead_i][newHead_j] > 0) // 失败条件 {  isFailure = 1;  return; } Blocks[newHead_i][newHead_j] = 1;               // 新蛇头位置数值为1 if (newHead_i == food_i && newHead_j == food_j) // 如果新蛇头碰到食物 {  food_i = rand() % (HEIGHT - 5) + 2;         // 食物重新随机位置  food_j = rand() % (WIDTH - 5) + 2; } else {  Blocks[oldTail_i][oldTail_j] = 0;           // 旧蛇尾变成空白 }}void updateWithoutInput()                           // 与输入无关的更新{ if (isFailure) {  return; } static int waitIndex = 1; waitIndex++;                                     // 每一帧加1 if (waitIndex == 10) {  moveSnake();  waitIndex = 1; }}void updateWithInput()                                // 和输入有关的更新{ if (_kbhit() && isFailure == 0) {  char input = _getch();  if (input == 'A' || input == 'S' || input == 'D' || input == 'W')  {   moveDirection = input;   moveSnake();  } }}int main(){ startup();                       // 初始化函数,仅执行一次 while (1) {  show();                      // 进行绘制  updateWithoutInput();        // 和输入无关的更新  updateWithInput();           // 和输入有关的更新 } return 0;}

感谢各位的阅读!关于"如何使用C++实现贪吃蛇游戏"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

0