欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

贪吃蛇_C实现 (初学者) (o゚▽゚)o

程序员文章站 2022-03-25 17:17:09
我是刚入坑不久的,贪吃蛇算是我第一个用C写出来的小游戏 这个程序里并没有什么难懂的部分,大多都是刚开始学就接触到的,so 加油吧! 源代码在文章的末尾. 效果图就不上了 (〃'▽'〃) 首先,来确定我们所需的头文件 #include #include #incl ......

我是刚入坑不久的,贪吃蛇算是我第一个用c写出来的小游戏

这个程序里并没有什么难懂的部分,大多都是刚开始学就接触到的,so 加油吧!

源代码在文章的末尾.

效果图就不上了    (〃'▽'〃)

 

 

 

首先,来确定我们所需的头文件

#include <time.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

<time.h>  这是我们在之后生成随机食物坐标时,用来以时间来生成随机数种子所需的头文件

<conio.h>   这个是gotoxy()函数所需的头文件

至于其他的应该都明白的.

接下来,定义我们需要的常量和全局变量

//常量
//蛇的行进状态 u:上 d:下 l:左 r:右 #define u 1 #define d 2
#define l 3 #define r 4

//全局变量的设定 int state; //当前蛇的状态 int wall_x=1,wall_y=1,wall_x1=97,wall_y1=25; //围墙的坐标 int speed =200; //蛇每一次运行的时间间隔 int snake_x=6,snake_y=5; //蛇头的坐标 int food_x,food_y; //食物的坐标 int path_list[30000][2]; //路径列表 int path_find_line=0; //路径记录到第几行 int point_food=0; //食物得到次数

上面的注释应该挺清楚的了,我用的是食物得到的次数来确定蛇身的长度.

因为我比较喜欢吧main()函数放在源文件中定义函数的前面,

所以我需要函数原型,来告诉编译器将在源文件中定义的函数的特征.(如图)

void wall_draw();               //制造围墙
int border(int,int);            //边界限制
int snake_move();               //蛇的移动
int snake_tail_delete();        //删除蛇尾
int path_log();                 //蛇的位移路径记录
int food_generate();            //食物生成
int food_get(int,int);          //获得食物
int gotoxy(int,int);            //移动光标
int rectangle(int,int,int,int); //建立矩形
int control();                  //控制蛇的移动方向

然后,开始一个一个的分析定义的函数:

void wall_draw()
{
    //确定窗口大小
    system("mode con cols=100 lines=30");
    //绘画矩形
    rectangel(wall_x,wall_y,wall_x1,wall_y1);
    //打印标题
    gotoxy(43,0);
    printf("***snake***");
    //回到光标区
    gotoxy(0,29);
}

其中的:

贪吃蛇_C实现        (初学者) (o゚▽゚)o

 

 

 在命令行中的意思是:吧窗口改变成 行容纳100个字符 可以输出30列

(ps:效果是这样但是我描述的可能不太好,建议自己在命令提示符中尝试)

贪吃蛇_C实现        (初学者) (o゚▽゚)o

 

 

接下来的 rectangel()函数,是我自己写的,好像在哪个头文件里已经有了这个函数,但是我看不懂.

没办法只能自己打一个.

int rectangel(int x,int y,int x2,int y2)
{
    gotoxy(x,y);
    printf("┌");
    int i;
    for (i = 0; i < x2-x-1; i++)
    {
        printf("─");
    }
    printf("┐");
    for (i = 0; i < y2-y-1; i++)
    {
        gotoxy(x,y+i+1);
        printf("│");
        gotoxy(x2,y+i+1);
        printf("│");
    }
    gotoxy(x,y2);
    printf("└");
    for (i = 0; i < x2-x-1; i++)
    {
        printf("─");
    }
    printf("┘");
}

关于这个函数其实挺简单的,他要求输入的参数有 4个.也就是矩形的两个对顶点

把两个对顶点输入进去,就可以求出整个矩形的四个顶点,然后用gotoxy()函数来移动光标进行打印矩形

 

path_log()函数:

//蛇的移动路径记录
int path_log()
{
    path_list[path_find_line][0]=snake_x;
    path_list[path_find_line][1]=snake_y;
    ++path_find_line;
}

当执行该函数时,会把当前蛇头的坐标记录到path_list数组中.

 

snake_tail_delete()函数:

