C + SDL 貪喫蛇的基礎實現

說明一下:目前實現了 時間顯示、碰撞、蛇身的增加 、轉向。剩下的就是障礙的出現還有地圖的設置。這些就留給朋友們自己發揮創意了。

總共分四個文件。 貪喫蛇頭文件、時間顯示頭文件、常用設置頭文件還有主函數文件。

//SNake.h
//貪喫蛇頭文件
/******************** 常量定義區 *******************/

//一個節點的寬
#define FTB_W 27
//一個節點的高
#define FTB_H 27

//蛇的最大長度
#define SK_MAX 15


/******************* 表面定義區 ********************/

//節點
SDL_Surface *fc_ftb = NULL;

/******************* 全局變量聲明區 *********************/

//足球兩種狀態的座標
struct point football[2] = {{0,0}, {0,27}};

//當前蛇的長度
unsigned int body_length = 0;
//蛇身的組
struct object body_list[SK_MAX];


/******************* 函數定義區 ********************/

//初始化蛇的節點表面
void Init_Snake(char *pic)
{
     fc_ftb = IMG_Load(pic);
     if(fc_ftb == NULL)   printf("Error[Init_Snake()]:Init snake failed!/n");
}

//蛇的圖片變換
void ChangPic()
{
     for(int i = body_length-1; i > 0; i--)
     {
         if(body_list[i].seq == 1)  body_list[i].seq = 0;
                else body_list[i].seq = 1;
         body_list[i].xs = football[body_list[i].seq].xpos;
         body_list[i].ys = football[body_list[i].seq].ypos;          
     }
}

//增加節點
void AddNode()
{
      body_list[body_length].seq = 0;
     body_length++;
}

//蛇頭可否轉向的判定 0不可轉
int CanTurn(struct object *head, int direction)
{
    if(head->direction == 1 || head->direction == 2)
    switch(direction)
    {
     case 1:
            break;
     case 2:
            break;
     case 3:
            head->direction = 3;
            return 3;
     case 4:
            head->direction = 4;        
            return 4;
     default:
            break;                       
    }
   
    if(head->direction == 3 || head->direction == 4)
    switch(direction)
    {
     case 1:
            head->direction = 1;
            return 1;
     case 2:
            head->direction = 2;
            return 2;
     case 3:
            break;
     case 4:
            break;
     default:
            break;                       
    }
    return 0;
}

//獲得鍵盤
void GetKey(struct object *body)
{
     Uint8 *keys = SDL_GetKeyState(NULL);
     int LEFT = 1, RIGHT = 2, UP = 3, DOWN = 4;
    
     if(keys[SDLK_DOWN])
         CanTurn(body,DOWN);
     else if(keys[SDLK_UP])
        CanTurn(body,UP);
        else if(keys[SDLK_LEFT])
             CanTurn(body,LEFT);
             else if(keys[SDLK_RIGHT])
                 CanTurn(body,RIGHT);
}
         


//蛇的身體的移動
void BodyMove(struct object *body)
{
     struct object temp = body_list[body_length-1];
     for(int i = body_length-1; i > 0; i--)
     {
         body_list[i].xpos = body_list[i-1].xpos;
         body_list[i].ypos = body_list[i-1].ypos;
         body_list[i].direction = body_list[i-1].direction;
         body_list[i].src_s = body_list[i-1].src_s;
         body_list[i].width = body_list[i-1].width;
         body_list[i].height = body_list[i-1].height;
         body_list[i].xs = body_list[i-1].xs;
         body_list[i].ys = body_list[i-1].ys;
         body_list[i].state = body_list[i-1].state;
         body_list[i].seq = body_list[i-1].seq;
         DrawFraise(body_list[i],back);
     }
         
     if(body[0].direction == 1) body[0].xpos -= MOVE_LTH;
     else if(body[0].direction == 2) body[0].xpos += MOVE_LTH;
          else if(body[0].direction == 3) body[0].ypos -= MOVE_LTH;
               else if(body[0].direction == 4) body[0].ypos += MOVE_LTH;
     DrawFraise(body_list[0],back);
     DrawIMG(back,temp.width,temp.height,temp.xpos,temp.ypos,screen,temp.xpos,temp.ypos);             
}

 

