C - 简易贪吃蛇的编写

Posted x≒y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C - 简易贪吃蛇的编写相关的知识,希望对你有一定的参考价值。

  不多废话,直接进入正题——用C编写简易贪吃蛇。附上拙劣的源码 * c-snake *

 

  首先说明使画面动起来的原理:通过 system("cls"); 清除当前控制台的显示,再printf下一步画面进行显示,以此循环形成动画效果(类似手翻书)。因为这是在控制台,难免会有晃眼的感觉,并且不存在美工一说,所以就将就下吧。

  有了使画面动起来的方法,接下来就是贪吃蛇游戏本体的制作思路了,可将游戏本体分解为以下3个部分:

1、边界,即墙:圈定一个范围,蛇只能在墙内移动,食物只能生成在墙内

2、蛇:游戏主角,可视为2部分组成——蛇头和蛇身。蛇头引导了蛇身前行的方向,也用于判定蛇是否吃到食物

3、食物:蛇的猎物,被蛇吃掉后会触发2个事件——蛇身加长、重新生成一个食物

  将本体分解完后,就是解析游戏方式:蛇会自动向蛇头朝向进行移动,玩家需要控制蛇头的方向进行移动,抛却理论不说(理论上可以将蛇身占满整个边界内部),游戏结束的情况有2种:撞墙和撞身

 

  用人话将贪吃蛇游戏理了一遍,接下来就是将人话变成真正的设计思路:

1、边界的描述:可看作一个二维数组,四周为墙,用“*”表示;内部为空,用“ ”表示

