home *** CD-ROM | disk | FTP | other *** search
/ PC Format (South-Africa) 2001 June / PCFJune.iso / Xenon / XenonSource.exe / gamesystem / source / gs_collisionlist.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-31  |  5.4 KB  |  234 lines

  1. //-------------------------------------------------------------
  2. //
  3. // Class:    gsCCollisionList
  4. //
  5. // Author:    John M Phillips
  6. //
  7. // Started:    06/05/00
  8. //
  9. // Base:    gsCObject
  10. //
  11. // Derived:    None
  12. //
  13. //-------------------------------------------------------------
  14.  
  15. #include "gamesystem.h"
  16.  
  17. //-------------------------------------------------------------
  18.  
  19. gsCCollider::gsCCollider()
  20. {
  21.     m_object = 0;
  22. }
  23.  
  24. //-------------------------------------------------------------
  25.  
  26. gsCCollider::gsCCollider(void *object,const gsCRect& rect,gsUDWORD object_mask,gsUDWORD target_mask,int uid)
  27. {
  28.     m_object = object;
  29.     m_rect = rect;
  30.     m_uid = uid;
  31.     m_object_mask = object_mask;
  32.     m_target_mask = target_mask;
  33. }
  34.  
  35. //-------------------------------------------------------------
  36.         
  37. gsCCollider::gsCCollider(const gsCCollider& collider)
  38. {
  39.     m_object = collider.m_object;
  40.     m_rect = collider.m_rect;
  41.     m_uid = collider.m_uid;
  42.     m_object_mask = collider.m_object_mask;
  43.     m_target_mask = collider.m_target_mask;
  44. }
  45.  
  46. //-------------------------------------------------------------
  47.  
  48. gsCCollisionList::gsCCollisionList()
  49. {
  50.     m_pixel_size = gsCPoint(0,0);
  51.     m_zone_size = gsCPoint(0,0);
  52.     m_zones = gsCPoint(0,0);
  53.     m_zone = 0;
  54. }
  55.  
  56. //-------------------------------------------------------------
  57.  
  58. gsCCollisionList::~gsCCollisionList()
  59. {
  60.     destroy();
  61. }
  62.  
  63. //-------------------------------------------------------------
  64.  
  65. void gsCCollisionList::destroy()
  66. {
  67.     clear();
  68.  
  69.     if (m_zone) {
  70.         delete [] m_zone;
  71.         m_zone = 0;
  72.         }
  73. }
  74.  
  75. //-------------------------------------------------------------
  76.  
  77. void gsCCollisionList::setSize(const gsCPoint& pixel_size,const gsCPoint& zones)
  78. {
  79.     destroy();
  80.  
  81.     m_pixel_size = pixel_size;
  82.     m_zones = zones;
  83.     m_zone_size = m_pixel_size / zones;
  84.  
  85.     // create a collider list for each zone
  86.  
  87.     m_zone = new gsColliderList[m_zones.getX() * m_zones.getY()];
  88. }
  89.  
  90. //-------------------------------------------------------------
  91.  
  92. void gsCCollisionList::clear()
  93. {
  94.     // clear out the zone lists
  95.  
  96.     if (m_zone) {
  97.         for (int i = 0; i < m_zones.getX() * m_zones.getY(); i++)
  98.             m_zone[i].clear();
  99.         }
  100.  
  101.     // clear out the object list
  102.  
  103.     for (int i = 0; i < m_collider_list.getSize(); i++)
  104.         delete m_collider_list[i];
  105.  
  106.     m_collider_list.clear();
  107. }
  108.  
  109. //-------------------------------------------------------------
  110.  
  111. void gsCCollisionList::addObject(void *object,const gsCRect& rect,gsUDWORD object_mask,gsUDWORD target_mask)
  112. {
  113.     // get range of zones which object overlaps
  114.  
  115.     int left_zone = rect.getLeft() / m_zone_size.getX();
  116.     int right_zone = (rect.getRight() - 1) / m_zone_size.getX();
  117.     int top_zone = rect.getTop() / m_zone_size.getY();
  118.     int bottom_zone = (rect.getBottom() - 1) / m_zone_size.getY();
  119.  
  120.     // skip if outside collision map
  121.  
  122.     if (left_zone >= m_zones.getX() ||
  123.         right_zone < 0 ||
  124.         top_zone >= m_zones.getY() ||
  125.         bottom_zone < 0)
  126.         return;
  127.  
  128.     // clip against collision map
  129.  
  130.     if (left_zone < 0)
  131.         left_zone = 0;
  132.     if (right_zone >= m_zones.getX())
  133.         right_zone = m_zones.getX() - 1;
  134.     if (top_zone < 0)
  135.         top_zone = 0;
  136.     if (bottom_zone >= m_zones.getY())
  137.         bottom_zone = m_zones.getY() - 1;
  138.  
  139.     // make a record of the collider
  140.  
  141.     int uid = m_collider_list.getSize();
  142.  
  143.     gsCCollider *collider = new gsCCollider(object,rect,object_mask,target_mask,uid);
  144.  
  145.     m_collider_list.addItem(collider);
  146.  
  147.     // add to EACH zone which it overlaps
  148.  
  149.     for (int y = top_zone; y <= bottom_zone; y++) {
  150.         for (int x = left_zone; x <= right_zone; x++) {
  151.             m_zone[y * m_zones.getX() + x].addItem(collider);
  152.             }
  153.         }
  154. }
  155.  
  156. //-------------------------------------------------------------
  157.  
  158. void gsCCollisionList::scan(gsCollisionCallback *callback)
  159. {
  160.     if (!callback)
  161.         return;
  162.  
  163.     int num_objects = m_collider_list.getSize();
  164.  
  165.     // create an array of flags to mark whether we've tested
  166.     // a particular combination of objects
  167.  
  168.     gsUBYTE *tested = new gsUBYTE[num_objects * num_objects];
  169.  
  170.     memset(tested,0,num_objects * num_objects);
  171.  
  172.     // scan the zones
  173.  
  174.     for (int i = 0; i < m_zones.getX() * m_zones.getY(); i++) {
  175.  
  176.         // get list of the colliders in the zone
  177.         
  178.         gsColliderList& collider_list = m_zone[i];
  179.  
  180.         // skip if empty or only one collider
  181.  
  182.         if (collider_list.getSize() > 1) {
  183.  
  184.             // we've found a zone with at least 2 objects in it
  185.             // test all combinations of pairs of objects
  186.  
  187.             for (int a = 0; a < collider_list.getSize(); a++) {
  188.  
  189.                 gsCCollider *obj_a = collider_list[a];
  190.  
  191.                 // get pointer to row of flags for object a
  192.                 
  193.                 gsUBYTE *tp = tested + obj_a->m_uid * num_objects;
  194.  
  195.                 for (int b = a + 1; b < collider_list.getSize(); b++) {
  196.  
  197.                     gsCCollider *obj_b = collider_list[b];
  198.  
  199.                     // skip pairs we've already tested
  200.                     
  201.                     if (tp[obj_b->m_uid] == 0) {
  202.  
  203.                         gsASSERT(obj_a->m_object);
  204.                         gsASSERT(obj_b->m_object);
  205.  
  206.                         // check if rectangles overlap
  207.  
  208.                         if (obj_a->m_rect.overlaps(obj_b->m_rect)) {
  209.  
  210.                             // if object a can hit object b test collision
  211.  
  212.                             if ((obj_a->m_target_mask & obj_b->m_object_mask) != 0)
  213.                                 callback(obj_a->m_object,obj_b->m_object);
  214.  
  215.                             if ((obj_b->m_target_mask & obj_a->m_object_mask) != 0)
  216.                                 callback(obj_b->m_object,obj_a->m_object);
  217.                             }
  218.                         
  219.                         // mark pair as having been tested
  220.             
  221.                         tp[obj_b->m_uid] = 1;
  222.                         }
  223.                     }
  224.                 }
  225.             }
  226.         }
  227.  
  228.     // delete the flags
  229.  
  230.     delete [] tested;
  231. }
  232.  
  233. //-------------------------------------------------------------
  234.