⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 game.c

📁 linux下编的简单游戏,类似于是男人就撑过20秒
💻 C
字号:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>                              //需要产生随机数,加载时间头文件
#include "SDL.h"
#ifdef macintosh
#define DIR_SEP ":"
#define DIR_CUR ":"
#else
#define DIR_SEP "/"
#define DIR_CUR ""
#endif
#define DATAFILE(X) DIR_CUR "data" DIR_SEP X
#define FRAMES_PER_SEC  10                   //每秒钟的帧数
#define PLANE_SPEED 8                    //飞机运动速度
#define MAX_SHOTS   2                       //最多可以发射多少发激光
#define SHOT_SPEED  20                       //激光的速度
#define MAX_BOMBS 10                         //最多出现多少枚炮弹
#define BOMB_SPEED_X  8                        //炮弹的x速度
#define BOMB_SPEED_Y  8 
#define BOMB_ODDS (1*FRAMES_PER_SEC)  //剩下的炮弹数
#define EXPLODE_TIME  4 //爆炸时间

SDL_Rect dst;
int shoot_bomb_num=0; 
struct timeval tv1,tv2,tz;
typedef struct {  //对象结构体
  int alive;  //是否存活标志
  int facing;   //运动方向
  int x, y; //坐标
  SDL_Surface *image;   //图像指针
} object; 
SDL_Surface *screen;  //屏幕指针
SDL_Surface *background;  //背景指针
SDL_Surface *gameover;
object plane; //飞机对象
int reloading;  //重新加载标志
object shots[MAX_SHOTS];  //激光对象
object bombs[MAX_BOMBS];  //炮弹对象
object explosions[MAX_BOMBS+1]; //爆炸对象
#define MAX_UPDATES 3*(1+MAX_SHOTS+MAX_BOMBS) //最大更新次数
int numupdates; //更新次数的变量
SDL_Rect srcupdate[MAX_UPDATES];  //源目标更新
SDL_Rect dstupdate[MAX_UPDATES];  //目标更新
struct blit { //定义快速重绘对象结构体
  SDL_Surface *src;
  SDL_Rect *srcrect;
  SDL_Rect *dstrect;
} blits[MAX_UPDATES];

SDL_Surface *LoadImage(char *datafile)  //加载图片函数
{
  SDL_Surface *image, *surface;
  image = SDL_LoadBMP(datafile);  //用SDL_LoadBMP()函数加载图片
  if ( image == NULL ) {
    fprintf(stderr, "Couldn't load image %s: %s\n",
          datafile,SDL_GetError());
    return(NULL);
  }
  surface = SDL_DisplayFormat(image);   //用图片的形式显示
  SDL_FreeSurface(image);   //释放图片
  return(surface);
}
int LoadData(void)  //加载数据
{
  int i;
  plane.image = LoadImage(DATAFILE("plane.bmp")); //加载飞机图片
  if ( plane.image == NULL ) {
    return(0);
  }

  shots[0].image = LoadImage(DATAFILE("shot.bmp")); //加载激光图片
  if ( shots[0].image == NULL ) {
    return(0);
  }
  for ( i=1; i<MAX_SHOTS; ++i ) {
    shots[i].image = shots[0].image;
  }

  bombs[0].image = LoadImage(DATAFILE("bomb.bmp"));   //加载炮弹图片
  if ( bombs[0].image == NULL ) {
    return(0);
  }
  for ( i=1; i<MAX_BOMBS; ++i ) {
    bombs[i].image = bombs[0].image;
  }

  explosions[0].image = LoadImage(DATAFILE("explosion.bmp"));//加载爆炸图片
  for ( i=1; i<MAX_BOMBS+1; ++i ) {
    explosions[i].image = explosions[0].image;
  }
  background = LoadImage(DATAFILE("background.bmp"));//加载背景图片
  gameover = LoadImage(DATAFILE("gameover.bmp"));
  //设置更新目标矩形的指针
  for ( i=0; i<MAX_UPDATES; ++i ) {
    blits[i].srcrect = &srcupdate[i];
    blits[i].dstrect = &dstupdate[i];
  }
  return(1);
}

