《QQ表情版贪吃蛇游戏》项目实作【附代码】
《QQ表情版贪吃蛇游戏》项目实作【附代码】
突发奇想:
最近又得开始忙着复习考试了,整天都是看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;
- }
具体的源代码下载
下载在帮客之家的1号FTP服务器里,下载地址:
FTP地址:ftp://www.bkjia.com
用户名:www.bkjia.com
密码:www.muu.cc
在 2012年LinuxIDC.com\7月\《贪吃蛇游戏》项目实作【附代码】
下载方法见 http://www.bkjia.net/thread-1187-1-1.html
(四)操作(CDIO中的O)
至于操作嘛,我还真不知一个软件有什么好操作的,也许是运维吧,在前面我也已经展现出了运行的照片了,也就没啥好说了。不过有点体会倒是很深,那就是一定要一定要海读有质量的源代码~~
评论暂时关闭