贪吃蛇程序(c/Linux)

本文分享了一款自制的贪吃蛇游戏实现过程,利用C语言和单向链表技术,详细解析了游戏的设计思路和难点,包括蛇的移动、食物生成、碰撞检测等关键环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很早就有了这个想法,只是一直没有践行,经过零零碎碎地小作业,慢慢就做了出来,看起来还行。
下面说一下我的思路:
a 通过画一个二维数组显示游戏框图
b 创建蛇,单向链表最合适了
c 蛇的行动,撞墙、吃自己:游戏结束,移动、吃食物:游戏进行
d 蛇的控制,一开始用简单的getchar模拟,后面从网上找了按键识别,做出来了,还有待学习
e 游戏步骤:恢复空图->写入蛇->写入食物->输出画面->控制输入->蛇的行动->游戏结束判断->恢复空图
总的来说,还有一些结构可以优化,部分可以集合到一个函数里,画面还ok。
难点:1 蛇移动的函数设计,开始用传入结点指针,返回void,结果蛇走一下没动,从尾巴到蛇头慢慢缩成一个头,于是发现传入的蛇头只是指针的值(形参),原来的蛇头还是没变,于是设计了返回结点指针,通过赋值 snake = Move(snake)的方式更新蛇头,然后蛇就活了
2 按键的输入,此处涉及I/O的操作,借鉴的网上代码,待学习
3 逻辑转换,二维数组与数学中x,y坐标的转换一开始就弄得很混乱,但所幸才二维而已,通过高度、宽度的概念一下就清晰了。

还算简单,脑海中有大概的思路,剩下的就是一步步来,多用printf()把错误点定位出来,下一步,继续学习。