// STime.h
//時間顯示頭文件


/******************** 常量定義區 *******************/

//數字寬
#define NUM_W 16
//數字高
#define NUM_H 20

//框寬
#define FRAME_W 82
//框高
#define FRAME_H 22


/******************* 表面定義區 ********************/

//數字
SDL_Surface *fc_num = NULL;
//數字框
SDL_Surface *fc_tframe = NULL;


/******************* 結構體聲明區 *********************/

//各數字的座標
struct point num[10] = {
            {2,4}, {22,4}, {42,4}, {62,4}, {82,4}, {102,4}, {122,4}, {142,4}, {162,4}, {182,4}
            };
           
struct object o_number;
struct object o_frame;           
           
/******************* 函數定義區 ********************/

//初始化函數
//第三,四個參數是 時間框 出線的座標
void Init_stime(char *num, char *frame, int x, int y)
{
     fc_num = IMG_Load(num);
     fc_tframe = IMG_Load(frame);
     SDL_SetColorKey(fc_num, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(fc_num->format, 255, 0, 255));
     ObjectEva(&o_number,0,0,NUM_H,NUM_W,2,fc_num,0,0,0,0);
     ObjectEva(&o_frame,x,y,FRAME_H,FRAME_W,2,fc_tframe,0,0,0,0);    
}

//生成時間表面
void showtime(Uint32 time,struct object src,struct object aim,struct point *num)
{
     unsigned int mins1;
     unsigned int mins2;
     unsigned int seds1;
     unsigned int seds2;
    
     unsigned int tempm = time / 60;
     unsigned int temps = time % 60;
    
     mins1 = tempm / 10;
     mins2 = tempm % 10;
     seds1 = temps / 10;
     seds2 = temps % 10;  
    
     Slock(screen);
     DrawIMG(aim.src_s,aim.width,aim.height,0,0,screen,aim.xpos,aim.ypos);   
     DrawIMG(src.src_s,src.width,src.height,num[mins1].xpos,num[mins1].ypos,screen,aim.xpos+1,aim.ypos+1);
     DrawIMG(src.src_s,src.width,src.height,num[mins2].xpos,num[mins2].ypos,screen,aim.xpos+17,aim.ypos+1);
     DrawIMG(src.src_s,src.width,src.height,num[seds1].xpos,num[seds1].ypos,screen,aim.xpos+49,aim.ypos+1);
     DrawIMG(src.src_s,src.width,src.height,num[seds2].xpos,num[seds2].ypos,screen,aim.xpos+65,aim.ypos+1);
     Sulock(screen);
}

 

//SCommon.h
//常用設置頭文件

/******************** 常量定義區 *******************/

//窗口的寬
#define X_LENGTH 640
//窗口的高
#define Y_LENGTH 480
//顯示的顏色位數
#define SCREEN_BPP  32
//移動的步長
#define MOVE_LTH 30
//每幀的時長
#define TICK_INTERVAL 100


/******************* 結構體定義區 *********************/

//點
struct point{
         int xpos;
         int ypos;
         };
        
//遊戲裏的各種物體
struct object{
       //座標      
          int xpos;
          int ypos;
       //寬高  
          unsigned int height;
          unsigned int width;
       //方向(1左,2右,3上,4下)
          unsigned int direction;  
       //源表面
          SDL_Surface *src_s;
       //源圖塊座標
          unsigned int xs;
          unsigned int ys;
       //上一個狀態[暫時用作存儲本節點需要判定的事件序列]:
          unsigned int state;
       //移動序列
          unsigned int seq; 
       };

/******************* 表面定義區 ********************/
 
//背景
SDL_Surface *back = NULL;
//屏幕(我們所有的圖都貼在這個表面上,然後刷他)
SDL_Surface *screen = NULL;


/******************* 函數定義區 ********************/

//鎖表面
void Slock(SDL_Surface *screen)
{
 if ( SDL_MUSTLOCK(screen) )
   if ( SDL_LockSurface(screen) < 0 )  return;
}