void FreeData(void) //释放数据
{
  int i;
  SDL_FreeSurface(plane.image); //释放飞机图片
  SDL_FreeSurface(shots[0].image);  //释放激光图片
  SDL_FreeSurface(bombs[0].image);    //释放炮弹图片
  SDL_FreeSurface(explosions[0].image); //释放爆炸图片
  SDL_FreeSurface(background);  //最后释放背景图片
}
void CreateBomb(void) //产生一枚新的炮弹
{
  int i;
  for ( i=0; i<MAX_BOMBS; ++i )   //当炮弹数没有达到最大值,并且存活值为0时,产生一枚新的炮弹
    if ( ! bombs[i].alive )
      break;
  
  if ( i == MAX_BOMBS )               //已经到达最大值就返回,不产生
    return;
  
      bombs[i].facing=rand()%3-1;                                 

  bombs[i].y = 0;               //确定炮弹初始时的y方向上的位置,0即表示屏幕的上部
  bombs[i].x = (int)(screen->w-bombs[i].image->w)*(rand()/(RAND_MAX+1.0));
  bombs[i].alive = 1;
}
void DrawObject(object *sprite) //画对象
{
  struct blit *update;

  update = &blits[numupdates++];
  update->src = sprite->image;
  update->srcrect->x = 0;   //根据源目标的大小和位置坐标来画
  update->srcrect->y = 0;
  update->srcrect->w = sprite->image->w;
  update->srcrect->h = sprite->image->h;
  update->dstrect->x = sprite->x;
  update->dstrect->y = sprite->y;
  update->dstrect->w = sprite->image->w;
  update->dstrect->h = sprite->image->h;
}
void EraseObject(object *sprite)  //消除目标
{
  struct blit *update;
  int wrap;
  //背景水平重叠达到清除画面效果
  update = &blits[numupdates++];
  update->src = background;
  update->srcrect->x = sprite->x%background->w;
  update->srcrect->y = sprite->y;
  update->srcrect->w = sprite->image->w;
  update->srcrect->h = sprite->image->h;
  wrap = (update->srcrect->x+update->srcrect->w)-(background->w);
  if ( wrap > 0 ) {
    update->srcrect->w -= wrap;
  }
  update->dstrect->x = sprite->x;
  update->dstrect->y = sprite->y;
  update->dstrect->w = update->srcrect->w;
  update->dstrect->h = update->srcrect->h;
  //一个背景一个背景的把屏幕重绘
  if ( wrap > 0 ) {
    update = &blits[numupdates++];
    update->src = background;
    update->srcrect->x = 0;
    update->srcrect->y = sprite->y;
    update->srcrect->w = wrap;
    update->srcrect->h = sprite->image->h;
    update->dstrect->x =((sprite->x/background->w)+1)*background->w;
    update->dstrect->y = sprite->y;
    update->dstrect->w = update->srcrect->w;
    update->dstrect->h = update->srcrect->h;
  }
}
void UpdateScreen(void) //更新屏幕
{
  int i;
  for ( i=0; i<numupdates; ++i ) {
    SDL_LowerBlit(blits[i].src, blits[i].srcrect,
            screen, blits[i].dstrect);
  }
  SDL_UpdateRects(screen, numupdates, dstupdate);
  numupdates = 0;
}
int Collide(object *sprite1, object *sprite2) //两个物体碰撞的情况
{
  if ( (sprite1->y >= (sprite2->y+sprite2->image->h-8)) ||
       (sprite1->x >= (sprite2->x+sprite2->image->w-8)) ||
       (sprite2->y >= (sprite1->y+sprite1->image->h-8)) ||
       (sprite2->x >= (sprite1->x+sprite1->image->w-8)) ) {
    return(0);
  }
  return(1);
}