2、蛇的描述:由蛇头和蛇身组成,而蛇头可看作蛇身的特殊部分,因此实际并无蛇头一说,仅仅是表示方式不同罢了(蛇头用“@”表示,蛇身用“#”表示),从而将蛇头和蛇身的描述问题转为了蛇身的描述。而蛇身应当如何描述?蛇身由一个又一个的、连续的点组成,因此,该问题实质便是如何去描述一个点。在二维坐标中,点便是用x和y描述,所以蛇的每个蛇身(点)都需要储存x和y这2个”标识符”,同时又需要储存多个xy对,显而易见,依旧是用一个二维数组去描述蛇

3、食物的描述:食物本质上依旧是一个点,但和蛇身不同,食物有且仅有1个,所以用一个一维数组即可描述食物

4、蛇的移动:什么是移动?移动即为位置的改变,所以在确定了方向后,我们要做的仅仅是将蛇头向该方向移动后,后面的蛇身依次覆盖前一个蛇身/头,即拷贝前一个蛇身所储存的xy坐标。当吃到食物时,应当将长度+1

5、蛇的移动方向控制:那么如何控制蛇头所指向的方向呢?虽然方向是蛇头的属性之一,但可将其从蛇中分离出去,定义一个单独的变量去描述方向。当有键盘敲击输入事件发生时,获取输入值并判断输入值与方向的关系,更新方向即可

6、食物的消失与生成:当蛇头与食物的坐标相同时,食物应当消失(被吃),消失后应当生成一个新的食物,而生成食物的x和y应为随机数,且需在墙内,不能生成在蛇上

7、游戏的结束:判断蛇头的位置即可(撞墙:当蛇头的位置处于墙上时;撞身:当蛇头的位置处于蛇身上时)

  

  有了思路,代码其实就自然而然的写出来了:

    定义部分:

技术分享
 1 /*
 2     若内部场地大小为x*y:
 3     墙定义为char wall[y+2][x+2],+2是因为2边的边界
 4     蛇定义为int snake[x*y][3],snake[i][0]表示x坐标,snake[i][1]表示y坐标,snake[i][2]表示该蛇身是否存在。当然亦可定义为snake[x*y][2],初始化为0,判断x和y值是否为0去确定该蛇身是否存在
 5     食物定义为int food[3],food[0]表示x坐标,food[1]表示y坐标,food[2]表示食物是否已经存在
 6     移动的方向定义为int direction,1/2/3/4分别对应4个方向
 7 */
 8 
 9 char wall[22][42];
10 int snake[800][3];
11 int food[3];
12 int direction = 2;    //方向:1-上 2-右 3-下 4-左
define

 

    功能模块部分:

技术分享
 1 //初始化围墙属性
 2 void init_wall()
 3 {
 4     extern char wall[22][42];
 5     int i,j;
 6     for(i = 0; i < 22; i++)
 7     {
 8         for(j = 0; j < 42; j++)
 9         {
10             if(i == 0 || i == 21)
11                 wall[i][j] = *;
12             else if(j == 0 || j == 41)
13                 wall[i][j] = *;
14             else
15                 wall[i][j] =  ;
16         }
17     }
18 }
init_wall
技术分享
 1 //初始化蛇属性
 2 void init_snake()
 3 {
 4     /*    
 5         snake[i][0]为x坐标
 6         snake[i][1]为y坐标
 7         snake[i][2]值为1或0 1表示存在 0表示不存在
 8     */
 9     extern int snake[800][3];
10     snake[0][0] = 11;
11     snake[0][1] = 11;
12     snake[0][2] = 1;
13     snake[1][0] = 10;
14     snake[1][1] = 11;
15     snake[1][2] = 1;
16     snake[2][0] = 9;
17     snake[2][1] = 11;
18     snake[2][2] = 1;
19 }
init_snake
技术分享
 1 //初始化食物属性
 2 void init_food()
 3 {
 4     /*
 5         food[0]为x坐标
 6         food[1]为y坐标
 7         food[2]值为1或0 1表示不存在 0表示存在
 8     */
 9     extern int food[3];
10     extern int snake[800][3];
11     
12     int x,y;
13     int flag = 1;    //是否在蛇身的标志 1表示在 0表示不在
14     food[2] = 0;    //生成食物 置0
15     
16     while(flag)
17     {
18         srand(time(0));
19         x = rand()%40+1;
20         y = rand()%20+1;
21         int i;
22         for(i = 0; i < 800; i++)
23         {
24             if(snake[i][2])
25             {
26                 if(snake[i][0] == x && snake[i][1] == y)
27                     break;
28             }
29             else
30                 flag = 0;
31         }
32     }
33     food[0] = x;
34     food[1] = y;
35 }
init_food
技术分享
 1 //在墙中生成蛇和食物
 2 void change()
 3 {
 4     extern char wall[22][42];
 5     extern int snake[800][3];
 6     extern int food[3];
 7     int i;
 8     
 9     if(food[2])
10     {
11         init_food();
12     }
13     
14     wall[food[1]][food[0]] = O;    //食物
15     
16     for(i = 0; i < 800; i++)
17     {
18         if(snake[i][2])
19         {
20             int x = snake[i][0];
21             int y = snake[i][1];
22             if(i == 0)
23                 wall[y][x] = @;    //蛇头
24             else
25                 wall[y][x] = #;    //蛇身
26         }
27     }
28 }
change
技术分享
 1 //判断是否吃到食物
 2 int ifEat()
 3 {
 4     extern int snake[800][3];
 5     extern int food[3];
 6     extern int score;
 7     
 8     if(snake[0][0] == food[0] && snake[0][1] == food[1])
 9     {
10         food[2] = 1;
11         return 1;    //吃到返回1
12     }
13     return 0;        //没吃到返回0
14 }
ifEat
技术分享
 1 //判断是否撞墙或自身
 2 int ifBreak()
 3 {
 4     extern int snake[800][3];
 5     int i;
 6     
 7     if(snake[0][0] == 0 || snake[0][0] == 41 || snake[0][1] == 0 || snake[0][1] == 21)
 8         return 1;
 9     for(i = 1; i < 800; i++)
10     {
11         if(snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1])
12             return 1;
13     }
14     return 0;
15 }
ifBreak
技术分享
 1 //获取输入的方向
 2 void getKey()
 3 {
 4     char ch;
 5     if(_kbhit())
 6     {
 7         ch = _getch();
 8     }
 9     switch(ch)
10     {
11         case w:
12         case W:
13             if(direction != 3)
14                 direction = 1;
15             break;
16         case d:
17         case D:
18             if(direction != 4)
19                 direction = 2;
20             break;
21         case s:
22         case S:
23             if(direction != 1)
24                 direction = 3;
25             break;
26         case a:
27         case A:
28             if(direction != 2)
29                 direction = 4;
30             break;
31         default:
32             break;
33     }
34 }
getKey
技术分享
 1 //移动
 2 void move()
 3 {
 4     extern int direction;
 5     extern int snake[800][3];
 6     extern int score;
 7     int i = score - 1;
 8     int x,y;
 9     
10     switch(direction)
11     {
12         case 1:
13             x = 0;
14             y = -1;
15             break;
16         case 2:
17             x = 1;
18             y = 0;
19             break;
20         case 3:
21             x = 0;
22             y = 1;
23             break;
24         case 4:
25             x = -1;
26             y = 0;
27             break;
28         default:
29             break;
30     }
31     
32     if(ifEat())
33     {
34         snake[score][0] = snake[score-1][0];
35         snake[score][1] = snake[score-1][1];
36         snake[score][2] = 1;
37         score++;
38     }
39     
40     while(i > 0)
41     {
42         if(snake[i][2] != 0)
43         {
44             snake[i][0] = snake[i-1][0];
45             snake[i][1] = snake[i-1][1];
46         }
47         i--;
48     }
49     
50     snake[0][0] += x;
51     snake[0][1] += y;
52 }
move
技术分享
 1 //打印
 2 void print_all()
 3 {
 4     extern char wall[22][42];
 5     int i,j;
 6     for(i = 0; i < 22; i++)
 7     {
 8         for(j = 0; j < 42; j++)
 9         {
10             printf("%c", wall[i][j]);
11         }
12         printf("\n");
13     }
14 }
print_all

    最后只需在main中按照顺序将各个模块进行调用即可

技术分享
 1 void main()
 2 {
 3     extern char wall[22][42];
 4     extern int snake[800][3];
 5     extern int score;
 6     int speed = 400;
 7     int spot = 8;
 8     
 9     init_snake();
10     init_food();
11     
12     while(1)
13     {
14         getKey();
15         system("cls");
16         init_wall();
17         move();
18         change();
19         print_all(wall[22][42]);
20         if(ifBreak())
21             break;
22         Sleep(speed);
23         if(score == spot)
24         {
25             speed = 0.9*speed;
26             spot += 5;
27         }
28     }
29     printf("Game Over\n");
30     printf("score:%d\n",score);
31     system("pause");
32 }
main

 

以上是关于C - 简易贪吃蛇的编写的主要内容,如果未能解决你的问题,请参考以下文章

JS学习——贪吃蛇代码(简易版)

JS学习——贪吃蛇代码(简易版)

JS学习——贪吃蛇代码(简易版)

关于C语言写贪吃蛇时,蛇的身体以及移动该怎么写

基于C#开发的简易贪吃蛇

用C语言编写贪吃蛇小游戏