歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 《QQ表情版貪吃蛇游戲》項目實作【附代碼】

《QQ表情版貪吃蛇游戲》項目實作【附代碼】

日期:2017/3/1 10:16:51   编辑:Linux編程

突發奇想:

最近又得開始忙著復習考試了,整天都是看PPT,啃課本,做習題,無聊加煩惱。手癢,想敲代碼,又怕上瘾耽誤了考試,所以就想著拿個小程序來練練手,以解煩悶。正在做視頻監控,對SDL有點了解,所以就它了!而且它是跨平台的,方便在linux下玩弄。做個什麼好呢?就來個QQ表情版的貪吃蛇好了,我覺得做出來會很搞笑的。說干就干,這篇blog就是在這種沖動下寫的,嘻嘻嘻~~為了寫好這篇blog,我決定使用我們學校整天吹噓的CDIO理念來組織文章,所以這對我又是一個有意思的挑戰。好了,廢話不多說,哥開始了……

(一)構思(CDIO中的C)

QQ表情版的貪吃蛇使用QQ經典表情來充當蛇身和食物的,其中頭像當蛇身,其他的當食物。這些表情是按照一定順序來出來的,也許可以使用循環數組的方法實現之~~至於游戲規則就沒什麼好講的了,就是前後左右鍵盤響應控制蛇身方向,食物隨機位置出現,蛇身吃完食物後蛇身便長長一節,分數便增加一分。

(二)設計(CDIO中的D)

關鍵部分就是蛇的移動,我把整條蛇設計成一條單向循環鏈表,並且是逆向的,即從蛇尾蛇一直指向蛇頭,再從蛇頭指回蛇尾,當蛇移動時,只要把蛇頭指針向前移動一節(即蛇尾,移動之前已經將其改為新蛇頭),同時蛇尾指針也向向前移動一節(即次蛇尾),而中間部分的蛇節點的結構體不需要改變,這樣用戶就會感覺是蛇在移動。

次關鍵部分就是蛇的增長,當蛇頭吃到食物之後,就根據舊蛇的蛇尾記錄產生新的節點,然後插到蛇尾即可

是不是很簡單啊!!那接下來開始實現吧~~