void WaitFrame(void)
{
  static Uint32 next_tick = 0;
  Uint32 this_tick;
  this_tick = SDL_GetTicks(); //得到当前时间值
  if ( this_tick < next_tick ) {
    SDL_Delay(next_tick-this_tick);//延时时间
  }
  next_tick = this_tick + (1000/FRAMES_PER_SEC);//下一帧
}
void RunGame(void)  //开始游戏
{
  int i, j;
  SDL_Event event;  //SDL事件
  Uint8 *keys;
  SDL_Rect dst;
  
  dst.x = 0;
  dst.y = 0;
  dst.w = background->w;
  dst.h = background->h;
   gettimeofday(&tv1,&tz);
  numupdates = 0;
  SDL_BlitSurface(background, NULL, screen, &dst);
  SDL_UpdateRect(screen, 0, 0, 0, 0);   //更新屏幕
  plane.alive = 1;   //初始化飞机参数,存活,位置和运动方向
  plane.x = (screen->w - plane.image->w)/2;
  plane.y = (screen->h - plane.image->h) -1;
  plane.facing = 0;
  DrawObject(&plane); //画飞机
  for ( i=0; i<MAX_SHOTS; ++i ) {   //初始化激光的存活参数
    shots[i].alive = 0;
  }
  for ( i=0; i<MAX_BOMBS; ++i ) { //初始化炮弹的存活参数
    bombs[i].alive = 0;
  }
  CreateBomb(); //产生炮弹
  DrawObject(&bombs[0]);         //画炮弹
  UpdateScreen();
  
  while ( plane.alive ) {        //当飞机没有被炸毁的时候,游戏正常进行
    WaitFrame();          
    while ( SDL_PollEvent(&event) ) {       //循环接受键盘事件,直到退出
      if ( event.type == SDL_QUIT )
        return;
    }                      
    keys = SDL_GetKeyState(NULL);           //得到键盘键的状态
    for ( i=0; i<MAX_SHOTS; ++i ) {   //清除激光
      if ( shots[i].alive ) {
        EraseObject(&shots[i]);
    	}
    }
    for ( i=0; i<MAX_BOMBS; ++i ) { //清除炮弹
      if ( bombs[i].alive ) {
        EraseObject(&bombs[i]);
    	}
    }
    EraseObject(&plane);
    for ( i=0; i<MAX_BOMBS+1; ++i ) { //清除爆炸
      if ( explosions[i].alive ) {
        EraseObject(&explosions[i]);
    	}
    }
    for ( i=0; i<MAX_BOMBS+1; ++i ) { //爆炸次数记录,并减少
      if ( explosions[i].alive ) {
        --explosions[i].alive;
      } SDL_BlitSurface(background, NULL, screen, &dst);
    }
    if ( (rand()%BOMB_ODDS) == 0 ) {    //产生新的炮弹
      CreateBomb();
    }
    if ( ! reloading ) {  //产生新的激光
      if ( keys[SDLK_SPACE] == SDL_PRESSED ) {//按下空格键,发射
        for ( i=0; i<MAX_SHOTS; ++i ) {
          if ( ! shots[i].alive ) {
            break;
      		}
      	}
        if ( i != MAX_SHOTS ) {        //激光移动轨迹
          shots[i].x = plane.x +
           (plane.image->w-shots[i].image->w)/2;
          shots[i].y = plane.y -
                shots[i].image->h;
          shots[i].alive = 1;
      	}
    	}
    }
    reloading = (keys[SDLK_SPACE] == SDL_PRESSED);
    plane.facing = 0;           //移动飞机
    if ( keys[SDLK_RIGHT] ) {     //右方向键向右运动
      ++plane.facing;
    }
    if ( keys[SDLK_LEFT] ) {    //左方向键向左运动
      --plane.facing;
    }
    if ( keys[SDLK_UP] ) {    //上方向键向上运动
      plane.y-=PLANE_SPEED;
         if(plane.y < 0)
           plane.y= 0 ;
    }
    if ( keys[SDLK_DOWN] ) {    //下方向键向下运动
      plane.y+=PLANE_SPEED;
         if(plane.y > screen->h-plane.image->h)
           plane.y=screen->h-plane.image->h;
    }
    plane.x += plane.facing*PLANE_SPEED;         //计算移动的位移
    if ( plane.x < 0 ) {
      plane.x = 0;
    } else
    if ( plane.x >= (screen->w-plane.image->w) ) {//两边碰头的处理
      plane.x = (screen->w-plane.image->w)-1;
    }
    for ( i=0; i<MAX_BOMBS; ++i ) {//移动炮弹
      if ( bombs[i].alive ) {
            if(bombs[i].facing){
              if(rand()%2){    
                      bombs[i].x += bombs[i].facing*BOMB_SPEED_X;  //计算炮弹位移
                                      }
              else
                  bombs[i].y += BOMB_SPEED_Y;
              }
            else
                bombs[i].y += BOMB_SPEED_Y;
        if ( bombs[i].x < 0 ) { //炮弹两边碰头的计算
          bombs[i].x = (screen->w-bombs[i].image->w)-1;
          bombs[i].y += bombs[i].image->h;
        } else
        if ( bombs[i].x >=
             (screen->w-bombs[i].image->w) ) {
          bombs[i].x = 0;   			   
      	}
            if(bombs[i].y>=(screen->h-bombs[i].image->h))
              bombs[i].alive=0;
    	}
    }
    for ( i=0; i<MAX_SHOTS; ++i ) {   //激光的移动
      if ( shots[i].alive ) {
        shots[i].y -= SHOT_SPEED;          //计算激光位移
        if ( shots[i].y < 0 ) {
          shots[i].alive = 0;
      	}
    	}
    }
    for ( j=0; j<MAX_SHOTS; ++j ) {   //处理碰撞
      for ( i=0; i<MAX_BOMBS; ++i ) {
        if ( shots[j].alive && bombs[i].alive &&
            Collide(&shots[j], &bombs[i]) ) {
          bombs[i].alive = 0;
          explosions[i].x = bombs[i].x; //如果碰撞了,出现爆炸
          explosions[i].y = bombs[i].y;
          explosions[i].alive = EXPLODE_TIME;
          shots[j].alive = 0;
               shoot_bomb_num++;
          break;
      	}
    	}
    }
    for ( i=0; i<MAX_BOMBS; ++i ) { //炮弹和飞机碰撞的处理
      if ( bombs[i].alive && Collide(&plane, &bombs[i]) ) {
        bombs[i].alive = 0;
        explosions[i].x = bombs[i].x; //出现爆炸
        explosions[i].y = bombs[i].y;
        explosions[i].alive = EXPLODE_TIME;
        plane.alive = 0;
        explosions[MAX_BOMBS].x = plane.x;  //飞机爆炸
        explosions[MAX_BOMBS].y = plane.y;
        explosions[MAX_BOMBS].alive = EXPLODE_TIME;
    	}
    }
    for ( i=0; i<MAX_BOMBS; ++i ) { //画炮弹
      if ( bombs[i].alive ) {
        DrawObject(&bombs[i]);
    	}
    }
    for ( i=0; i<MAX_SHOTS; ++i ) {   //画激光
      if ( shots[i].alive ) {
        DrawObject(&shots[i]);
    	}
    }
    if ( plane.alive ) {  //画飞机
      DrawObject(&plane);
    }
    for ( i=0; i<MAX_BOMBS+1; ++i ) { //画爆炸
      if ( explosions[i].alive ) {
        DrawObject(&explosions[i]);
    	}
    }
    UpdateScreen();
    if ( keys[SDLK_ESCAPE] == SDL_PRESSED ) {//按下Esc退出
      plane.alive = 0;
    }
  }
  return;
}

