很早就有了这个想法,只是一直没有践行,经过零零碎碎地小作业,慢慢就做了出来,看起来还行。
下面说一下我的思路:
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 }