基于投影方法的碰撞检测以及一个测试DEMO【C + SDL】

来源:互联网 发布:淘宝的奇葩商品 编辑:程序博客网 时间:2024/04/29 05:36

理论知识是网路上的《2D多边形碰撞检测和反馈》,具体到四条边平行于X,Y轴的矩形的碰撞检测情况就简单了不少。原理如下:

      将两个矩形分别投影到X和Y轴。

      在X轴上,如果两个矩形的投影(即一条线上的两个部分)有重叠区域,则X轴上重叠。

      同样判断Y轴。如果X和Y轴上的投影都重叠,那么这两个矩形一定重叠。

 

      由于判断投影不重叠更容易,所以我们用反证法。函数如下:

//投影直线重合判定: 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;
     }

   

     以下是一个测试程序,大体是一个类似于推箱子的踢足球小游戏。

     想学习SDL的朋友可以在里面找到绝大多数基础的函数的使用实例。

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


#define X_LENGTH 640
#define Y_LENGTH 480
#define SCREEN_BPP  32

#define ROLE_W 20
#define ROLE_H 30

#define FTB_W 16
#define FTB_H 16

#define MOVE_LTH 10

 


struct point{
         int xpos;
         int ypos;
         };

//全局变量
SDL_Surface *back = NULL;
SDL_Surface *image = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *message = NULL;
SDL_Surface *football = NULL;

struct point stand[4] = {{10,100}, {110,100}, {210,100}, {310,100} };
struct point walk[4][2]  = {
                               {{10,250},{10,300}},
                               {{110,250},{110,300}},
                               {{210,250},{210,300}},
                               {{310,250},{310,300}}
                           };

struct point ball[2] = {{0,0}, {0,16}};

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);
 }
}

 

//object
struct object{
       //坐标      
          int xpos;
          int ypos;
       //宽高  
          unsigned int height;
          unsigned int width;
       //方向(1左,2右,3上,4下)
          unsigned int direction;  
       //源表面
          SDL_Surface *src_s;
       //源图块坐标
          int xs;
          int ys;
       //上一个状态: 1 站;2 走
          unsigned int state;
       //移动序列
          unsigned int seq; 
       };
 
//投影直线重合判定: 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 Drawmsg(SDL_Surface *message, int x, int y)
{
     SDL_Rect dest;
     dest.x = x;
     dest.y = y; 
     Slock(screen);
     SDL_BlitSurface(message,NULL,screen,&dest);
     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;
 }  
}

//站
void stand_f(struct object *obj)
{
     switch(obj->direction)
     {
       case 4:
              obj->xs = stand[0].xpos;
              obj->ys = stand[0].ypos;
              break;
       case 1: 
              obj->xs = stand[1].xpos;
              obj->ys = stand[1].ypos;
              break;  
       case 3: 
              obj->xs = stand[2].xpos;
              obj->ys = stand[2].ypos;
              break; 
       case 2: 
              obj->xs = stand[3].xpos;
              obj->ys = stand[3].ypos;
              break; 
     }
}

//走
void walk_f(struct object *obj)
{
     switch(obj->direction)
     {
       case 4:
              if(obj->state == 2)//以前就是走的状态
              {
                 if(obj->seq == 1) obj->seq = 0;
                   else if(obj->seq == 0)  obj->seq = 1;       
              }
              else  obj->seq = 0;
              obj->xs = walk[0][obj->seq].xpos;
              obj->ys = walk[0][obj->seq].ypos;
              break;
       case 1:
              if(obj->state == 2)//以前就是走的状态
              {
                 if(obj->seq == 1) obj->seq = 0;
                   else if(obj->seq == 0)  obj->seq = 1;       
              }
              else  obj->seq = 0;
              obj->xs = walk[1][obj->seq].xpos;
              obj->ys = walk[1][obj->seq].ypos;
              break;
       case 3:
              if(obj->state == 2)//以前就是走的状态
              {
                 if(obj->seq == 1) obj->seq = 0;
                   else if(obj->seq == 0)  obj->seq = 1;       
              }
              else  obj->seq = 0;
              obj->xs = walk[2][obj->seq].xpos;
              obj->ys = walk[2][obj->seq].ypos;
              break;
       case 2:
              if(obj->state == 2)//以前就是走的状态
              {
                 if(obj->seq == 1) obj->seq = 0;
                   else if(obj->seq == 0)  obj->seq = 1;       
              }
              else  obj->seq = 0;
              obj->xs = walk[3][obj->seq].xpos;
              obj->ys = walk[3][obj->seq].ypos;
              break;
     }
}