//解鎖表面
void Sulock(SDL_Surface *screen)
{
 if ( SDL_MUSTLOCK(screen) )
    SDL_UnlockSurface(screen);
}

//投影直線重合判定: 1重合; 0不重合
int Line_touch(int ax1, int ax2, int bx1, int bx2)
{
    if(ax2 <= bx1) return 0;
    if(ax1 >= bx2) return 0;
    return 1;
}      
      
//判定觸碰
int  Touch(struct object pusher, struct object box)
{
     int  p_x1  =   pusher.xpos;
     int  p_x2  =   pusher.xpos + pusher.width;
     int  p_y1  =   pusher.ypos;
     int  p_y2  =   pusher.ypos + pusher.height;
         
     int  b_x1  =   box.xpos;
     int  b_x2  =   box.xpos + box.width;
     int  b_y1  =   box.ypos;
     int  b_y2  =   box.ypos + box.height;
         
     if(Line_touch(p_x1,p_x2,b_x1,b_x2) == 0) return 0;
     if(Line_touch(p_y1,p_y2,b_y1,b_y2) == 0) return 0;
     return 1;
     }

//邊界判定  1111 分別是左右上下
int  Border(struct object const obj)
{
     int  o_left   =   obj.xpos;
     int  o_right  =   obj.xpos + obj.width;
     int  o_top    =   obj.ypos;
     int  o_bottom =   obj.ypos + obj.height;
         
     int result = 0;
         
     if(o_left < 0) result += 1;
     if(o_right > X_LENGTH )  result += 10;
     if(o_top < 0) result +=100;
     if(o_bottom > Y_LENGTH ) result += 1000;
     return result;
}

//封裝後的貼圖函數【子函數】
void DrawIMG(SDL_Surface *src, int w, int h, int x, int y, SDL_Surface *aim, int x2, int y2)
{
     SDL_Rect a;
     a.x = x;
     a.y = y;
     a.w = w;
     a.h = h;
    
     SDL_Rect b;
     b.x = x2;
     b.y = y2;

     SDL_BlitSurface(src, &a, aim, &b);
}

//貼背景
void DrawBG(SDL_Surface *bg)
{
     SDL_Rect dest;
     dest.x = 0;
     dest.y = 0;
    
     Slock(screen);
     SDL_BlitSurface(bg,NULL,screen,&dest);
     Sulock(screen);
}

//貼靜態物體[障礙物]
void DrawFraise(struct object const obj, SDL_Surface *background)
{
     Slock(screen);             
     DrawIMG(obj.src_s, obj.width, obj.height, obj.xs, obj.ys, screen, obj.xpos, obj.ypos);
     Sulock(screen);
}

//貼動態圖像
void DrawScene(struct object const obj, SDL_Surface *background)
{
 switch(obj.direction)
 {
  case 1 : //左
          Slock(screen);            
          //補充背景
          DrawIMG(background, obj.width + MOVE_LTH, obj.height, obj.xpos, obj.ypos, screen, obj.xpos, obj.ypos);
          //畫移動物體
          DrawIMG(obj.src_s, obj.width, obj.height, obj.xs, obj.ys, screen, obj.xpos, obj.ypos);
          Sulock(screen);
          break;
  case 2 : //右
          Slock(screen);            
          DrawIMG(background, obj.width + MOVE_LTH, obj.height, obj.xpos - MOVE_LTH, obj.ypos, screen, obj.xpos - MOVE_LTH, obj.ypos);
          DrawIMG(obj.src_s, obj.width, obj.height, obj.xs, obj.ys, screen, obj.xpos, obj.ypos);
          Sulock(screen);
          break;
  case 3 : //上
          Slock(screen);            
          DrawIMG(background, obj.width, obj.height + MOVE_LTH, obj.xpos, obj.ypos, screen, obj.xpos, obj.ypos);
          DrawIMG(obj.src_s, obj.width, obj.height, obj.xs, obj.ys, screen, obj.xpos, obj.ypos);
          Sulock(screen);
          break;
  case 4 : //下
          Slock(screen);            
          DrawIMG(background, obj.width, obj.height + MOVE_LTH, obj.xpos, obj.ypos - MOVE_LTH, screen, obj.xpos, obj.ypos - MOVE_LTH);
          DrawIMG(obj.src_s, obj.width, obj.height, obj.xs, obj.ys, screen, obj.xpos, obj.ypos);
          Sulock(screen);
          break;
  default:
          printf("Error:please use correct function to deal the Draw!/n");
 }  
}