//删除蛇尾
int snake_tail_delete()
{
    //查询蛇尾位置
    int x,y;
    x=path_list[path_find_line-point_food-1][0];    
    y=path_list[path_find_line-point_food-1][1];    
    gotoxy(x,y);
    printf(" ");
    path_list[path_find_line-point_food-1][0]=0;
    path_list[path_find_line-point_food-1][1]=0;
    
    //返回光标区
    gotoxy(0,29);

    return 0;
}

在这里我的想法是每次都删除蛇尾,只不过如果吃到食物的时候会去上一次的地方删除蛇尾.

解释的可能不怎么好.(简单来讲:假设蛇移动了十次,且吃到了两次食物,那么就可知道蛇尾是在已走路径中的第 path_find_line - point_food这里,即10-2)

border()函数:

在贪吃蛇中,蛇不能撞墙,也不能撞到自己的身体所以需要 border()函数来判断蛇是否撞墙,或者撞到自己的身体.

//是否生成在障碍物上 是:1  否:0 border(x,y)
int border(int x,int y)
{
    //查询物体是否撞到蛇身
    int i;
    for (i = 0; i < path_find_line+1; i++)
    {
        if (x==path_list[i][0] && y==path_list[i][1])
        {
            return 1;
        }
        
    }

    //查询物体是否撞到墙
    if (wall_x>=x || wall_x1<=x || wall_y>=y || wall_y1<=y)
    {
        return 1;
    }

    return 0;
}

在这个函数中,是有返回值的.

判断蛇身就是在path_list数组中查询当前蛇头坐标是否在里面,是:撞到    否:没撞到

如果蛇撞墙,或者撞到了蛇身,返回1,  否则返回0.

food_generate()函数:

//食物的生成 成功:1 失败:0
int food_generate()
{
    //初始化随机种子
    srand((unsigned int)time(null));
    int x,y;
    x=food_x;
    y=food_y;
    while (1)
    {
        //随机食物坐标
        food_x=rand()%wall_x1+wall_x;
        food_y=rand()%wall_y1+wall_y;

        //查询食物是否生成位置错误
        if (food_x%2 ==1)
        {
            continue;
        }
        
        if (food_x==x && food_y==y)
        {
            continue;
        }
        if (border(food_x,food_y)==1)
        {
            continue;
        }

        //打印食物
        gotoxy(food_x,food_y);
        printf("\a⊕");
        gotoxy(0,29);

        return 1;
    }
    return 0;
}

唯一要讲的差不多就是食物的随机生成的问题了

rand()函数取随机数.但是使用前需要初始化随机数种子

也就是这个:

贪吃蛇_C实现        (初学者) (o゚▽゚)o

 

 

food_get()函数:

//获得食物  food_get(snake_x,snake_y)
int food_get(int x,int y)
{
    if (x==food_x && y==food_y)
    {
        food_generate();
        ++point_food;
        gotoxy(1,0);
        printf("point:%4d",point_food);
        gotoxy(0,29);
    }
}

简单讲:就是判断蛇头坐标是否和食物坐标相等.

相等  -> 生成一次食物 food_generate()

不相等  -> 不执行

snake_move()函数:

//蛇的移动
int snake_move()
{
    snake_tail_delete();
    if (state == u)
    {
        --snake_y;
        gotoxy(snake_x,snake_y);
        printf("█");
        gotoxy(10,29);
        printf("speed:%4d",speed);
    }
    if (state == d)
    {
        ++snake_y;
        gotoxy(snake_x,snake_y);
        printf("█");
        gotoxy(10,29);
        printf("speed:%4d",speed);
    }
    if (state == l)
    {
        --snake_x;
        --snake_x;
        gotoxy(snake_x,snake_y);
        printf("█");
        gotoxy(10,29);
        printf("speed:%4d",speed);
    }
    if (state == r)
    {
        ++snake_x;
        ++snake_x;
        gotoxy(snake_x,snake_y);
        printf("█");
        gotoxy(10,29);
        printf("speed:%4d",speed);
    }
    food_get(snake_x,snake_y);
    
    if (border(snake_x,snake_y)==1)
    {
        return 1;
    }
    path_log();
    sleep(speed);
}

在游戏里贪吃蛇每隔一定的时间就要移动一格.

所以我们需要sleep()函数.

(ps:sleep的s一定要大写,c语言对大小写十分敏感)

然后在蛇每移动一次,就执行path_log()来记录移动的路径

之后判断是否吃到食物 food_get()

以及执行snake_tail_delete()来删除蛇尾

然后等待sleep(speed);

最后就是控制蛇的移动啦  ε≡٩(๑>₃<)۶

