home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 February / maximum-cd-2009-02.iso / DiscContents / SMC_1.6_win32.exe / src / core / collision.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2008-05-22  |  11.2 KB  |  481 lines

  1. /***************************************************************************
  2.  * collison.cpp  -  internal collision functions
  3.  *
  4.  * Copyright (C) 2005 - 2008 Florian Richter
  5.  * Copyright (C) 2005        Amir Taaki
  6.  ***************************************************************************/
  7. /*
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 3 of the License, or
  11.    (at your option) any later version.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15. */
  16.  
  17. #include "../core/collision.h"
  18. #include "../core/game_core.h"
  19. #include "../objects/movingsprite.h"
  20. #include "../level/level.h"
  21. #include "../player/player.h"
  22. #include "../video/gl_surface.h"
  23. #include "../core/sprite_manager.h"
  24.  
  25. /* *** *** *** *** *** *** *** collision type class *** *** *** *** *** *** *** *** *** *** */
  26.  
  27. cObjectCollisionType :: cObjectCollisionType( void )
  28. {
  29.  
  30. }
  31.  
  32. cObjectCollisionType :: ~cObjectCollisionType( void )
  33. {
  34.     list.clear();
  35. }
  36.  
  37. void cObjectCollisionType :: add( cSprite *obj )
  38. {
  39.     if( !obj )
  40.     {
  41.         return;
  42.     }
  43.  
  44.     list.push_back( obj );
  45. }
  46.  
  47. bool cObjectCollisionType :: find( const cSprite *obj )
  48. {
  49.     for( SpriteList::iterator itr = list.begin(), itr_end = list.end(); itr != itr_end; ++itr )
  50.     {
  51.         // matching
  52.         if( (*itr) == obj )
  53.         {
  54.             return 1;
  55.         }
  56.     }
  57.  
  58.     return 0;
  59. }
  60.  
  61. cSprite *cObjectCollisionType :: find( const ArrayType type )
  62. {
  63.     for( SpriteList::iterator itr = list.begin(), itr_end = list.end(); itr != itr_end; ++itr )
  64.     {
  65.         // matching
  66.         if( (*itr)->sprite_array == type )
  67.         {
  68.             return (*itr);
  69.         }
  70.     }
  71.  
  72.     return 0;
  73. }
  74.  
  75. cSprite *cObjectCollisionType :: find( const SpriteType type )
  76. {
  77.     for( SpriteList::iterator itr = list.begin(), itr_end = list.end(); itr != itr_end; ++itr )
  78.     {
  79.         // matching
  80.         if( (*itr)->type == type )
  81.         {
  82.             return (*itr);
  83.         }
  84.     }
  85.  
  86.     return 0;
  87. }
  88.  
  89. unsigned int cObjectCollisionType :: size( void )
  90. {
  91.     return list.size();
  92. }
  93.  
  94. /* *** *** *** *** *** *** *** collision description *** *** *** *** *** *** *** *** *** *** */
  95.  
  96. cObjectCollision :: cObjectCollision( void )
  97. {
  98.     received = 0;
  99.     type = CO_NOTHING;
  100.     number = 0;
  101.     direction = DIR_UNDEFINED;
  102. }
  103.  
  104. cObjectCollision :: ~cObjectCollision( void )
  105. {
  106.     //
  107. }
  108.  
  109. void cObjectCollision :: Set_Direction( cSprite *base, cSprite *col )
  110. {
  111.     direction = Get_Collision_Direction( base, col );
  112. }
  113.  
  114. GL_rect cObjectCollision :: Get_Collision_Object_Rect( void )
  115. {
  116.     // player
  117.     if( type == CO_PLAYER )
  118.     {
  119.         return pActive_Player->col_rect;
  120.     }
  121.  
  122.     // sprite manager
  123.     return pActive_Sprite_Manager->objects[number]->col_rect;
  124. }
  125.  
  126. /* *** *** *** *** *** *** *** functions *** *** *** *** *** *** *** *** *** *** */
  127.  
  128. ObjectDirection Get_Collision_Direction( cSprite *base, cSprite *col )
  129. {
  130.     // if valid moving sprite
  131.     if( base->sprite_array == ARRAY_ENEMY || base->sprite_array == ARRAY_ACTIVE )
  132.     {
  133.         const cMovingSprite *moving_base = static_cast<const cMovingSprite *>(base);
  134.  
  135.         // ## velocity based detection
  136.         if( moving_base->velx != 0 || moving_base->vely != 0 )
  137.         {
  138.             // top
  139.             if( moving_base->vely < 0 && Is_Collision_Top( &base->col_rect, &col->col_rect ) )
  140.             {
  141.                 return DIR_TOP;
  142.             }
  143.             // bottom
  144.             else if( moving_base->vely > 0 && Is_Collision_Bottom( &base->col_rect, &col->col_rect ) )
  145.             {
  146.                 return DIR_BOTTOM;
  147.             }
  148.             // left
  149.             else if( moving_base->velx < 0 && Is_Collision_Left( &base->col_rect, &col->col_rect ) )
  150.             {
  151.                 return DIR_LEFT;
  152.             }
  153.             // right
  154.             else if( moving_base->velx > 0 && Is_Collision_Right( &base->col_rect, &col->col_rect ) )
  155.             {
  156.                 return DIR_RIGHT;
  157.             }
  158.         }
  159.     }
  160.  
  161.  
  162.     // ## detection without velocity
  163.  
  164.     // top
  165.     if( Is_Collision_Top( &base->col_rect, &col->col_rect ) )
  166.     {
  167.         return DIR_TOP;
  168.     }
  169.     // bottom
  170.     else if( Is_Collision_Bottom( &base->col_rect, &col->col_rect ) )
  171.     {
  172.         return DIR_BOTTOM;
  173.     }
  174.     // left
  175.     else if( Is_Collision_Left( &base->col_rect, &col->col_rect ) )
  176.     {
  177.         return DIR_LEFT;
  178.     }
  179.     // right
  180.     else if( Is_Collision_Right( &base->col_rect, &col->col_rect ) )
  181.     {
  182.         return DIR_RIGHT;
  183.     }
  184.  
  185.     // ## advanced detection ( if base object is partly inside col object )
  186.  
  187.     // get the middle point
  188.     GL_point point_base = base->col_rect.Get_pos_middle();
  189.     GL_point point_col = col->col_rect.Get_pos_middle();
  190.  
  191.     // difference between points
  192.     float diff_x = point_col.x - point_base.x;
  193.     float diff_y = point_col.y - point_base.y;
  194.  
  195.     // more horizontal
  196.     if( ( diff_x > 0 && ( diff_x > diff_y ) ) || ( diff_x < 0 && ( diff_x < diff_y ) ) )
  197.     {
  198.         // if col object point left
  199.         if( diff_x > 0 )
  200.         {
  201.             return DIR_RIGHT;
  202.         }
  203.         // if col object point is right
  204.         else
  205.         {
  206.             return DIR_LEFT;
  207.         }
  208.     }
  209.     // more vertical
  210.     else
  211.     {
  212.         // if col object point is on top
  213.         if( diff_y > 0 )
  214.         {
  215.             return DIR_DOWN;
  216.         }
  217.         // if col object point is below
  218.         else
  219.         {
  220.             return DIR_UP;
  221.         }
  222.     }
  223. }
  224.  
  225. bool Is_Collision_Top( const GL_rect *base_rect, const GL_rect *col_rect )
  226. {
  227.     if( base_rect->y + 1 >= col_rect->y + col_rect->h && base_rect->x < col_rect->x + col_rect->w && base_rect->x + base_rect->w > col_rect->x )
  228.     {
  229.         return 1;
  230.     }
  231.  
  232.     return 0;
  233. }
  234.  
  235. bool Is_Collision_Bottom( const GL_rect *base_rect, const GL_rect *col_rect )
  236. {
  237.     if( base_rect->y + base_rect->h - 1 <= col_rect->y && base_rect->x < col_rect->x + col_rect->w && base_rect->x + base_rect->w > col_rect->x )
  238.     {
  239.         return 1;
  240.     }
  241.  
  242.     return 0;
  243. }
  244.  
  245. bool Is_Collision_Left( const GL_rect *base_rect, const GL_rect *col_rect )
  246. {
  247.     if( base_rect->x + 1 >= col_rect->x + col_rect->w && base_rect->y < col_rect->y + col_rect->h && base_rect->y + base_rect->h > col_rect->y )
  248.     {
  249.         return 1;
  250.     }
  251.  
  252.     return 0;
  253. }
  254.  
  255. bool Is_Collision_Right( const GL_rect *base_rect, const GL_rect *col_rect )
  256. {
  257.     if( base_rect->x + base_rect->w - 1 <= col_rect->x && base_rect->y < col_rect->y + col_rect->h && base_rect->y + base_rect->h > col_rect->y )
  258.     {
  259.         return 1;
  260.     }
  261.  
  262.     return 0;
  263. }
  264.  
  265. ObjectCollisionType Get_Collision_Type( ArrayType array_type )
  266. {
  267.     if( array_type == ARRAY_FRONT_PASSIVE || array_type == ARRAY_PASSIVE )
  268.     {
  269.         return CO_PASSIVE;
  270.     }
  271.     else if( array_type == ARRAY_MASSIVE )
  272.     {
  273.         return CO_MASSIVE;
  274.     }
  275.     else if( array_type == ARRAY_ACTIVE )
  276.     {
  277.         return CO_ACTIVE;
  278.     }
  279.     else if( array_type == ARRAY_ENEMY )
  280.     {
  281.         return CO_ENEMY;
  282.     }
  283.  
  284.     return CO_NOTHING;
  285. }
  286.  
  287. bool Col_Box( const GL_rect *a, const GL_rect *b )
  288. {
  289.     // check if their bounding boxes touch
  290.     if( b->x + b->w < a->x )
  291.     {
  292.         return 0;
  293.     }
  294.     if( b->x > a->x + a->w )
  295.     {
  296.         return 0;
  297.     }
  298.  
  299.     if( b->y + b->h < a->y )
  300.     {
  301.         return 0;
  302.     }
  303.     if( b->y > a->y + a->h )
  304.     {
  305.         return 0;
  306.     }
  307.  
  308.     // bounding boxes intersect
  309.     return 1;
  310. }
  311.  
  312. bool Col_Box( const SDL_Rect *a, const GL_rect *b )
  313. {
  314.     // check if their bounding boxes touch
  315.     if( b->x + b->w < a->x )
  316.     {
  317.         return 0;
  318.     }
  319.     if( b->x > a->x + a->w )
  320.     {
  321.         return 0;
  322.     }
  323.  
  324.     if( b->y + b->h < a->y )
  325.     {
  326.         return 0;
  327.     }
  328.     if( b->y > a->y + a->h )
  329.     {
  330.         return 0;
  331.     }
  332.  
  333.     // bounding boxes intersect
  334.     return 1;
  335. }
  336.  
  337. bool Col_Box_full( const SDL_Rect *a, const SDL_Rect *b )
  338. {
  339.     if( a->x <= b->x )
  340.     {
  341.         return 0;
  342.     }
  343.     if( a->x + a->w >= b->x + b->w )
  344.     {
  345.         return 0;
  346.     }
  347.     if( a->y <= b->y )
  348.     {
  349.         return 0;
  350.     }
  351.     if( a->y + a->h >= b->y + b->h )
  352.     {
  353.         return 0;
  354.     }
  355.  
  356.     return 1;
  357. }
  358.  
  359. // from SDL_collide ( Copyright (C) 2005 Amir Taaki ) - MIT License
  360. bool Col_Circle( float x1, float y1, float r1, float x2, float y2, float r2, int offset )
  361. {
  362.     float xdiff = x2 - x1;    // x plane difference
  363.     float ydiff = y2 - y1;    // y plane difference
  364.     
  365.     /* distance between the circles centres squared */
  366.     float dcentre_sq = ( ydiff * ydiff ) + ( xdiff * xdiff );
  367.     
  368.     /* calculate sum of radiuses squared */
  369.     float r_sum_sq = r1 + r2;    // square on seperate line, so
  370.     r_sum_sq *= r_sum_sq;    // dont recompute r1 + r2
  371.  
  372.     return ( dcentre_sq - r_sum_sq <= ( offset * offset ) );
  373. }
  374.  
  375. bool Col_Circle( GL_Surface *surface1, SDL_Rect *a, GL_Surface *surface2, SDL_Rect *b, int offset )
  376. {
  377.     return Col_Circle( surface1, a->x, a->y, surface2, b->x, b->y, offset );
  378. }
  379.  
  380. // from SDL_collide ( Copyright (C) 2005 Amir Taaki ) - MIT License
  381. bool Col_Circle( GL_Surface *a, float x1, float y1, GL_Surface *b, float x2, float y2, int offset )
  382. {
  383.     /* if radius is not specified
  384.     we approximate them using SDL_Surface's
  385.     width and height average and divide by 2*/
  386.     float r1 = ( ( a->w + a->h ) / 4 );    // same as / 2) / 2;
  387.     float r2 = ( ( b->w + b->h ) / 4 );
  388.  
  389.     x1 += a->w / 2;        // offset x and y
  390.     y1 += a->h / 2;        // co-ordinates into
  391.                 // centre of image
  392.     x2 += b->w / 2;
  393.     y2 += b->h / 2;
  394.  
  395.     return Col_Circle( x1, y1, r1, x2, y2, r2, offset );
  396. }
  397.  
  398. template<typename T> inline T pow2( T value ) { return value * value; }
  399. template<typename T> inline T cl_min( T a, T b ) { if( a < b ) return a; return b; }
  400.  
  401. // from ClanLib ( Copyright (C) 2005 Magnus Norddahl ) - BSD License
  402. float Distance_to_Line( float x, float y, GL_line *line )
  403. {
  404.     float L = sqrt( pow2( line->x2 - line->x1 ) + pow2( line->y2 - line->y1 ) );
  405.     float r = ( ( x - line->x1 ) * ( line->x2 - line->x1 ) + ( y - line->y1 ) * ( line->y2 - line->y1 ) ) / pow2( L );
  406.     
  407.     if( r <= 0 || r >= 1 )
  408.     {
  409.         GL_point p( x, y );
  410.         GL_point A( line->x1, line->y1 );
  411.         GL_point B( line->x2, line->y2 );
  412.         
  413.         return cl_min( p.distance( A ), p.distance( B ) );
  414.     }
  415.     
  416.     float s = ( ( line->y1 - y ) * ( line->x2 - line->x1 ) - ( line->x1 - x ) * ( line->y2 - line->y1 ) ) / pow2( L );
  417.     return fabs( s ) * L ;
  418. }
  419.  
  420. // from ClanLib ( Copyright (C) 2005 Magnus Norddahl ) - BSD License
  421. GL_point Get_Line_Intersection( GL_line *line1, GL_line *line2 )
  422. {
  423.     float denominator = ( ( line1->x2 - line1->x1 ) * ( line2->y2 - line2->y1 ) - ( line1->y2 - line1->y1 ) * ( line2->x2 - line2->x1 ) );
  424.  
  425.     if( denominator == 0 )
  426.     {
  427.         return GL_point( line1->x1, line1->y1 );
  428.     }
  429.     
  430.     float r = ( ( line1->y1 - line2->y1 ) * ( line2->x2 - line2->x1 ) - ( line1->x1 - line2->x1 ) * ( line2->y2 - line2->y1 ) ) / denominator;
  431.     
  432.     GL_point p;
  433.     p.x = line1->x1 + r * ( line1->x2 - line1->x1 );
  434.     p.y = line1->y1 + r * ( line1->y2 - line1->y1 );
  435.     
  436.     return p;
  437. }
  438.  
  439. // from ClanLib ( Copyright (C) 2005 Magnus Norddahl ) - BSD License
  440. bool Col_Line( GL_line *line1, GL_line *line2, bool collinear_intersect )
  441. {
  442.     float denominator = ( ( line1->x2 - line1->x1 ) * ( line2->y2 - line2->y1 ) - ( line1->y2 - line1->y1 ) * ( line2->x2 - line2->x1 ) );    
  443.     
  444.     if( denominator == 0 ) // parallel
  445.     {
  446.         if( ( line1->y1 - line2->y1 ) * ( line2->x2 - line2->x1 ) - ( line1->x1 - line2->x1 ) * ( line2->y2 - line2->y1 ) == 0 ) // collinear
  447.         {
  448.             if( collinear_intersect )
  449.             {
  450.                 return 1;
  451.             }
  452.             else
  453.             {
  454.                 return 0;
  455.             }
  456.         }
  457.  
  458.         return 0;
  459.     }
  460.     
  461.     float r = ( ( line1->y1 - line2->y1 ) * ( line2->x2 - line2->x1 ) - ( line1->x1 - line2->x1 ) * ( line2->y2 - line2->y1 ) ) / denominator;
  462.     float s = ( ( line1->y1 - line2->y1 ) * ( line1->x2 - line1->x1 ) - ( line1->x1 - line2->x1 ) * ( line1->y2 - line1->y1 ) ) / denominator;
  463.     
  464.     if( line2->y1 < line2->y2 )
  465.     {
  466.         if( (s >= 0.0f  && s < 1.0f) && ( r >= 0.0f && r <= 1.0f ) )
  467.         {
  468.             return 1;
  469.         }
  470.     }
  471.     else
  472.     {
  473.         if( (s > 0.0f  && s <= 1.0f) && ( r >= 0.0f && r <= 1.0f ) )
  474.         {
  475.             return 1;
  476.         }
  477.     }
  478.     
  479.     return 0;
  480. }
  481.