突发奇想:最近又得开始忙着复习考试了,整天都是看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
", 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
");
-
- if ((screen = SDL_SetVideoMode (720, 720, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
-
- fprintf (stderr, "set video mode error
");
-
- if (TTF_Init() < 0)
-
- fprintf(stderr, "TTF init error:%s
", 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==========
");
- for(k=0;k<S.snake_long;k++)
- {
- printf("i=%d j=%d
",tp->i,tp->j);
- tp=tp->p;
- }
- printf("==========Food===========
");
- printf("i=%d j=%d
",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.com7月《贪吃蛇游戏》项目实作【附代码】下载方法见 http://www.linuxidc.net/thread-1187-1-1.html(四)操作(CDIO中的O)至于操作嘛,我还真不知一个软件有什么好操作的,也许是??维吧,在前面我也已经展现出了运行的照片了,也就没啥好说了。不过有点体会倒是很深,那就是一定要一定要海读有质量的源代码~~