<c/centos>  
  1 #include <stdio.h>
  2 #include <time.h>
  3 #include <malloc.h>
  4 #include <unistd.h>
  5 #include <fcntl.h>
  6 #include <stdlib.h>
  7 #include <sys/select.h>
  8 
  9 void setIO(int flag)
 10 {
 11         if(flag)
 12                 system("stty cbreak -echo");
 13         else
 14                 system("stty cooked echo");
 15 }
 16 
 17 #define high 20
 18 #define wide 30
 19 
 20 #define up 1
 21 #define down 2
 22 #define left 3
 23 #define right 4
 24 
 25 int score  = 0;
 26 int Level = 1;
 27 int direction = 1;
 28 int IsEat=0;
 29 int FoodH=5,FoodW=10;
 30 
 31 char Picture[high][wide];  //游戏框图
 32 
 33 typedef struct snake{
 34       int x;
 35       int y;
 36       struct snake* next;
 37 }Node,*PSnake;
 38 
 39 PSnake Init()           //生成一条蛇  坐标为中心点向下5个格,蛇头向上 
 40 {
 41    printf("SnakeMake start!\n");
 42    int len=5;
 43    PSnake head=(PSnake)malloc(sizeof(Node));
 44    if(head == NULL)
 45          printf("Snake head make failed!\n");
 46    head->x=wide/2;
 47    head->y=high/2+5;
 48    head->next=NULL;
 49 
 50    int i=0;
 51    for(;i<5;i++)
 52    {
 53       PSnake P=(PSnake)malloc(sizeof(Node));
 54       if(P==NULL)
 55       {     printf("Frog king is dead!\n");
 56             break;
 57       }
 58       P->x=wide/2;
 59       P->y=high/2-i+4;
 60       P->next=head;
 61       head=P;
 62    }
 63    printf("Snake is alive!\n");
 64    return head;
 65 }
 66 
 67 PSnake Eat(int x,int y,PSnake snake)
 68 {
 69    PSnake p=(PSnake)malloc(sizeof(Node));
 70    if(p==NULL)
 71    {
 72       printf("New head make failed!");
 73    }
 74    p->x = x;
 75    p->y = y;
 76    p->next=snake;
 77    score += 100;
 78    return p;
 79 }
 80 
 81 void Walk(int x,int y,PSnake snake)
 82 {
 83    PSnake p=snake;
 84    int a,b, c=x, d=y;
 85    while(p!=NULL)
 86    {
 87       a=p->x;
 88       b=p->y;
 89       p->x = c;
 90       p->y = d;
 91       c=a;
 92       d=b;
 93       p=p->next;
 94    }
 95 }
 96 
 97 int Serch(int x,int y,PSnake snake)     //用于检验移动后的蛇头是否吃了自身
 98 {
 99    PSnake q=snake->next;
100    while(q!= NULL)
101    {
102        if( ( (q->x) == x ) && ( (q->y) == y ) )
103                return 1;
104        q=q->next;
105    }
106    return 0;
107 }
108 
109 void WriteSnake(PSnake snake)   //把蛇写入打印数组
110 {
111    PSnake   p=snake;
112    while(p != NULL)
113    {
114       Picture[p->y][p->x]='*';
115       p=p->next;
116    }
117 }
118 
119 void Paint(void)       //Init picture 初始化以及还原空图
120 {
121    int y=high,x=wide,i,j;
122    for(i=0; i<y; i++)
123          for(j=0; j<x; j++)
124                Picture[i][j]=' ';
125 }
126 void Print(char* p,int score,int Lev)       //打印框架,生成画面
127 {
128    int a=high,b=wide,i=0,j;
129    static int cnt=1;
130    printf("\033c");
131    printf("The Snake Game is On!! The Write times is %d !\n",cnt);
132    cnt++;
133    printf("Player:%s   Score:%d   Level:%d \n",p,score,Lev);
134    while(i<b*2+2)
135    {
136       printf("-");
137       i++;
138    }
139    printf("\n");
140    for (i=0; i<a; i++)
141    {
142       printf("|");
143       for(j=0; j<b; j++)
144       {
145             printf("%c ",Picture[i][j]);
146       }
147       printf("|");
148       printf("\n");
149    }
150    for(i=0;i<=b*2+1;i++)
151    {
152       printf("-");
153    }
154    printf("\n");
155    printf("-------------AAAAAAAA\n");
156    printf("----fdsfsdfsd3-------------------------------\n");
157    printf("===========++++++++This is bottom!!!!+++++++++++++++++++++\n");
158 }
159 int MakeFood(void)       //创造食物
160 {
161    static int MC=0;         //MC =  FoodMake Count
162    while(1)    //  食物不能生成在已是snake的部分,确认此处运行在蛇写入的部分之后!!!
163    {
164       if(MC > ((high * wide)/2 ) )      //限制食物生成数量,留待考虑
165             return 0;
166       srand((int)time(0));
167       FoodH=rand()%high;
168       FoodW=rand()%wide;
169       if(Picture[FoodH][FoodW] == ' ')
170               break;
171    }
172    //Picture[FoodH][FoodW]='*';
173    MC++;
174    return 1;
175 }
176 
177 PSnake MakeMove(PSnake s)    //蛇的动作
178 {
179    int x,y;
180    PSnake p=s;
181    x=s->x,y=s->y;      //x,y为下一步的坐标
182 
183    if(direction == up)
184            y = y - 1;
185    if(direction == down)
186            y = y + 1;
187    if(direction == right)
188            x = x + 1;
189    if(direction == left)
190            x = x - 1;
191    //check if the snake crash the wall
192    if( (y>(high-1)) || ((y<0)) || ((x)<0) || (x>(wide-1)) )   //撞墙检测
193    {
194       printf("x=%d y=%d s.x=%d s.y=%d \n",x,y,s->x,s->y);
195       printf("The snake break the wall!");
196       return NULL;
197    }
198    if(Serch(x,y,s))                                 //吃掉自身检测
199    {
200       printf("x=%d y=%d \n",x,y);
201       while(p != NULL)
202       {
203          printf("p->x= %d p->y= %d \n",p->x,p->y);
204          p=p->next;
205       }
206       printf("Your snake eat itsself!");
207       return NULL;
208    }
209 
210    if( (x==FoodW) && (y==FoodH) )     //如果下一步是食物,则吃食物
211    {
212       s=Eat(x,y,s);
213       IsEat=1;
214    }
215    else                               //不是食物则前进一步
216    {
217       Walk(x,y,s);
218    }
219    return s;
220 }
221 
222 int kbhit(void)                        //是否按下检测
223 {
224         struct timeval tv;
225         fd_set rdfs;
226         tv.tv_sec = 0;
227         tv.tv_usec = 0;
228         FD_ZERO(&rdfs);
229         FD_SET(STDIN_FILENO,&rdfs);
230         select(STDIN_FILENO+1,&rdfs,NULL,NULL,&tv);
231         return FD_ISSET(STDIN_FILENO,&rdfs);
232 }
233 void InputCTL(int level)        //控制输入部分,并根据level控制移动速度
234 {
235    int Dir=direction;
236    int timeUse;
237    struct timeval start,end;    
238    gettimeofday(&start,NULL);
239    setIO(1);
240    char c,n;
241    while(1)
242    {
243            gettimeofday(&end,NULL);
244            timeUse = 1000000*(end.tv_sec - start.tv_sec) +
245                    end.tv_usec - start.tv_usec;
246            if(timeUse > 1000000 - level*100000)    //通过设定时间段结束循环,达到控制速度的目的
247                    break;
248            if(kbhit())                           //记录按键信息
249               c=getchar();
250    }
251    setIO(0);
252    if( c == 'w')
253    {
254        Dir=1;
255    }
256    else if( c == 's')
257    {
258        Dir=2;
259    }
260    else if( c == 'a')
261    {
262        Dir=3;
263    }
264    else if( c == 'd')
265    {
266        Dir=4;
267    }
268    else;
269    if( ((Dir == 1) && (direction == down) ) || ((Dir == 2) && (direction == up))
270                    || ((Dir == 3) && (direction == right)) || ((Dir == 4) && (direction == left) ) )               //如若与行进方向相反则保持原来方向
271    {
272            //printf("Dir = %d \n",Dir);
273    }
274    else
275    {
276       direction = Dir;
277    }
278    // printf("The Direction'value is %d !\n",direction);
279 }
280 
281 int CheckLevel(int score)                  //return level
282 {
283         static int change=0;
284         if(((score - change) >= 300) && (Level < 9) )
285         {
286                 Level ++;
287                 change += 300;
288         }
289         return Level;
290 }
291 void GameRun(void)
292 {
293    int GameState=1;
294    score=0;
295    Level=1;
296    char Name[10];
297    printf("Please input your name:");
298    scanf("%s",&Name);
299    PSnake jack=Init();
300 
301    PSnake p=jack;
302    while(GameState)
303    {                            
304       Paint();             //恢复空的数组
305       WriteSnake(jack);    //写入蛇
306       if(IsEat)            //判断是否生成新的食物
307       {
308             if(MakeFood())
309                IsEat=0;
310       }
311       Picture[FoodH][FoodW]='*';   //写入食物
312       //system("clear");
313       //sleep(2);
314       Print(Name,score,CheckLevel(score));                      //打印游戏画面
315       InputCTL(Level);           //方向控制、速度控制
316       jack = MakeMove(jack);     //蛇的行动
317       if( jack == NULL )         //如果蛇头不存在,则游戏结束!
318       {
319          GameState=0;
320          printf("\033c");
321          printf("Game Over!\n");
322       }
323    }
324 }
325 int main(void)
326 {
327    GameRun();
328    return 0;
329 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值