zoukankan      html  css  js  c++  java
  • 贪吃蛇游戏(printf输出C语言版本)

    这一次我们应用printf输出实现一个经典的小游戏—贪吃蛇,主要难点是小蛇数据如何存储、如何实现转弯的效果、吃到食物后如何增加长度

    1 构造小蛇

    首先,在画面中显示一条静止的小蛇。二维数组canvas[High][Width]的对应元素,值为0输出空格,-1输出边框#,1输出蛇头@,大于1的正数输出蛇身*。startup()函数中初始化蛇头在画布中间位置(canvas[High/2][Width/2] = 1;),蛇头向左依次生成4个蛇身(for (i=1;i<=4;i++) canvas[High/2][Width/2-i] = i+1;),元素值分别为2、3、4、5。

     

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <conio.h>
     4 #include <windows.h>
     5           //C语言自学网
     6 #define High 20  // 游戏画面尺寸
     7 #define Width 30
     8 
     9 // 全局变量
    10 int canvas[High][Width] = {0}; // 二维数组存储游戏画布中对应的元素
    11 // 0为空格,-1为边框#,1为蛇头@,大于1的正数为蛇身*
    12 
    13 void gotoxy(int x,int y)  //光标移动到(x,y)位置
    14 {
    15     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    16     COORD pos;
    17     pos.X = x;
    18     pos.Y = y;
    19     SetConsoleCursorPosition(handle,pos);
    20 }
    21 
    22 void startup() // 数据初始化
    23 {
    24     int i,j;
    25     
    26     // 初始化边框
    27     for (i=0;i<High;i++)
    28     {
    29         canvas[i][0] = -1;
    30         canvas[i][Width-1] = -1;
    31     }
    32     for (j=0;j<Width;j++)
    33     {
    34         canvas[0][j] = -1;
    35         canvas[High-1][j] = -1;
    36     }
    37     
    38     // 初始化蛇头位置
    39     canvas[High/2][Width/2] = 1;
    40     // 初始化蛇身,画布中元素值分别为2,3,4,5....
    41     for (i=1;i<=4;i++)
    42         canvas[High/2][Width/2-i] = i+1;
    43 }
    44 
    45 void show()  // 显示画面
    46 {
    47     gotoxy(0,0);  // 光标移动到原点位置,以下重画清屏
    48     int i,j;
    49     for (i=0;i<High;i++)
    50     {
    51         for (j=0;j<Width;j++)
    52         {
    53             if (canvas[i][j]==0)
    54                 printf(" ");   //   输出空格
    55             else if (canvas[i][j]==-1)
    56                 printf("#");   //   输出边框#
    57             else if (canvas[i][j]==1)
    58                 printf("@");   //   输出蛇头@
    59             else if (canvas[i][j]>1)
    60                 printf("*");   //   输出蛇身*
    61         }
    62         printf("
    ");
    63     }
    64 }    
    65 
    66 void updateWithoutInput()  // 与用户输入无关的更新
    67 {
    68 }
    69 
    70 void updateWithInput()  // 与用户输入有关的更新
    71 {
    72 }
    73 
    74 int main()
    75 {
    76     startup();  // 数据初始化    
    77     while (1) //  游戏循环执行
    78     {
    79         show();  // 显示画面
    80         updateWithoutInput();  // 与用户输入无关的更新
    81         updateWithInput();  // 与用户输入有关的更新
    82     }
    83     return 0;
    84 }

    2 小蛇自动移动

    实现小蛇的移动是贪吃蛇游戏的难点,下图列出了小蛇分别向右、向上运动后,对应二维数组元素值的变化,从中我们可以得出实现思路。

     

    假设小蛇元素为54321,其中1为蛇头、5432为蛇身、最大值5为蛇尾。首先将所有大于0的元素加1,得到65432;将最大值6变为0,即去除了原来的蛇尾;再根据对应的移动方向,将2对应方向的元素由0变成1;如此即实现了小蛇的移动。小蛇向上移动的对应流程如图所示。

     

    定义变量int moveDirection表示小蛇的移动方向,值1、2、3、4分别表示小蛇向上、下、左、右方向移动,小蛇移动实现在moveSnakeByDirection()函数中。

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <conio.h>
      4 #include <windows.h>
      5 //C语言自学网
      6 #define High 20  // 游戏画面尺寸
      7 #define Width 30
      8 
      9 // 全局变量
     10 int moveDirection; // 小蛇移动方向,上下左右分别用1,2,3,4表示
     11 int canvas[High][Width] = {0}; // 二维数组存储游戏画布中对应的元素
     12             // 0为空格0,-1为边框#,1为蛇头@,大于1的正数为蛇身*
     13 
     14 void gotoxy(int x,int y)  //光标移动到(x,y)位置
     15 {
     16     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
     17     COORD pos;
     18     pos.X = x;
     19     pos.Y = y;
     20     SetConsoleCursorPosition(handle,pos);
     21 }
     22 
     23 // 移动小蛇
     24 // 第一步扫描数组canvas所有元素,找到正数元素都+1
     25 // 找到最大元素(即蛇尾巴),把其变为0
     26 // 找到=2的元素(即蛇头),再根据输出的上下左右方向,把对应的另一个像素值设为1(新蛇头)
     27 void moveSnakeByDirection()
     28 {
     29     int i,j;
     30     for (i=1;i<High-1;i++)
     31         for (j=1;j<Width-1;j++)
     32             if (canvas[i][j]>0)
     33                 canvas[i][j]++;
     34 
     35     int oldTail_i,oldTail_j,oldHead_i,oldHead_j;
     36     int max = 0;
     37 
     38     for (i=1;i<High-1;i++)
     39         for (j=1;j<Width-1;j++)
     40             if (canvas[i][j]>0)
     41             {
     42                 if (max<canvas[i][j])
     43                 {
     44                     max = canvas[i][j];
     45                     oldTail_i = i;
     46                     oldTail_j = j;
     47                 }
     48                 if (canvas[i][j]==2)
     49                 {
     50                     oldHead_i = i;
     51                     oldHead_j = j;
     52                 }
     53             }
     54 
     55     canvas[oldTail_i][oldTail_j] = 0;
     56 
     57     if (moveDirection==1) // 向上移动
     58         canvas[oldHead_i-1][oldHead_j] = 1;
     59     if (moveDirection==2) // 向下移动
     60         canvas[oldHead_i+1][oldHead_j] = 1;
     61     if (moveDirection==3) // 向左移动
     62         canvas[oldHead_i][oldHead_j-1] = 1;
     63     if (moveDirection==4) // 向右移动
     64         canvas[oldHead_i][oldHead_j+1] = 1;
     65 }
     66 
     67 void startup() // 数据初始化
     68 {
     69     int i,j;
     70     
     71     // 初始化边框
     72     for (i=0;i<High;i++)
     73     {
     74         canvas[i][0] = -1;
     75         canvas[i][Width-1] = -1;
     76     }
     77     for (j=0;j<Width;j++)
     78     {
     79         canvas[0][j] = -1;
     80         canvas[High-1][j] = -1;
     81     }
     82     
     83     // 初始化蛇头位置
     84     canvas[High/2][Width/2] = 1;
     85     // 初始化蛇身,画布中元素值分别为2,3,4,5....
     86     for (i=1;i<=4;i++)
     87         canvas[High/2][Width/2-i] = i+1;
     88     
     89     // 初始小蛇向右移动
     90     moveDirection = 4;    
     91 }
     92 
     93 void show()  // 显示画面
     94 {
     95     gotoxy(0,0);  // 光标移动到原点位置,以下重画清屏
     96     int i,j;
     97     for (i=0;i<High;i++)
     98     {
     99         for (j=0;j<Width;j++)
    100         {
    101             if (canvas[i][j]==0)
    102                 printf(" ");   //   输出空格
    103             else if (canvas[i][j]==-1)
    104                 printf("#");   //   输出边框#
    105             else if (canvas[i][j]==1)
    106                 printf("@");   //   输出蛇头@
    107             else if (canvas[i][j]>1)
    108                 printf("*");   //   输出蛇身*
    109         }
    110         printf("
    ");
    111     }
    112     Sleep(100);
    113 }    
    114 
    115 void updateWithoutInput()  // 与用户输入无关的更新
    116 {
    117     moveSnakeByDirection();
    118 }
    119 
    120 void updateWithInput()  // 与用户输入有关的更新
    121 {
    122 }
    123 
    124 int main()
    125 {
    126     startup();  // 数据初始化    
    127     while (1) //  游戏循环执行
    128     {
    129         show();  // 显示画面
    130         updateWithoutInput();  // 与用户输入无关的更新
    131         updateWithInput();  // 与用户输入有关的更新
    132     }
    133     return 0;
    134 }

    3 玩家控制小蛇移动

    这一步的实现比较简单,在updateWithInput()函数中按asdw键改变moveDirection的值,然后调用moveSnakeByDirection()实现小蛇向不同方向的移动,如图所示。

     

     1 void updateWithInput()  // 与用户输入有关的更新
     2     //C语言自学网
     3 {
     4     char input;
     5     if(kbhit())  // 判断是否有输入
     6     {
     7         input = getch();  // 根据用户的不同输入来移动,不必输入回车
     8         if (input == 'a') 
     9         {
    10             moveDirection = 3;   // 位置左移
    11             moveSnakeByDirection();
    12         }
    13         else if (input == 'd')
    14         {
    15             moveDirection = 4;  // 位置右移
    16             moveSnakeByDirection();
    17         }
    18         else if (input == 'w')
    19         {
    20             moveDirection = 1;  // 位置上移
    21             moveSnakeByDirection();
    22         }
    23         else if (input == 's')
    24         {
    25             moveDirection = 2;   // 位置下移
    26             moveSnakeByDirection();
    27         }
    28     }
    29 }

    4 判断游戏失败

    当小蛇和边框或自身发生碰撞时,游戏失败,如图所示。

     1 void moveSnakeByDirection()
     2 //C语言自学网
     3 {
     4     int i,j;
     5     for (i=1;i<High-1;i++)
     6         for (j=1;j<Width-1;j++)
     7             if (canvas[i][j]>0)
     8                 canvas[i][j]++;
     9     int oldTail_i,oldTail_j,oldHead_i,oldHead_j;
    10     int max = 0;
    11     for (i=1;i<High-1;i++)
    12         for (j=1;j<Width-1;j++)
    13             if (canvas[i][j]>0)
    14             {
    15                 if (max<canvas[i][j])
    16                 {
    17                     max = canvas[i][j];
    18                     oldTail_i = i;
    19                     oldTail_j = j;
    20                 }
    21                 if (canvas[i][j]==2)
    22                 {
    23                     oldHead_i = i;
    24                     oldHead_j = j;
    25                 }
    26             }
    27     canvas[oldTail_i][oldTail_j] = 0;
    28     int newHead_i,newHead_j;
    29     if (moveDirection==1) // 向上移动
    30     {
    31         newHead_i = oldHead_i-1;
    32         newHead_j = oldHead_j;
    33     }
    34     if (moveDirection==2) // 向下移动
    35     {
    36         newHead_i = oldHead_i+1;
    37         newHead_j = oldHead_j;
    38     }
    39     if (moveDirection==3) // 向左移动
    40     {
    41         newHead_i = oldHead_i;
    42         newHead_j = oldHead_j-1;
    43     }
    44     if (moveDirection==4) // 向右移动
    45     {
    46         newHead_i = oldHead_i;
    47         newHead_j = oldHead_j+1;
    48     }
    49 
    50     // 是否小蛇和自身撞,或者和边框撞,游戏失败
    51     if (canvas[newHead_i][newHead_j]>0 || canvas[newHead_i][newHead_j]==-1)
    52     {
    53         printf("游戏失败!
    ");
    54         exit(0);
    55     }
    56     else
    57         canvas[newHead_i][newHead_j] = 1;
    58 }

    5 吃食物增加长度

    增加食物,二维数组canvas[High][Width]元素值为-2时,输出食物数值’F’,如图所示。当蛇头碰到食物时,长度加一。

     

    实现思路和2中小蛇移动类似,只需保持原蛇尾,不将最大值变为0即可,下图为小蛇向上移动吃到食物的对应流程。

     

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <conio.h>
      4 #include <windows.h>
      5 //C语言自学网
      6 #define High 20  // 游戏画面尺寸
      7 #define Width 30
      8 
      9 // 全局变量
     10 int moveDirection; // 小蛇移动位置,上下左右分别用1,2,3,4表示
     11 int food_x,food_y; // 食物的位置
     12 int canvas[High][Width] = {0}; // 二维数组存储游戏画布中对应的元素
     13     // 0为空格0,-1为边框#,-2为食物F,1为蛇头@,大于1的正数为蛇身*
     14 
     15 void gotoxy(int x,int y)  //光标移动到(x,y)位置
     16 {
     17     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
     18     COORD pos;
     19     pos.X = x;
     20     pos.Y = y;
     21     SetConsoleCursorPosition(handle,pos);
     22 }
     23 
     24 // 移动小蛇
     25 // 第一步扫描数组canvas所有元素,找到正数元素都+1
     26 // 找到最大元素(即蛇尾巴),把其变为0
     27 // 找到=2的元素(即蛇头),再根据输出的上下左右方向,把对应的另一个像素值设为1(新蛇头)
     28 void moveSnakeByDirection()
     29 {
     30     int i,j;
     31     for (i=1;i<High-1;i++)
     32         for (j=1;j<Width-1;j++)
     33             if (canvas[i][j]>0)
     34                 canvas[i][j]++;
     35 
     36     int oldTail_i,oldTail_j,oldHead_i,oldHead_j;
     37     int max = 0;
     38 
     39     for (i=1;i<High-1;i++)
     40         for (j=1;j<Width-1;j++)
     41             if (canvas[i][j]>0)
     42             {
     43                 if (max<canvas[i][j])
     44                 {
     45                     max = canvas[i][j];
     46                     oldTail_i = i;
     47                     oldTail_j = j;
     48                 }
     49                 if (canvas[i][j]==2)
     50                 {
     51                     oldHead_i = i;
     52                     oldHead_j = j;
     53                 }
     54             }
     55 
     56     int newHead_i,newHead_j;
     57 
     58     if (moveDirection==1) // 向上移动
     59     {
     60         newHead_i = oldHead_i-1;
     61         newHead_j = oldHead_j;
     62     }
     63     if (moveDirection==2) // 向下移动
     64     {
     65         newHead_i = oldHead_i+1;
     66         newHead_j = oldHead_j;
     67     }
     68     if (moveDirection==3) // 向左移动
     69     {
     70         newHead_i = oldHead_i;
     71         newHead_j = oldHead_j-1;
     72     }
     73     if (moveDirection==4) // 向右移动
     74     {
     75         newHead_i = oldHead_i;
     76         newHead_j = oldHead_j+1;
     77     }
     78 
     79     // 新蛇头如果吃到食物
     80     if (canvas[newHead_i][newHead_j]==-2)
     81     {
     82         canvas[food_x][food_y] = 0;
     83         // 产生一个新的食物
     84         food_x = rand()%(High-5) + 2;
     85         food_y = rand()%(Width-5) + 2;
     86         canvas[food_x][food_y] = -2;
     87 
     88         // 原来的旧蛇尾留着,长度自动+1
     89     }
     90     else // 否则,原来的旧蛇尾减掉,保持长度不变
     91         canvas[oldTail_i][oldTail_j] = 0;
     92 
     93     // 是否小蛇和自身撞,或者和边框撞,游戏失败
     94     if (canvas[newHead_i][newHead_j]>0 || canvas[newHead_i][newHead_j]==-1)
     95     {
     96         printf("游戏失败!
    ");
     97         Sleep(2000);
     98         system("pause");
     99         exit(0);
    100     }
    101     else
    102         canvas[newHead_i][newHead_j] = 1;
    103 }
    104 
    105 void startup() // 数据初始化
    106 {
    107     int i,j;
    108     
    109     // 初始化边框
    110     for (i=0;i<High;i++)
    111     {
    112         canvas[i][0] = -1;
    113         canvas[i][Width-1] = -1;
    114     }
    115     for (j=0;j<Width;j++)
    116     {
    117         canvas[0][j] = -1;
    118         canvas[High-1][j] = -1;
    119     }
    120     
    121     // 初始化蛇头位置
    122     canvas[High/2][Width/2] = 1;
    123     // 初始化蛇身,画布中元素值分别为2,3,4,5....
    124     for (i=1;i<=4;i++)
    125         canvas[High/2][Width/2-i] = i+1;
    126 
    127     // 初始小蛇向右移动
    128     moveDirection = 4;
    129     
    130     food_x = rand()%(High-5) + 2;
    131     food_y = rand()%(Width-5) + 2;
    132     canvas[food_x][food_y] = -2;
    133 }
    134 
    135 void show()  // 显示画面
    136 {
    137     gotoxy(0,0);  // 光标移动到原点位置,以下重画清屏
    138     int i,j;
    139     for (i=0;i<High;i++)
    140     {
    141         for (j=0;j<Width;j++)
    142         {
    143             if (canvas[i][j]==0)
    144                 printf(" ");   //   输出空格
    145             else if (canvas[i][j]==-1)
    146                 printf("#");   //   输出边框#
    147             else if (canvas[i][j]==1)
    148                 printf("@");   //   输出蛇头@
    149             else if (canvas[i][j]>1)
    150                 printf("*");   //   输出蛇身*
    151             else if (canvas[i][j]==-2)
    152                 printf("F");   //   输出食物F
    153         }
    154         printf("
    ");
    155     }
    156     Sleep(100);
    157 }    
    158 
    159 void updateWithoutInput()  // 与用户输入无关的更新
    160 {
    161     moveSnakeByDirection();
    162 }
    163 
    164 void updateWithInput()  // 与用户输入有关的更新
    165 {
    166     char input;
    167     if(kbhit())  // 判断是否有输入
    168     {
    169         input = getch();  // 根据用户的不同输入来移动,不必输入回车
    170         if (input == 'a') 
    171         {
    172             moveDirection = 3;   // 位置左移
    173             moveSnakeByDirection();
    174         }
    175         else if (input == 'd')
    176         {
    177             moveDirection = 4;  // 位置右移
    178             moveSnakeByDirection();
    179         }
    180         else if (input == 'w')
    181         {
    182             moveDirection = 1;  // 位置上移
    183             moveSnakeByDirection();
    184         }
    185         else if (input == 's')
    186         {
    187             moveDirection = 2;   // 位置下移
    188             moveSnakeByDirection();
    189         }
    190     }
    191 }
    192 
    193 int main()
    194 {
    195     startup();  // 数据初始化    
    196     while (1) //  游戏循环执行
    197     {
    198         show();  // 显示画面
    199         updateWithoutInput();  // 与用户输入无关的更新
    200         updateWithInput();  // 与用户输入有关的更新
    201     }
    202     return 0;
    203 }

    6 思考题

    1. 增加道具,吃完可以加命或减速;

    2. 尝试实现双人版贪吃蛇


    感谢你的阅读,请用心感悟!希望可以帮到爱学习的你!!分享也是一种快乐!!!请接力。。。

  • 相关阅读:
    list转datatable,SqlBulkCopy将DataTable中的数据批量插入数据库
    Html.BeginForm 与Section、Partial View 和 Child Action
    e.stopPropagation();与 e.preventDefault();
    NPOI导出
    Excel导入导出(篇二)
    Excel导入导出,通过datatable转存(篇一)
    ajax请求加载Loading或错误提示
    jQuery UI dialog
    Zebra_Dialog 弹出层插件
    Google浏览器导出书签
  • 原文地址:https://www.cnblogs.com/kangyifan/p/13149831.html
Copyright © 2011-2022 走看看