void init()
{
//初始化视频子系统
   int i;
  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
    fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
    exit(2);
  }
  atexit(SDL_Quit);
  //设置视频模式
  screen = SDL_SetVideoMode(640, 480, 0, SDL_SWSURFACE);
  if ( screen == NULL ) {
    fprintf(stderr, "Couldn't set 640x480 video mode: %s\n",
              SDL_GetError());
    exit(2);
  }

  srand(time(0));//随机时间产生器
}

void output(void)
{
  double dt;
  dt=(tv2.tv_sec-tv1.tv_sec)+(tv2.tv_usec-tv1.tv_usec)/1000000.0;
   printf("\n********************************************************************");
   printf("\n    You have shot down  %d  bombs!!",shoot_bomb_num);
   if(shoot_bomb_num>=15)
      printf("\n    You are a good ## SHOOTER ##  !!!!");
  printf("\n    You have successfully survived   %.2lf  seconds!!!",dt);
  if(dt>=30)
     printf("\n    You have passed 30 seconds,\n"
              "    so you are a real ## MAN ## now! Congratulations!!");
   else
     printf("\n    You have not passed 30 seconds\n" 
                "    so you are not a real MAN,catch on and try again!!!");
  printf("\n********************************************************************\n");
}

int main(int argc, char *argv[])
{
  init();
  if ( LoadData() ) {              //加载数据
    RunGame();  //运行游戏
    SDL_Delay(1000);             
      gettimeofday(&tv2,&tz);
    SDL_BlitSurface(gameover, NULL, screen, &dst);
    SDL_UpdateRect(screen, 0, 0, 0, 0);   //更新屏幕  
    SDL_Delay(2000);             
      output();     
    FreeData();                //释放数据
  }
  exit(0);                       //退出
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -