說明一下:目前實現了 時間顯示、碰撞、蛇身的增加 、轉向。剩下的就是障礙的出現還有地圖的設置。這些就留給朋友們自己發揮創意了。
總共分四個文件。 貪喫蛇頭文件、時間顯示頭文件、常用設置頭文件還有主函數文件。
//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
}