control()函数:

//监听键盘 成功:1 失败:0
int control()
{
    state = d;
    gotoxy(snake_x,snake_y);
    printf(" ");
    while(1)
    {
        if(getasynckeystate(vk_up) && state!=d)
        {
            state=u;
        }
        else if(getasynckeystate(vk_down) && state!=u)
        {
            state=d;
        }
        else if(getasynckeystate(vk_left)&& state!=r)
        {
            state=l;
        }
        else if(getasynckeystate(vk_right)&& state!=l)
        {
            state=r;
        }
        else if(getasynckeystate(vk_f1))
        {
            if (speed<=20)
            {
                speed=10;
            }
            else
            {
                speed=speed-10;
            }
            
            
        }
        else if(getasynckeystate(vk_f2))
        {
            speed=speed+10;
        }
        if (snake_move()==1)
        {
            break;
        }
    }
}

这个就是游戏的主循环了

在这里的时候,出现了getasynckeystate()函数

(解释一下这个函数:执行他的时候会寻找是否在上次执行这个命令时是否按下键盘上的那个键,详细的去百度吧!)

 

源代码:

  1 #include <time.h>
  2 #include <conio.h>
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <windows.h>
  6 
  7 //蛇的行进状态
  8 #define u 1
  9 #define d 2
 10 #define l 3
 11 #define r 4
 12 
 13 void wall_draw();               //制造围墙
 14 int border(int,int);            //边界限制
 15 int snake_move();               //蛇的移动
 16 int snake_tail_delete();        //删除蛇尾
 17 int path_log();                 //蛇的位移路径记录
 18 int food_generate();            //食物生成
 19 int food_get(int,int);          //获得食物
 20 int gotoxy(int,int);            //移动光标
 21 int rectangle(int,int,int,int); //建立矩形
 22 int control();                  //控制移动方向
 23 
 24 //全局变量的设定
 25 
 26 int state;          //当前蛇的状态
 27 int wall_x=1,wall_y=1,wall_x1=97,wall_y1=25;        //围墙的坐标
 28 int speed =200;         //蛇每一次运行的时间间隔
 29 int snake_x=6,snake_y=5;        //蛇头的坐标
 30 int food_x,food_y;              //食物的坐标
 31 int path_list[30000][2];        //路径列表
 32 int path_find_line=0;           //路径记录到第几行
 33 int point_food=0;               //食物得到次数
 34 
 35 int main()
 36 {
 37     wall_draw();        //绘制边界
 38 
 39     gotoxy(snake_x,snake_y);
 40     printf("█");
 41 
 42     food_generate();    //生成一次食物
 43 
 44     //游戏进程
 45     control();           //控制蛇的移动方向
 46     
 47     //游戏结束
 48     system("cls");
 49     wall_draw();
 50 }
 51 
 52 
 53 
 54 int gotoxy(int x,int y)
 55 {
 56     coord coord = {x,y};
 57     setconsolecursorposition(getstdhandle(std_output_handle), coord);
 58 }
 59 void wall_draw()
 60 {
 61     //确定窗口大小
 62     system("mode con cols=100 lines=30");
 63     //绘画矩形
 64     rectangel(wall_x,wall_y,wall_x1,wall_y1);
 65     //打印标题
 66     gotoxy(43,0);
 67     printf("***snake***");
 68     //回到光标区
 69     gotoxy(0,29);
 70 }
 71 int rectangel(int x,int y,int x2,int y2)
 72 {
 73     gotoxy(x,y);
 74     printf("┌");
 75     int i;
 76     for (i = 0; i < x2-x-1; i++)
 77     {
 78         printf("─");
 79     }
 80     printf("┐");
 81     for (i = 0; i < y2-y-1; i++)
 82     {
 83         gotoxy(x,y+i+1);
 84         printf("│");
 85         gotoxy(x2,y+i+1);
 86         printf("│");
 87     }
 88     gotoxy(x,y2);
 89     printf("└");
 90     for (i = 0; i < x2-x-1; i++)
 91     {
 92         printf("─");
 93     }
 94     printf("┘");
 95 }
 96 
 97 //是否生成在障碍物上 是:1  否:0 border(x,y)
 98 int border(int x,int y)
 99 {
100     //查询物体是否撞到蛇身
101     int i;
102     for (i = 0; i < path_find_line+1; i++)
103     {
104         if (x==path_list[i][0] && y==path_list[i][1])
105         {
106             return 1;
107         }
108         
109     }
110 
111     //查询物体是否撞到墙
112     if (wall_x>=x || wall_x1<=x || wall_y>=y || wall_y1<=y)
113     {
114         return 1;
115     }
116 
117     return 0;
118 }
119 
120 //蛇的移动路径记录
121 int path_log()
122 {
123     path_list[path_find_line][0]=snake_x;
124     path_list[path_find_line][1]=snake_y;
125     ++path_find_line;
126 }
127 
128 //食物的生成 成功:1 失败:0
129 int food_generate()
130 {
131     //初始化随机种子
132     srand((unsigned int)time(null));
133     int x,y;
134     x=food_x;
135     y=food_y;
136     while (1)
137     {
138         //随机食物坐标
139         food_x=rand()%wall_x1+wall_x;
140         food_y=rand()%wall_y1+wall_y;
141 
142         //查询食物是否生成位置错误
143         if (food_x%2 ==1)
144         {
145             continue;
146         }
147         
148         if (food_x==x && food_y==y)
149         {
150             continue;
151         }
152         if (border(food_x,food_y)==1)
153         {
154             continue;
155         }
156 
157         //打印食物
158         gotoxy(food_x,food_y);
159         printf("\a⊕");
160         gotoxy(0,29);
161 
162         return 1;
163     }
164     return 0;
165 }
166 
167 //获得食物  food_get(snake_x,snake_y)
168 int food_get(int x,int y)
169 {
170     if (x==food_x && y==food_y)
171     {
172         food_generate();
173         ++point_food;
174         gotoxy(1,0);
175         printf("point:%4d",point_food);
176         gotoxy(0,29);
177     }
178     
179 }
180 
181 //删除蛇尾
182 int snake_tail_delete()
183 {
184     //查询蛇尾位置
185     int x,y;
186     x=path_list[path_find_line-point_food-1][0];    
187     y=path_list[path_find_line-point_food-1][1];    
188     gotoxy(x,y);
189     printf(" ");
190     path_list[path_find_line-point_food-1][0]=0;
191     path_list[path_find_line-point_food-1][1]=0;
192 
193     //返回光标区
194     gotoxy(0,29);
195 
196     return 0;
197 }
198 
199 //监听键盘 成功:1 失败:0
200 int control()
201 {
202     state = d;
203     gotoxy(snake_x,snake_y);
204     printf(" ");
205     while(1)
206     {
207         if(getasynckeystate(vk_up) && state!=d)
208         {
209             state=u;
210         }
211         else if(getasynckeystate(vk_down) && state!=u)
212         {
213             state=d;
214         }
215         else if(getasynckeystate(vk_left)&& state!=r)
216         {
217             state=l;
218         }
219         else if(getasynckeystate(vk_right)&& state!=l)
220         {
221             state=r;
222         }
223         else if(getasynckeystate(vk_f1))
224         {
225             if (speed<=20)
226             {
227                 speed=10;
228             }
229             else
230             {
231                 speed=speed-10;
232             }
233             
234             
235         }
236         else if(getasynckeystate(vk_f2))
237         {
238             speed=speed+10;
239         }
240         if (snake_move()==1)
241         {
242             break;
243         }
244     }
245 }
246 //蛇的移动
247 int snake_move()
248 {
249     snake_tail_delete();
250     if (state == u)
251     {
252         --snake_y;
253         gotoxy(snake_x,snake_y);
254         printf("█");
255         gotoxy(10,29);
256         printf("speed:%4d",speed);
257     }
258     if (state == d)
259     {
260         ++snake_y;
261         gotoxy(snake_x,snake_y);
262         printf("█");
263         gotoxy(10,29);
264         printf("speed:%4d",speed);
265     }
266     if (state == l)
267     {
268         --snake_x;
269         --snake_x;
270         gotoxy(snake_x,snake_y);
271         printf("█");
272         gotoxy(10,29);
273         printf("speed:%4d",speed);
274     }
275     if (state == r)
276     {
277         ++snake_x;
278         ++snake_x;
279         gotoxy(snake_x,snake_y);
280         printf("█");
281         gotoxy(10,29);
282         printf("speed:%4d",speed);
283     }
284     food_get(snake_x,snake_y);
285     
286     if (border(snake_x,snake_y)==1)
287     {
288         return 1;
289     }
290     
291
292     path_log();
293     
294     sleep(speed);
295     
296 }

如果这个程序有什么问题,或者是有什么建议的话,可以联系我交流.

欢迎讨论,并互相进步!

                                                                                     (第 4次更改)