• 贪吃蛇小游戏-----C语言实现


    1.分析

      众所周知,贪吃蛇游戏是一款经典的益智游戏,有PC和手机等多平台版本,既简单又耐玩。该游戏通过控制蛇头方向吃食物,从而使得蛇变得越来越长,蛇不能撞墙,也不能装到自己,否则游戏结束。玩过贪吃蛇的朋友都知道这个小游戏有一圈“墙”、还有食物以及蛇,还有吃了食物之后的分数。所以通过C语言实现贪吃蛇,可以分为以下几个模块来实现:

      a)编程实现“墙”

      b)实现随机食物的生成

      c)蛇的构建

      d)以上三部分都实现了之后,实现游戏运行的部分,包括蛇的移动、吃食物、判断是否撞墙或者撞到自己。

      e)游戏结束时的相关操作

    2.具体思路

      要通过C语言实现贪吃蛇,首先就要用C语言将贪吃蛇的相关信息描述出来。C语言提供了结构体类型,我们可以用结构体描述蛇的结点(结点的横纵坐标)、运动状态、总分数、每个食物的分数等等。

      首先实现进入游戏的"welcome"界面,为了将“欢迎来到贪吃蛇游戏”打印到屏幕的中间,可以运用库函数先设置窗口的大小(system("mode con cols=100 lines=30");将窗口设置为长100,宽30),再通过库函数中的GetStdHandle函数、SetConsoleCursorPosition函数(把光标定位到我们需要的位置)将这句话打印到屏幕中央。

      其次可以通过相同的方法将光标固定到我们需要的位置,用特殊字符‘■’打印实现墙(注意,‘■’在c中占用两个字符,所以在设置循环条件时要格外注意)

      接着通过编程实现蛇的移动,本文中蛇是通过单链表实现的,因此在实现蛇的移动时,如果蛇接下来走的位置(上下左右)为食物,将这个位置的用指针表示,可以将食物头插到用_psnake指针维护的蛇身中,如果接下来的位置不是食物,同样头插到蛇身中,再将蛇的最后一个结点打印时输出为空格字符,然后free最后一个节点。

    3.代码如下

    snake.h:

     1 #pragma once
     2 
     3 #include<Windows.h>
     4 #include<stdio.h>
     5 #include<time.h>
     6 #include<stdlib.h>
     7 
     8 #define WALL "■"
     9 #define FOOD "●"
    10 
    11 #define INIT_X 20
    12 #define INIT_Y 18
    13 typedef struct SnakeNode
    14 {
    15     int x;
    16     int y;
    17     struct SnakeNode *next;
    18 }SnakeNode, *pSnakeNode;
    19 
    20 //蛇的方向
    21 enum Diretion
    22 {
    23     UP,
    24     DOWN,
    25     LEFT,
    26     RIGHT
    27 };
    28 
    29 //状态
    30 enum GameState
    31 {
    32     OK,
    33     NORMAL_END,
    34     KILL_BY_WALL,
    35     KILL_BY_SELF
    36 };
    37 //游戏结构体
    38 typedef struct Snake
    39 {
    40     pSnakeNode _psnake;//维护蛇身的指针
    41     pSnakeNode _pFood;//维护食物的位置
    42     int _TotalScore;//总分数
    43     int _AddScore;//增加的分数
    44     int _SleepTime;//休眠时间
    45     enum Direction  _Dir;
    46     enum GameStatus _Status;
    47 }Snake, *pSnake;
    48 
    49 void GameStart(pSnake ps);
    50 void WelcomeToGame();//欢迎界面函数
    51 void SetPos(int x, int y);
    52 void CreateMap();//创建地图
    53 void InitSnake(pSnake ps);
    54 void CreateFood(pSnake ps);//创建食物
    55 void GameRun(pSnake ps);//运行游戏
    56 void pause();//暂停函数
    57 
    58 void snakmove(pSnake ps);
    59 int NextHasFood(pSnakeNode pn, pSnakeNode pf);//判断下个结点是否为食物
    60 void EatFood(pSnake ps,pSnakeNode pn);//吃食物
    61 void NoFood(pSnake ps, pSnakeNode pn);//没有食物
    62 void KillBYWALL(pSnake ps);
    63 void KillBySelf(pSnake ps);
    64 void GameEnd(pSnake ps);

    snake.c:

      1 #include"snake.h"
      2 void  SetPos(int x, int y)
      3 {
      4     COORD pos = { 0 };
      5     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
      6     pos.X = x; pos.Y = y;
      7     SetConsoleCursorPosition(handle, pos);//把光标定位到我们需要的位置了
      8 }
      9 void WelcomeToGame()//欢迎界面函数
     10 {
     11     //设置窗口大小
     12     system("mode con cols=100 lines=30");
     13     SetPos(40, 13);//分装的函数用来定位光标
     14     printf("欢迎来到贪吃蛇小游戏
    ");
     15     SetPos(35, 25);
     16     system("pause");//暂停
     17     system("cls");//清空屏幕
     18     SetPos(30, 9);
     19     printf("用↑,↓,←,→来控制蛇的移动,F1为加速,F2为减速
    ");
     20     SetPos(40, 11);
     21     printf("加速获得分数更多
    ");
     22     SetPos(35, 25);
     23     system("pause");
     24     system("cls");
     25 }
     26 
     27 void CreateMap()
     28 {
     29     int i = 0;
     30     //
     31     for (i = 0; i <= 58; i += 2)
     32     {
     33         SetPos(i, 0);
     34         printf(WALL);
     35     }
     36     //
     37     for (i = 0; i <= 58; i += 2)
     38     {
     39         SetPos(i, 27);
     40         printf(WALL);
     41     }
     42     //
     43     for (i = 1; i <= 26; i++)
     44     {
     45         SetPos(0, i);
     46         printf(WALL);
     47     }
     48     //
     49     for (i = 1; i <= 26; i++)
     50     {
     51         SetPos(58, i);
     52         printf(WALL);
     53     }
     54 }
     55 pSnakeNode BuyNode()
     56 {
     57     pSnakeNode pRet = (pSnakeNode)malloc(sizeof(SnakeNode));
     58     if (pRet == NULL)
     59     {
     60         perror("BuyNode::malloc()");
     61         exit(EXIT_FAILURE);
     62     }
     63     pRet->x = 0;
     64     pRet->y = 0;
     65     pRet->next = NULL;
     66     return pRet;
     67 }
     68 void InitSnake(pSnake ps)
     69 {
     70     pSnakeNode first = BuyNode();//创建蛇头
     71     pSnakeNode cur = NULL;
     72     first->x = INIT_X;
     73     first->y = INIT_Y;
     74     int i = 0;
     75     for (i = 1; i <= 4; i++)
     76     {
     77         cur = BuyNode();//创建蛇身
     78         cur->x = first->x + 2;
     79         cur->y = first->y;
     80         cur->next = first;
     81         first = cur;
     82     }
     83     //打印蛇
     84     while (cur)
     85     {
     86         SetPos(cur->x, cur->y);
     87         printf(FOOD);
     88         cur = cur->next;
     89     }
     90     ps->_psnake = first;
     91 }
     92 
     93 void CreateFood(pSnake ps)
     94 {
     95     pSnakeNode pfood = BuyNode();
     96     pSnakeNode cur = ps->_psnake;
     97     pfood->y = rand() % 26 + 1;
     98     do
     99     {
    100         pfood->x = rand() % 55 + 2;//0-54,+2产生2-56
    101     } while (pfood->x % 2 != 0);
    102     while (cur)
    103     {
    104         if (cur->x == pfood->x&&cur->y == pfood->y)
    105         {
    106             CreateFood(ps);
    107         }
    108         cur = cur->next;
    109     }
    110     ps->_pFood = pfood;
    111     SetPos(pfood->x, pfood->y);
    112     printf(FOOD);
    113 }
    114 
    115 void GameStart(pSnake ps)
    116 {
    117     //打印欢迎界面
    118     WelcomeToGame();
    119     //创建地图,画墙
    120     CreateMap();
    121     //初始化蛇
    122     InitSnake(ps);
    123     //初始化食物
    124     CreateFood(ps);
    125     //游戏运行
    126     ps->_AddScore = 10;//每次增加的分数
    127     ps->_TotalScore = 0;//总分
    128     ps->_Dir = RIGHT;//方向
    129     ps->_SleepTime = 200;//0.2秒
    130     ps->_Status = OK;//状态
    131 }
    132 
    133 void pause()//暂停函数
    134 {
    135     while (1)
    136     {
    137         Sleep(100);
    138         if (GetAsyncKeyState(VK_SPACE))
    139         {
    140             return;
    141         }
    142     }
    143 }
    144 
    145 int NextHasFood(pSnakeNode pn, pSnakeNode pf)
    146 {
    147     return (pn->x == pf->x) && (pn->y == pf->y);
    148 }
    149 
    150 void EatFood(pSnake ps, pSnakeNode pn)//吃食物
    151 {
    152     pSnakeNode cur = NULL;
    153     pn->next = ps->_psnake;//头插
    154     ps->_psnake = pn;
    155     cur = ps->_psnake;
    156     ps->_TotalScore += ps->_AddScore;
    157     while (cur)
    158     {
    159         SetPos(cur->x, cur->y);
    160         printf(FOOD);
    161         cur = cur->next;
    162     }
    163     CreateFood(ps);
    164 }
    165 
    166 void NoFood(pSnake ps, pSnakeNode pn)//没有食物
    167 {
    168     pSnakeNode cur = NULL;
    169     pn->next = ps->_psnake;//头插
    170     ps->_psnake = pn;
    171     cur = ps->_psnake;
    172     while (cur->next->next)
    173     {
    174         SetPos(cur->x, cur->y);
    175         printf(FOOD);
    176         cur = cur->next;
    177     }
    178     SetPos(cur->x, cur->y);
    179     printf(FOOD);
    180     SetPos(cur->next->x, cur->next->y);
    181     printf(" ");
    182     free(cur->next);
    183     cur->next = NULL;
    184 }
    185 
    186 void snakmove(pSnake ps)//蛇的移动
    187 {
    188     pSnakeNode pNextNode = BuyNode();
    189     SetPos(65, 8);
    190     printf("总分:%d", ps->_TotalScore);
    191     SetPos(65, 9);
    192     printf("每个食物的得分:%d ", ps->_AddScore);
    193     //
    194     switch (ps->_Dir)
    195     {
    196         case UP:
    197         {
    198             pNextNode->x = ps->_psnake->x;
    199             pNextNode->y = ps->_psnake->y - 1;
    200             if (NextHasFood(pNextNode,ps->_pFood))
    201             {
    202                 //下一个节点是食物
    203                 EatFood(ps,pNextNode);
    204             }
    205             else
    206             {
    207                 NoFood(ps,pNextNode);
    208             }
    209             break;
    210         }
    211         case DOWN:
    212         {
    213             pNextNode->x = ps->_psnake->x;
    214             pNextNode->y = ps->_psnake->y + 1;
    215             if (NextHasFood(pNextNode, ps->_pFood))
    216             {
    217               //下一个节点是食物
    218                   EatFood(ps, pNextNode);
    219               }
    220             else
    221             {
    222                   NoFood(ps, pNextNode);
    223             }
    224             break;
    225         }
    226         case LEFT:
    227         {
    228             pNextNode->x = ps->_psnake->x-2;
    229             pNextNode->y = ps->_psnake->y;
    230             if (NextHasFood(pNextNode, ps->_pFood))
    231             {
    232                 //下一个节点是食物
    233                 EatFood(ps, pNextNode);
    234             }
    235             else
    236             {
    237                 NoFood(ps, pNextNode);
    238             }
    239             break;
    240         }
    241         case RIGHT:
    242         {
    243             pNextNode->x = ps->_psnake->x+2;
    244             pNextNode->y = ps->_psnake->y ;
    245             if (NextHasFood(pNextNode, ps->_pFood))
    246             {
    247                  //下一个节点是食物
    248                 EatFood(ps, pNextNode);
    249             }
    250             else
    251             {
    252                 NoFood(ps, pNextNode);
    253             }
    254             break;
    255         }
    256         default:
    257         {
    258             break;
    259         }
    260     }
    261 }
    262 
    263 void KillBYWALL(pSnake ps)
    264 {
    265     if ((ps->_psnake->x == 0) ||
    266         (ps->_psnake->x == 58) || 
    267         (ps->_psnake->y == 0) ||
    268         (ps->_psnake->y == 27))
    269     {
    270         ps->_Status = KILL_BY_WALL;
    271     }
    272 }
    273 
    274 void KillBySelf(pSnake ps)
    275 {
    276     pSnakeNode tnext = ps->_psnake->next;
    277     while (tnext)
    278     {
    279         if ((tnext->x == ps->_psnake->x) && (tnext->y == ps->_psnake->y))
    280         {
    281             ps->_Status = KILL_BY_SELF;
    282             return;
    283         }
    284         tnext = tnext->next;
    285     }
    286 
    287 }
    288 void PrintHelpInfo()
    289 {
    290     SetPos(65, 11);
    291     printf("用↑,↓,←,→来控制蛇的移动");
    292     SetPos(65, 12);
    293     printf("F1为加速,F2为减速
    ");
    294     SetPos(65, 13);
    295     printf("加速获得分数更多
    ");
    296     SetPos(65, 14);
    297     printf("按空格暂停游戏
    ");
    298 
    299 }
    300 
    301 void GameEnd(pSnake ps)
    302 {
    303     pSnakeNode cur = ps->_psnake;
    304     SetPos(25, 14);
    305     if (ps->_Status == NORMAL_END)
    306     {
    307         SetPos(70, 20);
    308         printf("游戏正常接结束
    ");
    309         SetPos(70, 21);
    310     }
    311     else if (ps->_Status == KILL_BY_SELF)
    312     {
    313         SetPos(70, 20);
    314         printf("蛇撞到自己了
    ");
    315         SetPos(70, 21);
    316     }
    317     else if (ps->_Status == KILL_BY_WALL)
    318     {
    319         SetPos(70, 20);
    320         printf("撞到墙了
    ");
    321         SetPos(70, 21);
    322     }
    323     while (cur)
    324     {
    325         pSnakeNode del = cur;
    326         cur = cur->next;
    327         free(del);
    328         del = NULL;
    329     }
    330     ps->_psnake = NULL;
    331     free(ps->_pFood);
    332     ps->_pFood = NULL;
    333 }
    334 
    335 void GameRun(pSnake ps)
    336 {
    337     PrintHelpInfo();
    338     do
    339     {
    340         //确定方向
    341         if (GetAsyncKeyState(VK_UP)&&(ps->_Dir!=DOWN))
    342         {
    343             ps->_Dir = UP;
    344         }
    345         else if (GetAsyncKeyState(VK_DOWN) && ps->_Dir != UP)
    346         {
    347             ps->_Dir = DOWN;
    348         }
    349         else if (GetAsyncKeyState(VK_LEFT) && ps->_Dir != RIGHT)
    350         {
    351             ps->_Dir = LEFT;
    352         }
    353         else if (GetAsyncKeyState(VK_RIGHT) && ps->_Dir != LEFT)
    354         {
    355             ps->_Dir = RIGHT;
    356         }
    357         else if (GetAsyncKeyState(VK_SPACE))
    358         {
    359             //暂停游戏
    360             pause();
    361         }
    362         else if (GetAsyncKeyState(VK_ESCAPE))
    363         {
    364             //结束游戏
    365             ps->_Status = NORMAL_END;
    366             break;
    367         }
    368         else if (GetAsyncKeyState(VK_F1))
    369         {
    370             //加速
    371             if (ps->_SleepTime >= 40)
    372             {
    373                 ps->_SleepTime -= 20;
    374                 ps->_AddScore += 2;
    375             }
    376         }
    377         else if (GetAsyncKeyState(VK_F2))
    378         {
    379             //减速
    380             if (ps->_SleepTime <= 300)
    381             {
    382                 ps->_SleepTime += 20;
    383                 ps->_AddScore -= 2;
    384             }
    385             if (ps->_SleepTime > 300)
    386             {
    387                 ps->_AddScore = 1;//不能一直减
    388             }
    389         }
    390         Sleep(ps->_SleepTime);//睡眠
    391         //蛇的移动
    392         snakmove(ps);
    393         KillBYWALL(ps);
    394         KillBySelf(ps);
    395     } while (ps->_Status == OK);
    396 }

    test.c:

     1 #include"snake.h"
     2 
     3 void test()
     4 {
     5     srand((unsigned)time(NULL));
     6     Snake snake = { 0 };//创建贪吃蛇
     7     GameStart(&snake);
     8     GameRun(&snake);
     9     GameEnd(&snake);
    10 }
    11 
    12 int main()
    13 {
    14     test();
    15     system("pause");
    16     return 0;
    17 }
  • 相关阅读:
    spring属性注入
    spring的bean标签属性
    spring三种实例化bean的方式
    测试环境部署
    sql server将字符串转换为 uniqueidentifier 时失败
    mybatis parametertype 多个参数
    ORACLE-023:令人烦恼的 ora-01722 无效数字
    PostMan使用教程
    sqlserver复制表数据到另一个表
    to_number()函数的用法
  • 原文地址:https://www.cnblogs.com/love-you1314/p/9695764.html
Copyright © 2020-2023  润新知