//动画坐标转换函数
void cartoon(struct object *obj)
{
     switch(obj->state)
     {
      case 1:
           stand_f(obj);
           break;
      case 2:
           walk_f(obj);
           break;
     }
}

 


////  主函数   /////
////           /////


int main(int argc, char *argv[])
{
    //初始化 
    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 );

 /////////////设置字体//////////////
 //
  TTF_Font *font;
  SDL_Color textColor = { 0, 0, 0 };
  TTF_Init();
  font = TTF_OpenFont("C://Windows//Fonts//BRITANIC.TTF",28);
  if(font == NULL) return 1;
  message = TTF_RenderText_Solid( font, "hello,the world!", textColor );
  if(message == NULL) return 1;
 
 /////////////////////////////
  back = IMG_Load("c://back.bmp");
  image = IMG_Load("c://abc.png");
  football = IMG_Load("c://football.bmp");
  SDL_SetColorKey(football, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(football->format, 255, 0, 255));
  struct object role = {0,0,ROLE_H,ROLE_W,2,image,10,100,1,0};
  struct object ftb = {150,150,FTB_H,FTB_W,2,football,0,0,1,0};
 /////////////////////////////
 Uint8* keys;
 int done=0;
 
 DrawBG(back);
 DrawScene(role,back);
 ///////////字体//////
 Slock(screen);
 Drawmsg(message, 100, 100);
 Sulock(screen);
 
 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; }
    }
 }
 keys = SDL_GetKeyState(NULL);
 
 if ( keys[SDLK_UP] )
      { role.ypos -= MOVE_LTH;
        role.direction = 3;
        role.state = 2;
        cartoon(&role);}
 else if ( keys[SDLK_DOWN] )
      { role.ypos += MOVE_LTH;
        role.direction = 4;
        role.state = 2;
        cartoon(&role);}
 else if ( keys[SDLK_LEFT] )
      { role.xpos -= MOVE_LTH;
        role.direction = 1;
        role.state = 2;
        cartoon(&role);}
  else if ( keys[SDLK_RIGHT] )
      { role.xpos += MOVE_LTH;
        role.direction = 2;
        role.state = 2;
        cartoon(&role);}
 
 int test_val = border(role);
 if(test_val%10 == 1)  role.xpos =0;
 if(test_val/10%10 == 1) role.xpos = X_LENGTH - role.width;
 if(test_val/100%10 == 1) role.ypos = 0;
 if(test_val/1000 == 1) role.ypos = Y_LENGTH - role.height;
 
 if(touch(role,ftb))
  {
     switch(role.direction)
     {
      case 1:
             ftb.xpos = role.xpos - ftb.width;
             ftb.direction = 1;
             break;
      case 2:
             ftb.xpos = role.xpos + role.width;
             ftb.direction = 2;
             break;
      case 3:
             ftb.ypos = role.ypos - ftb.height;
             ftb.direction = 3;
             break;
      case 4:
             ftb.ypos = role.ypos + role.height;;
             ftb.direction = 4;
             break;
      }
 
      int test_val = border(ftb);
      if(test_val%10 == 1){ 
                          ftb.xpos = 0;
                          if ( keys[SDLK_UP] )  role.ypos += MOVE_LTH;
                          if ( keys[SDLK_DOWN] ) role.ypos -= MOVE_LTH;
                          if ( keys[SDLK_LEFT] )  role.xpos += MOVE_LTH;
                          }
      if(test_val/10%10 == 1){ 
                          ftb.xpos = X_LENGTH - ftb.width;
                          if ( keys[SDLK_UP] )  role.ypos += MOVE_LTH;
                          if ( keys[SDLK_DOWN] ) role.ypos -= MOVE_LTH;
                          if ( keys[SDLK_RIGHT] )  role.xpos -= MOVE_LTH;
                          }
      if(test_val/100%10 == 1){
                          ftb.ypos = 0;
                          role.ypos += MOVE_LTH;
                          }
      if(test_val/1000 == 1){
                          ftb.ypos = Y_LENGTH - ftb.height;
                          role.ypos -= MOVE_LTH;
                          }
                         
     if(ftb.ys == 0) ftb.ys = 16;
     else ftb.ys = 0;
  }   
  DrawScene(ftb,back);
  DrawScene(role,back);
  SDL_Flip(screen);
  SDL_Delay(100);
}

//释放字体文件

    TTF_CloseFont( font );
  //释放TTF

  TTF_Quit();

}

原创粉丝点击