(三)實現(CDIO中的I)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include <SDL/SDL.h>
  4. #include <SDL/SDL_image.h>
  5. #include <SDL/SDL_ttf.h>
  6. #define down 1
  7. #define left 2
  8. #define right 3
  9. #define up 4
  10. SDL_Surface *screen;
  11. SDL_Surface *start_background;
  12. SDL_Surface *run_backgound;
  13. SDL_Surface *snake_node;
  14. SDL_Surface *food;
  15. SDL_Surface *score;
  16. SDL_Rect dst;
  17. SDL_Color color;
  18. TTF_Font *font;
  19. char str[10];
  20. /*蛇節點*/
  21. typedef struct Body_Node{
  22. int i,j;//坐標
  23. struct Body_Node *p;//指向下一蛇節點
  24. }Body_Node;
  25. /*蛇*/
  26. typedef struct Snake{
  27. Body_Node *head,*tail;//蛇頭蛇尾指針
  28. Body_Node tail_record;//舊蛇蛇尾記錄(吃東西時用到)
  29. int snake_long;//蛇身長度
  30. int direction;//蛇頭方向
  31. }Snake;
  32. /*食物*/
  33. typedef struct Food{
  34. int i,j;//坐標
  35. int num;//圖片編號
  36. }Food;
  37. SDL_Surface *LoadIMG(const char *name)
  38. {
  39. SDL_Surface *tmp, *final;
  40. if ((tmp = IMG_Load (name)) == NULL)
  41. fprintf (stderr, "load %s error\n", name);
  42. final = SDL_DisplayFormat (tmp);
  43. SDL_FreeSurface (tmp);
  44. SDL_SetColorKey (final, SDL_SRCCOLORKEY | SDL_RLEACCEL,*(Uint32 *) final->pixels);
  45. return final;
  46. }
  47. /*初始化*/
  48. void Init()
  49. {
  50. if ((SDL_Init (SDL_INIT_AUDIO | SDL_INIT_VIDEO)) < 0)
  51. fprintf (stderr, "init error\n");
  52. if ((screen = SDL_SetVideoMode (720, 720, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
  53. fprintf (stderr, "set video mode error\n");
  54. if (TTF_Init() < 0)
  55. fprintf(stderr, "TTF init error:%s\n", SDL_GetError());
  56. atexit (SDL_Quit);
  57. SDL_WM_SetCaption ("Greed Snake", NULL);
  58. srand (time (NULL));
  59. run_backgound = LoadIMG ("background.png");
  60. start_background = LoadIMG ("start.jpg");
  61. }
  62. /*繪畫游戲開始界面*/
  63. void Game_start()
  64. {
  65. int i,j;
  66. int temp=30;
  67. int x=0, y=0;
  68. int num=0;
  69. int flag=0;
  70. dst.x = 0;//繪畫游戲開始界面的背景
  71. dst.y = 0;
  72. dst.w = start_background->w;
  73. dst.h = start_background->h;
  74. SDL_BlitSurface (start_background, NULL, screen, &dst);
  75. SDL_UpdateRects (screen, 1, &dst);
  76. for(i=1; i<=31;)//繪畫游戲開始界面的動畫
  77. {
  78. for(j=1; j<= temp; j++)
  79. {
  80. snprintf(str, 10, "%d.gif", num);//繪畫一個QQ表情
  81. start_background = LoadIMG (str);
  82. SDL_Delay (15);
  83. dst.x = x;
  84. dst.y = y;
  85. dst.w = start_background->w;
  86. dst.h = start_background->h;
  87. SDL_BlitSurface (start_background, NULL, screen, &dst);
  88. SDL_UpdateRects (screen, 1, &dst);
  89. num = (num+1)%82;//QQ表情圖片的編號控制在0到81
  90. /*設置一個flag,動畫時,分別有(1)x軸遞增,y軸不變;(2)x軸不變,y軸遞減;(3)x軸遞減,y軸不變;(4)x軸不變,y軸遞增;四種狀態*/
  91. switch(flag)
  92. {
  93. case 0:x += 24;break;
  94. case 1:y += 24;break;
  95. case 2:x -= 24;break;
  96. case 3:y -= 24;break;
  97. }
  98. }
  99. i++;
  100. temp = (32-i)-(31-i)%2;//每畫一條邊時,控制需要繪畫的QQ表情個數
  101. switch(flag)//坐標超出屏幕,需要回溯
  102. {
  103. case 0:{x -= 24;y += 24;}break;
  104. case 1:{x -= 24;y -= 24;}break;
  105. case 2:{x += 24;y -= 24;}break;
  106. case 3:{x += 24;y += 24;}break;
  107. }
  108. flag = (flag+1)%4;//flag控制在0到3
  109. }
  110. }
  111. /*繪畫游戲進行時背景,即“QQ聊天窗口”*/
  112. void Game_background()
  113. {
  114. dst.x = 0;//設置目標邊框dst(x=0,y=0,width=w,height=h)
  115. dst.y = 0;
  116. dst.w = run_backgound->w;
  117. dst.h = run_backgound->h;
  118. SDL_BlitSurface (run_backgound, NULL, screen, &dst);//copy到主窗口(screen)上
  119. SDL_UpdateRects (screen, 1, &dst);//局部更新主窗口
  120. }
  121. /*繪畫游戲結束時的提示,即“GameOver”*/
  122. void Game_end()
  123. {
  124. font = TTF_OpenFont("test.ttf", 100);//設置字體樣式與大小
  125. color.r = 255;
  126. color.g = 0;
  127. color.b = 0;
  128. score=TTF_RenderText_Solid(font, "Game Over", color);
  129. dst.x = 150;
  130. dst.y = 350;
  131. dst.w = score->w;
  132. dst.h = score->h;
  133. SDL_BlitSurface(score, NULL, screen, &dst);
  134. SDL_UpdateRects (screen, 1, &dst);
  135. }
  136. /*繪畫游戲進行時分數*/
  137. void Draw_Score(Snake S)
  138. {
  139. snprintf(str, 10, "%d", S.snake_long);
  140. font = TTF_OpenFont("test.ttf", 15);
  141. color.r = 0;
  142. color.g = 0;
  143. color.b = 255;
  144. score=TTF_RenderText_Solid(font, str, color);
  145. dst.x = 278;
  146. dst.y = 122;
  147. dst.w = score->w;
  148. dst.h = score->h;
  149. SDL_BlitSurface(score, NULL, screen, &dst);
  150. SDL_UpdateRects (screen, 1, &dst);
  151. }
  152. /*繪畫食物*/
  153. void Draw_Food(Food F)
  154. {
  155. snprintf(str, 10, "%d.gif", F.num);
  156. food = LoadIMG (str);
  157. dst.x = F.i*24;
  158. dst.y = F.j*24+210;
  159. dst.w = food->w;
  160. dst.h = food->h;
  161. SDL_BlitSurface (food, NULL, screen, &dst);
  162. SDL_UpdateRects (screen, 1, &dst);
  163. }
  164. /*繪畫蛇*/
  165. void Draw_Snake(Snake S)
  166. {
  167. int k;
  168. int num;
  169. Body_Node *tp;
  170. tp=S.head;
  171. for(num=k=0;k<S.snake_long;k++,num=(num+1)%65)
  172. {
  173. snprintf(str, 10, "%d.gif", num);
  174. snake_node = LoadIMG (str);
  175. dst.x = tp->i*24;
  176. dst.y = tp->j*24+210;
  177. dst.w = snake_node->w;
  178. dst.h = snake_node->h;
  179. SDL_BlitSurface (snake_node, NULL, screen, &dst);
  180. SDL_UpdateRects (screen, 1, &dst);
  181. tp=tp->p;
  182. SDL_FreeSurface(snake_node);
  183. }
  184. }
  185. /*生產食物*/
  186. void Produce_Food(Food *F)
  187. {
  188. time_t t;
  189. int i,j;
  190. srand((unsigned)time(&t));
  191. F->i=(rand()%29);
  192. F->j=(rand()%20);
  193. F->num=(rand()%16)+65;
  194. }
  195. /*生產蛇,最初為2節*/
  196. void Produce_Snake(Snake *S)
  197. {
  198. Body_Node *temp;
  199. temp=(Body_Node *)malloc(sizeof(Body_Node));
  200. temp->i=4;
  201. temp->j=3;
  202. S->tail=temp;
  203. temp=(Body_Node *)malloc(sizeof(Body_Node));
  204. temp->i=5;
  205. temp->j=3;
  206. S->head=temp;
  207. S->tail->p=S->head;
  208. S->head->p=S->tail;
  209. S->snake_long=2;
  210. S->direction=right;
  211. S->tail_record.i=-1;
  212. S->tail_record.j=-1;
  213. S->tail_record.p=NULL;
  214. }
  215. /*移動蛇身*/
  216. void Move_Snake(Snake *S)
  217. {
  218. S->tail_record.i=S->tail->i;
  219. S->tail_record.j=S->tail->j;
  220. /*根據蛇的方向把蛇尾節點當新的蛇頭節點,我把整條蛇設計成一個單向循環鏈表*/
  221. switch(S->direction)
  222. {
  223. case left:{
  224. S->tail->i=S->head->i-1;
  225. S->tail->j=S->head->j;
  226. break;
  227. }
  228. case down:{
  229. S->tail->i=S->head->i;
  230. S->tail->j=S->head->j+1;
  231. break;
  232. }
  233. case right:{
  234. S->tail->i=S->head->i+1;
  235. S->tail->j=S->head->j;
  236. break;
  237. }
  238. case up:{
  239. S->tail->i=S->head->i;
  240. S->tail->j=S->head->j-1;
  241. break;
  242. }
  243. }
  244. S->head=S->tail;
  245. S->tail=S->tail->p;
  246. }
  247. /*根據鍵盤響應改變蛇的方向*/
  248. void Change_Snake_Direction(SDL_Event event,Snake *S)
  249. {
  250. switch(event.key.keysym.sym)
  251. {
  252. case SDLK_LEFT:
  253. if(S->direction!=right)
  254. S->direction=left;
  255. break;
  256. case SDLK_DOWN:
  257. if(S->direction!=up)
  258. S->direction=down;
  259. break;
  260. case SDLK_RIGHT:
  261. if(S->direction!=left)
  262. S->direction=right;
  263. break;
  264. case SDLK_UP:
  265. if(S->direction!=down)
  266. S->direction=up;
  267. break;
  268. default:;
  269. }
  270. }
  271. /*當吃到食物時,增長蛇身*/
  272. void Add_Snake_Node(Snake *S)
  273. {
  274. Body_Node *tp;
  275. tp=(Body_Node *)malloc(sizeof(Body_Node));
  276. tp->i=S->tail_record.i;
  277. tp->j=S->tail_record.j;
  278. tp->p=S->tail;
  279. S->head->p=tp;
  280. S->tail=tp;
  281. S->snake_long++;
  282. }
  283. /*判斷蛇是否存活*/
  284. void Judge_life(Snake S,int *life)
  285. {
  286. int k;
  287. Body_Node *tp=S.tail;
  288. for(k=S.snake_long;k>=5;k--,tp=tp->p)//判斷是否撞到自己的身體,只有5節蛇身才會出現此問題
  289. {
  290. if(S.head->i==tp->i&&S.head->j==tp->j)
  291. {
  292. *life=0;
  293. break;
  294. }
  295. }
  296. if(S.head->i<0||S.head->i>28)//判斷蛇頭是否撞到牆壁
  297. {
  298. *life=0;
  299. }
  300. else if(S.head->j<0||S.head->j>19)
  301. {
  302. *life=0;
  303. }
  304. }
  305. /*測試用的,方便調試*/
  306. void Test(Snake S,Food F)
  307. {
  308. Body_Node *tp;
  309. int k;
  310. tp=S.tail;
  311. printf("==========Snake==========\n");
  312. for(k=0;k<S.snake_long;k++)
  313. {
  314. printf("i=%d j=%d\n",tp->i,tp->j);
  315. tp=tp->p;
  316. }
  317. printf("==========Food===========\n");
  318. printf("i=%d j=%d\n",F.i,F.j);
  319. }
  320. int main()
  321. {
  322. int life=1;
  323. Snake S;
  324. Food F;
  325. SDL_Event event;
  326. Init();
  327. Produce_Food(&F);
  328. Produce_Snake(&S);
  329. Game_start();
  330. Game_background();
  331. while(life)
  332. {
  333. Game_background();
  334. Draw_Food(F);
  335. Draw_Snake(S);
  336. Draw_Score(S);
  337. SDL_Delay (300);
  338. while (SDL_PollEvent (&event))
  339. {
  340. switch (event.type)
  341. {
  342. case SDL_QUIT:
  343. life = 0;
  344. break;
  345. case SDL_KEYDOWN:
  346. Change_Snake_Direction(event,&S);
  347. break;
  348. default:;
  349. }
  350. }
  351. Move_Snake(&S);
  352. if(S.head->i==F.i&&S.head->j==F.j)
  353. {
  354. Add_Snake_Node(&S);//Test(S,F);
  355. Produce_Food(&F);
  356. }
  357. Judge_life(S,&life);
  358. }
  359. Game_end();
  360. getchar();
  361. return 0;
  362. }

具體的源代碼下載

下載在Linux公社的1號FTP服務器裡,下載地址:

FTP地址:ftp://www.linuxidc.com

用戶名:www.linuxidc.com

密碼:www.muu.cc

在 2012年LinuxIDC.com\7月\《貪吃蛇游戲》項目實作【附代碼】

下載方法見 http://www.linuxidc.net/thread-1187-1-1.html

(四)操作(CDIO中的O)

至於操作嘛,我還真不知一個軟件有什麼好操作的,也許是��維吧,在前面我也已經展現出了運行的照片了,也就沒啥好說了。不過有點體會倒是很深,那就是一定要一定要海讀有質量的源代碼~~

Copyright © Linux教程網 All Rights Reserved