//返回每幀剩餘時長
Uint32 TimeLeft()
{
 static Uint32 next_time = 0;
 Uint32 now;
 now = SDL_GetTicks();
 if ( next_time <= now )
  {
   next_time = now+TICK_INTERVAL;
   return(0);
  }
 return(next_time-now);
}

//測試函數,返回當前物件的座標
void TestPrint(char *name, struct object obj)
{
     printf("Object %s:(%d,%d) height(%d) width(%d)  direction(%d)/n",
     name,obj.xpos,obj.ypos,obj.height,obj.width,obj.direction);
}

//給結構體object賦值的函數
void ObjectEva(struct object *obj, int xpos, int ypos, unsigned int height, unsigned int width,
                      unsigned int direction, SDL_Surface *src_s, unsigned int xs, unsigned int ys,
                               unsigned int state, unsigned int seq)
{
     obj->xpos = xpos;
     obj->ypos = ypos;
     obj->height = height;
     obj->width = width;
     obj->direction = direction;  
     obj->src_s = src_s;
     obj->xs = xs;
     obj->ys = ys;
     obj->state = state;
     obj->seq = seq;                                                          
}

//初始化背景
void Init_Scommon(char *pic)
{
     back = IMG_Load(pic);
     if(back == NULL)   printf("Error[Init_Scommon()]:Init backgroud failed!/n");
     DrawBG(back);
}

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"

#include "SCommon.h"
#include "STime.h"
#include "SNake.h"


////  主函數   /////
////           /////

int main(int argc, char *argv[])
{
    //標準輸出重定向
     freopen( "G://MY test//SNAKE//image//log.txt", "w", stdout );
    
    //putenv("SDL_VIDEODRIVER=directx");
   
    //初始化SDL 
    if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 )
    {
         printf("Unable to init SDL: %s/n", SDL_GetError());
         exit(1);
    }
 
    atexit(SDL_Quit);
 
    //設置視頻(顯示)
    screen=SDL_SetVideoMode(X_LENGTH,Y_LENGTH,SCREEN_BPP,SDL_HWSURFACE|SDL_DOUBLEBUF);
    if ( screen == NULL )
    {
         printf("Unable to set 640x480 video: %s/n", SDL_GetError());
         exit(1);
    }
   
    //設置窗口的名稱
    SDL_WM_SetCaption( "Carton", NULL );

    //初始化背景和時間
    Init_Scommon("G://MY test//SNAKE//image//back.bmp");
    Init_stime("G://MY test//SNAKE//image//number.bmp","G://MY test//SNAKE//image//frame.png",500,0);
    Init_Snake("G://MY test//SNAKE//image//football.png");
   
    //蛇頭
    ObjectEva(&body_list[0],30,54,FTB_H,FTB_W,2,fc_ftb,football[0].xpos,football[0].ypos,0,0);
    body_length = 1;

    //DrawScene(body_list[0],back);
   
    int test = 0;
    //main game loop begin
    int done=0;
    while(done == 0)
    {
        SDL_Event event;

        while ( SDL_PollEvent(&event) )
        {
              if ( event.type == SDL_QUIT ) { done = 1; }

              if ( event.type == SDL_KEYDOWN )
              {
                   if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; }
              } 
        }
        Uint32 cur_time = SDL_GetTicks()/1000;
        showtime(cur_time,o_number,o_frame,num);
        //輸入轉換
        GetKey(body_list);

        //動作
        if(test == cur_time)
        {
            if(cur_time % 3 == 0)   
            AddNode();   
            ChangPic();
            BodyMove(body_list);
        }
        test=cur_time+1;
        SDL_Flip(screen);
        SDL_Delay(TimeLeft());
        if(Border(body_list[0]) > 0) return -1;
    }
    //main game loop end
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章