说明一下:目前实现了 时间显示、碰撞、蛇身的增加 、转向。剩下的就是障碍的出现还有地图的设置。这些就留给朋友们自己发挥创意了。
总共分四个文件。 贪吃蛇头文件、时间显示头文件、常用设置头文件还有主函数文件。
//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
#include
#include
#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
}