突發奇想:
最近又得開始忙著復習考試了,整天都是看PPT,啃課本,做習題,無聊加煩惱。手癢,想敲代碼,又怕上瘾耽誤了考試,所以就想著拿個小程序來練練手,以解煩悶。正在做視頻監控,對SDL有點了解,所以就它了!而且它是跨平台的,方便在linux下玩弄。做個什麼好呢?就來個QQ表情版的貪吃蛇好了,我覺得做出來會很搞笑的。說干就干,這篇blog就是在這種沖動下寫的,嘻嘻嘻~~為了寫好這篇blog,我決定使用我們學校整天吹噓的CDIO理念來組織文章,所以這對我又是一個有意思的挑戰。好了,廢話不多說,哥開始了……
(一)構思(CDIO中的C)
QQ表情版的貪吃蛇使用QQ經典表情來充當蛇身和食物的,其中頭像當蛇身,其他的當食物。這些表情是按照一定順序來出來的,也許可以使用循環數組的方法實現之~~至於游戲規則就沒什麼好講的了,就是前後左右鍵盤響應控制蛇身方向,食物隨機位置出現,蛇身吃完食物後蛇身便長長一節,分數便增加一分。
(二)設計(CDIO中的D)
關鍵部分就是蛇的移動,我把整條蛇設計成一條單向循環鏈表,並且是逆向的,即從蛇尾蛇一直指向蛇頭,再從蛇頭指回蛇尾,當蛇移動時,只要把蛇頭指針向前移動一節(即蛇尾,移動之前已經將其改為新蛇頭),同時蛇尾指針也向向前移動一節(即次蛇尾),而中間部分的蛇節點的結構體不需要改變,這樣用戶就會感覺是蛇在移動。
次關鍵部分就是蛇的增長,當蛇頭吃到食物之後,就根據舊蛇的蛇尾記錄產生新的節點,然後插到蛇尾即可
是不是很簡單啊!!那接下來開始實現吧~~
(三)實現(CDIO中的I)
- #include<stdio.h>
-
- #include<stdlib.h>
-
- #include <SDL/SDL.h>
-
- #include <SDL/SDL_image.h>
-
- #include <SDL/SDL_ttf.h>
-
-
-
- #define down 1
-
- #define left 2
-
- #define right 3
-
- #define up 4
-
-
-
- SDL_Surface *screen;
-
- SDL_Surface *start_background;
-
- SDL_Surface *run_backgound;
-
- SDL_Surface *snake_node;
-
- SDL_Surface *food;
-
- SDL_Surface *score;
-
-
-
- SDL_Rect dst;
-
- SDL_Color color;
-
- TTF_Font *font;
-
- char str[10];
-
-
-
- /*蛇節點*/
-
- typedef struct Body_Node{
-
- int i,j;//坐標
-
- struct Body_Node *p;//指向下一蛇節點
-
- }Body_Node;
-
-
- /*蛇*/
-
- typedef struct Snake{
-
- Body_Node *head,*tail;//蛇頭蛇尾指針
- Body_Node tail_record;//舊蛇蛇尾記錄(吃東西時用到)
-
- int snake_long;//蛇身長度
-
- int direction;//蛇頭方向
-
- }Snake;
-
-
- /*食物*/
-
- typedef struct Food{
-
- int i,j;//坐標
-
- int num;//圖片編號
-
- }Food;
-
-
-
- SDL_Surface *LoadIMG(const char *name)
-
- {
-
- SDL_Surface *tmp, *final;
-
- if ((tmp = IMG_Load (name)) == NULL)
-
- fprintf (stderr, "load %s error\n", name);
-
- final = SDL_DisplayFormat (tmp);
-
- SDL_FreeSurface (tmp);
-
- SDL_SetColorKey (final, SDL_SRCCOLORKEY | SDL_RLEACCEL,*(Uint32 *) final->pixels);
-
- return final;
-
- }
-
-
- /*初始化*/
-
- void Init()
-
- {
-
- if ((SDL_Init (SDL_INIT_AUDIO | SDL_INIT_VIDEO)) < 0)
-
- fprintf (stderr, "init error\n");
-
- if ((screen = SDL_SetVideoMode (720, 720, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
-
- fprintf (stderr, "set video mode error\n");
-
- if (TTF_Init() < 0)
-
- fprintf(stderr, "TTF init error:%s\n", SDL_GetError());
-
- atexit (SDL_Quit);
-
- SDL_WM_SetCaption ("Greed Snake", NULL);
-
- srand (time (NULL));
-
- run_backgound = LoadIMG ("background.png");
-
- start_background = LoadIMG ("start.jpg");
-
- }
-
-
- /*繪畫游戲開始界面*/
-
- void Game_start()
-
- {
-
- int i,j;
-
- int temp=30;
-
- int x=0, y=0;
-
- int num=0;
-
- int flag=0;
-
-
-
- dst.x = 0;//繪畫游戲開始界面的背景
-
- dst.y = 0;
-
- dst.w = start_background->w;
-
- dst.h = start_background->h;
-
- SDL_BlitSurface (start_background, NULL, screen, &dst);
-
- SDL_UpdateRects (screen, 1, &dst);
-
-
-
- for(i=1; i<=31;)//繪畫游戲開始界面的動畫
-
- {
-
- for(j=1; j<= temp; j++)
-
- {
-
- snprintf(str, 10, "%d.gif", num);//繪畫一個QQ表情
-
- start_background = LoadIMG (str);
-
- SDL_Delay (15);
-
- dst.x = x;
-
- dst.y = y;
-
- dst.w = start_background->w;
-
- dst.h = start_background->h;
-
- SDL_BlitSurface (start_background, NULL, screen, &dst);
-
- SDL_UpdateRects (screen, 1, &dst);
-
-
-
- num = (num+1)%82;//QQ表情圖片的編號控制在0到81
- /*設置一個flag,動畫時,分別有(1)x軸遞增,y軸不變;(2)x軸不變,y軸遞減;(3)x軸遞減,y軸不變;(4)x軸不變,y軸遞增;四種狀態*/
-
- switch(flag)
-
- {
-
- case 0:x += 24;break;
-
- case 1:y += 24;break;
-
- case 2:x -= 24;break;
-
- case 3:y -= 24;break;
-
- }
-
- }
-
- i++;
-
- temp = (32-i)-(31-i)%2;//每畫一條邊時,控制需要繪畫的QQ表情個數
-
- switch(flag)//坐標超出屏幕,需要回溯
-
- {
-
- case 0:{x -= 24;y += 24;}break;
-
- case 1:{x -= 24;y -= 24;}break;
-
- case 2:{x += 24;y -= 24;}break;
-
- case 3:{x += 24;y += 24;}break;
-
- }
-
- flag = (flag+1)%4;//flag控制在0到3
-
- }
-
- }
-
-
- /*繪畫游戲進行時背景,即“QQ聊天窗口”*/
-
- void Game_background()
-
- {
-
- dst.x = 0;//設置目標邊框dst(x=0,y=0,width=w,height=h)
-
- dst.y = 0;
-
- dst.w = run_backgound->w;
-
- dst.h = run_backgound->h;
-
- SDL_BlitSurface (run_backgound, NULL, screen, &dst);//copy到主窗口(screen)上
-
- SDL_UpdateRects (screen, 1, &dst);//局部更新主窗口
-
- }
-
-
- /*繪畫游戲結束時的提示,即“GameOver”*/
-
- void Game_end()
-
- {
-
- font = TTF_OpenFont("test.ttf", 100);//設置字體樣式與大小
-
- color.r = 255;
-
- color.g = 0;
-
- color.b = 0;
-
- score=TTF_RenderText_Solid(font, "Game Over", color);
-
-
-
- dst.x = 150;
-
- dst.y = 350;
-
- dst.w = score->w;
-
- dst.h = score->h;
-
- SDL_BlitSurface(score, NULL, screen, &dst);
-
- SDL_UpdateRects (screen, 1, &dst);
-
- }
-
-
- /*繪畫游戲進行時分數*/
-
- void Draw_Score(Snake S)
-
- {
-
- snprintf(str, 10, "%d", S.snake_long);
-
- font = TTF_OpenFont("test.ttf", 15);
-
- color.r = 0;
-
- color.g = 0;
-
- color.b = 255;
-
- score=TTF_RenderText_Solid(font, str, color);
-
-
-
- dst.x = 278;
-
- dst.y = 122;
-
- dst.w = score->w;
-
- dst.h = score->h;
-
- SDL_BlitSurface(score, NULL, screen, &dst);
-
- SDL_UpdateRects (screen, 1, &dst);
-
- }
-
-
- /*繪畫食物*/
-
- void Draw_Food(Food F)
-
- {
-
- snprintf(str, 10, "%d.gif", F.num);
-
- food = LoadIMG (str);
-
- dst.x = F.i*24;
-
- dst.y = F.j*24+210;
-
- dst.w = food->w;
-
- dst.h = food->h;
-
- SDL_BlitSurface (food, NULL, screen, &dst);
-
- SDL_UpdateRects (screen, 1, &dst);
-
- }
-
-
- /*繪畫蛇*/
-
- void Draw_Snake(Snake S)
-
- {
-
- int k;
- int num;
-
- Body_Node *tp;
-
-
-
- tp=S.head;
-
- for(num=k=0;k<S.snake_long;k++,num=(num+1)%65)
-
- {
-
- snprintf(str, 10, "%d.gif", num);
-
- snake_node = LoadIMG (str);
-
- dst.x = tp->i*24;
-
- dst.y = tp->j*24+210;
-
- dst.w = snake_node->w;
-
- dst.h = snake_node->h;
-
- SDL_BlitSurface (snake_node, NULL, screen, &dst);
-
- SDL_UpdateRects (screen, 1, &dst);
-
- tp=tp->p;
-
- SDL_FreeSurface(snake_node);
-
- }
-
- }
-
-
- /*生產食物*/
-
- void Produce_Food(Food *F)
-
- {
-
- time_t t;
-
- int i,j;
-
- srand((unsigned)time(&t));
-
- F->i=(rand()%29);
-
- F->j=(rand()%20);
-
- F->num=(rand()%16)+65;
-
- }
-
-
- /*生產蛇,最初為2節*/
-
- void Produce_Snake(Snake *S)
-
- {
-
- Body_Node *temp;
-
- temp=(Body_Node *)malloc(sizeof(Body_Node));
-
- temp->i=4;
-
- temp->j=3;
-
- S->tail=temp;
-
- temp=(Body_Node *)malloc(sizeof(Body_Node));
-
- temp->i=5;
-
- temp->j=3;
-
- S->head=temp;
-
- S->tail->p=S->head;
-
- S->head->p=S->tail;
-
- S->snake_long=2;
-
- S->direction=right;
- S->tail_record.i=-1;
- S->tail_record.j=-1;
- S->tail_record.p=NULL;
-
- }
-
-
- /*移動蛇身*/
-
- void Move_Snake(Snake *S)
-
- {
-
- S->tail_record.i=S->tail->i;
- S->tail_record.j=S->tail->j;
- /*根據蛇的方向把蛇尾節點當新的蛇頭節點,我把整條蛇設計成一個單向循環鏈表*/
- switch(S->direction)
-
- {
-
- case left:{
-
- S->tail->i=S->head->i-1;
-
- S->tail->j=S->head->j;
-
- break;
-
- }
-
- case down:{
-
- S->tail->i=S->head->i;
-
- S->tail->j=S->head->j+1;
-
- break;
-
- }
-
- case right:{
-
- S->tail->i=S->head->i+1;
-
- S->tail->j=S->head->j;
-
- break;
-
- }
-
- case up:{
-
- S->tail->i=S->head->i;
-
- S->tail->j=S->head->j-1;
-
- break;
-
- }
-
- }
-
- S->head=S->tail;
-
- S->tail=S->tail->p;
-
- }
-
-
- /*根據鍵盤響應改變蛇的方向*/
-
- void Change_Snake_Direction(SDL_Event event,Snake *S)
-
- {
-
- switch(event.key.keysym.sym)
-
- {
-
- case SDLK_LEFT:
-
- if(S->direction!=right)
-
- S->direction=left;
-
- break;
-
- case SDLK_DOWN:
-
- if(S->direction!=up)
-
- S->direction=down;
-
- break;
-
- case SDLK_RIGHT:
-
- if(S->direction!=left)
-
- S->direction=right;
-
- break;
-
- case SDLK_UP:
-
- if(S->direction!=down)
-
- S->direction=up;
-
- break;
-
- default:;
-
- }
-
- }
-
-
- /*當吃到食物時,增長蛇身*/
-
- void Add_Snake_Node(Snake *S)
-
- {
-
- Body_Node *tp;
-
- tp=(Body_Node *)malloc(sizeof(Body_Node));
- tp->i=S->tail_record.i;
- tp->j=S->tail_record.j;
-
- tp->p=S->tail;
-
- S->head->p=tp;
- S->tail=tp;
-
- S->snake_long++;
-
- }
-
-
- /*判斷蛇是否存活*/
-
- void Judge_life(Snake S,int *life)
-
- {
-
- int k;
-
- Body_Node *tp=S.tail;
-
- for(k=S.snake_long;k>=5;k--,tp=tp->p)//判斷是否撞到自己的身體,只有5節蛇身才會出現此問題
-
- {
-
- if(S.head->i==tp->i&&S.head->j==tp->j)
-
- {
-
- *life=0;
-
- break;
-
- }
-
- }
-
- if(S.head->i<0||S.head->i>28)//判斷蛇頭是否撞到牆壁
-
- {
-
- *life=0;
-
- }
-
- else if(S.head->j<0||S.head->j>19)
-
- {
-
- *life=0;
-
- }
-
- }
-
-
- /*測試用的,方便調試*/
- void Test(Snake S,Food F)
- {
- Body_Node *tp;
- int k;
-
- tp=S.tail;
- printf("==========Snake==========\n");
- for(k=0;k<S.snake_long;k++)
- {
- printf("i=%d j=%d\n",tp->i,tp->j);
- tp=tp->p;
- }
- printf("==========Food===========\n");
- printf("i=%d j=%d\n",F.i,F.j);
- }
-
-
- int main()
-
- {
-
- int life=1;
-
- Snake S;
-
- Food F;
-
- SDL_Event event;
-
-
-
- Init();
-
- Produce_Food(&F);
-
- Produce_Snake(&S);
-
- Game_start();
-
- Game_background();
-
- while(life)
-
- {
-
- Game_background();
-
- Draw_Food(F);
-
- Draw_Snake(S);
-
- Draw_Score(S);
-
- SDL_Delay (300);
-
- while (SDL_PollEvent (&event))
-
- {
-
- switch (event.type)
-
- {
-
- case SDL_QUIT:
-
- life = 0;
-
- break;
-
- case SDL_KEYDOWN:
-
- Change_Snake_Direction(event,&S);
-
- break;
-
- default:;
-
- }
-
- }
-
- Move_Snake(&S);
-
- if(S.head->i==F.i&&S.head->j==F.j)
-
- {
-
- Add_Snake_Node(&S);//Test(S,F);
-
- Produce_Food(&F);
-
- }
-
- Judge_life(S,&life);
-
- }
-
- Game_end();
-
- getchar();
-
- return 0;
-
- }
具體的源代碼下載
下載在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)
至於操作嘛,我還真不知一個軟件有什麼好操作的,也許是��維吧,在前面我也已經展現出了運行的照片了,也就沒啥好說了。不過有點體會倒是很深,那就是一定要一定要海讀有質量的源代碼~~