Changed collision code, we now have several collision groups:
authorMatthias Braun <matze@braunis.de>
Tue, 27 Dec 2005 23:25:59 +0000 (23:25 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 27 Dec 2005 23:25:59 +0000 (23:25 +0000)
  really moving objects,
  static (solid) objects,
  tilemap,
  touchable (nonsolid) objects
  (moving statics, not implemented yet will be used for moving platforms)

We now set 1 of these groups for all objects and then only check:
  moving objects vs statics + tilemap
  moving objects vs touchable objects
  moving objects vs moving objects

This gives a huge speedup for the Area42 map and will be the base for a correct fix of some collision problems encountered with ?-blocks

SVN-Revision: 2958

22 files changed:
src/badguy/badguy.cpp
src/badguy/snowball.cpp
src/collision_grid.cpp
src/game_object.hpp
src/game_session.cpp
src/main.cpp
src/moving_object.cpp
src/moving_object.hpp
src/object/block.cpp
src/object/coin.cpp
src/object/flower.cpp
src/object/growup.cpp
src/object/oneup.cpp
src/object/player.cpp
src/object/powerup.cpp
src/object/rock.cpp
src/object/skull_tile.cpp
src/object/star.cpp
src/object/unstable_tile.cpp
src/sector.cpp
src/sector.hpp
src/trigger/trigger_base.cpp

index b1e2790..91b4bc9 100644 (file)
@@ -229,7 +229,7 @@ BadGuy::set_state(State state)
       state_timer.start(SQUISH_TIME);
       break;
     case STATE_ACTIVE:
-      flags &= ~FLAG_NO_COLLDET;
+      set_group(COLGROUP_MOVING);
       bbox.set_pos(start_position);
       break;
     case STATE_INACTIVE:
@@ -237,10 +237,10 @@ BadGuy::set_state(State state)
       if(laststate == STATE_SQUISHED || laststate == STATE_FALLING) {
         remove_me();
       }
-      flags |= FLAG_NO_COLLDET;
+      set_group(COLGROUP_DISABLED);
       break;
     case STATE_FALLING:
-      flags |= FLAG_NO_COLLDET;
+      set_group(COLGROUP_DISABLED);
       break;
     default:
       break;
index 65319d8..e1c0e51 100644 (file)
@@ -33,7 +33,7 @@ SnowBall::SnowBall(const lisp::Lisp& reader)
   reader.get("fluffy",fluffy);
   bbox.set_size(31.8, 31.8);
   if (fluffy) sprite = sprite_manager->create("fluffy");
-  else sprite = sprite_manager->create("snowball");
+  else sprite = sprite_manager->create("images/creatures/snowball/snowball.sprite");
   set_direction = false;
 }
 
index bf6cc93..311811a 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include <iostream>
@@ -102,8 +101,8 @@ CollisionGrid::remove_object(MovingObject* object)
   assert(wrapper != 0);
 #else
   if(wrapper == 0) {
-       std::cerr << "Tried to remove nonexistant object!\n";
-       return;
+    std::cerr << "Tried to remove nonexistant object!\n";
+    return;
   }
 #endif
   
@@ -134,8 +133,8 @@ CollisionGrid::move_object(ObjectWrapper* wrapper)
     for(float x = obbox.p1.x; x < obbox.p2.x; x += cell_width) {
       int gridx = int(x / cell_width);
       int gridy = int(y / cell_height);
-      if(gridx < 0 || gridy < 0 
-          || gridx >= int(cells_x) || gridy >= int(cells_y)) {
+      if(gridx < 0 || gridy < 0  ||
+         gridx >= int(cells_x) || gridy >= int(cells_y)) {
         std::cerr << "Object out of range: " << gridx << ", " << gridy << "\n";
         continue;
       }
@@ -174,7 +173,7 @@ CollisionGrid::check_collisions()
     MovingObject* object = wrapper->object;
     if(!object->is_valid())
       continue;
-    if(object->get_flags() & GameObject::FLAG_NO_COLLDET) {
+    if(object->get_group() == COLGROUP_DISABLED) {
       object->bbox.move(object->movement);
       object->movement = Vector(0, 0);
       moved_objects.push_back(wrapper);
index 1131847..547353b 100644 (file)
@@ -78,9 +78,7 @@ public:
   // flags
   enum {
     /// the tile so you can stand on it
-    FLAG_SOLID       = 0x0001,
-    /// can be used to temporatily disable collision detection
-    FLAG_NO_COLLDET  = 0x0002
+    FLAG_SOLID       = 0x0001
   };                     
 
   int get_flags() const
index 5bca083..613d143 100644 (file)
@@ -731,7 +731,7 @@ GameSession::drawstatus(DrawingContext& context)
 
   if(config->show_fps) {
     char str[60];
-    snprintf(str, sizeof(str), "%2.1f", fps_fps);
+    snprintf(str, sizeof(str), "%3.1f", fps_fps);
     context.draw_text(white_text, "FPS", 
                       Vector(SCREEN_WIDTH -
                              white_text->get_text_width("FPS     ") - BORDER_X, BORDER_Y + 40),
index 22073bb..ae2dad1 100644 (file)
@@ -62,9 +62,8 @@ static void init_config()
   try {
     config->load();
   } catch(std::exception& e) {
-#ifdef DEBUG
     std::cerr << "Couldn't load config file: " << e.what() << "\n";
-#endif
+    std::cerr << "Using default settings.\n";
   }
 }
 
index 513375a..bd44896 100644 (file)
@@ -22,6 +22,7 @@
 
 MovingObject::MovingObject()
 {
+  group = COLGROUP_MOVING;
 }
 
 MovingObject::~MovingObject()
index 753914b..7117777 100644 (file)
 class Sector;
 class CollisionGrid;
 
+enum CollisionGroup {
+  COLGROUP_DISABLED,
+  COLGROUP_MOVING,
+  COLGROUP_STATIC,
+  COLGROUP_MOVINGSTATIC,
+  COLGROUP_TOUCHABLE,
+  
+  COLGROUP_TILEMAP /* not really used at the moment */
+};
+
 /**
  * Base class for all dynamic/moving game objects. This class contains things
  * for handling the bounding boxes and collision feedback.
@@ -66,6 +76,16 @@ public:
   {
     bbox.set_pos(pos);
   }
+
+  CollisionGroup get_group() const
+  {
+    return group;
+  }
+
+  void set_group(CollisionGroup group)
+  {
+    this->group = group;
+  }
   
 protected:
   friend class Sector;
@@ -79,6 +99,8 @@ protected:
   /** The movement that will happen till next frame
    */
   Vector movement;
+  /** The collision group */
+  CollisionGroup group;
 };
 
 #endif
index d68b02a..ac5bc57 100644 (file)
@@ -51,6 +51,7 @@ Block::Block(Sprite* newsprite)
   : sprite(newsprite), bouncing(false), bounce_dir(0), bounce_offset(0)
 {
   bbox.set_size(32, 32.1);
+  set_group(COLGROUP_STATIC);
   flags |= FLAG_SOLID;
 }
 
index 88c0d9e..d3eb1f5 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include "coin.hpp"
@@ -36,6 +35,7 @@ Coin::Coin(const Vector& pos)
   bbox.set_pos(pos);
   bbox.set_size(32, 32);
   sprite = sprite_manager->create("coin");
+  set_group(COLGROUP_TOUCHABLE);
 }
 
 Coin::Coin(const lisp::Lisp& reader)
@@ -44,6 +44,7 @@ Coin::Coin(const lisp::Lisp& reader)
   reader.get("y", bbox.p1.y);
   bbox.set_size(32, 32);
   sprite = sprite_manager->create("coin");
+  set_group(COLGROUP_TOUCHABLE);
 }
 
 Coin::~Coin()
index c71ec69..9c2ac91 100644 (file)
@@ -37,6 +37,8 @@ Flower::Flower(Type _type)
     sprite = sprite_manager->create("fireflower");
   else
     sprite = sprite_manager->create("iceflower"); 
+
+  set_group(COLGROUP_TOUCHABLE);
 }
 
 Flower::~Flower()
index 6f0fe5e..1e8406b 100644 (file)
@@ -35,6 +35,7 @@ GrowUp::GrowUp()
   sprite = sprite_manager->create("egg");
   physic.enable_gravity(true);
   physic.set_velocity_x(100);
+  set_group(COLGROUP_MOVING);
 }
 
 GrowUp::~GrowUp()
index 668bbe2..464a3eb 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include "oneup.hpp"
@@ -34,6 +33,7 @@ OneUp::OneUp(const Vector& pos)
   bbox.set_size(32, 32);
   sprite = sprite_manager->create("1up");
   physic.set_velocity(100, 400);
+  set_group(COLGROUP_TOUCHABLE);
 }
 
 OneUp::~OneUp()
index aee2daa..2adc8bf 100644 (file)
@@ -750,7 +750,7 @@ Player::kill(HurtMode mode)
       player_status->bonus = NO_BONUS;
       dying = true;
       dying_timer.start(3.0);
-      flags |= FLAG_NO_COLLDET;
+      set_group(COLGROUP_DISABLED);
     }
 }
 
index c9733c6..c7df315 100644 (file)
@@ -41,6 +41,8 @@ PowerUp::PowerUp(const lisp::Lisp& lisp)
   bbox.set_size(32, 32);   
   sprite = sprite_manager->create(sprite_name);
   physic.enable_gravity(true);
+
+  set_group(COLGROUP_MOVING);
 }
 
 PowerUp::~PowerUp()
index 0600b11..e6862f3 100644 (file)
@@ -65,12 +65,12 @@ Rock::update(float elapsed_time)
 {
   if(!grabbed) {
     flags |= FLAG_SOLID;
-    flags &= ~FLAG_NO_COLLDET;
+    set_group(COLGROUP_STATIC);
     movement = physic.get_movement(elapsed_time);
   } else {
     physic.set_velocity(0, 0);
     flags &= ~FLAG_SOLID;
-    flags |= FLAG_NO_COLLDET;
+    set_group(COLGROUP_DISABLED);
   }
   
   grabbed = false;
index 4afb207..d49f407 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include "skull_tile.hpp"
@@ -40,6 +39,8 @@ SkullTile::SkullTile(const lisp::Lisp& lisp)
   bbox.set_size(32, 32);
   sprite = sprite_manager->create("skull_tile");
   flags |= FLAG_SOLID;
+
+  set_group(COLGROUP_STATIC);
 }
 
 SkullTile::~SkullTile()
index a504e40..e0a89eb 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include "star.hpp"
@@ -37,6 +36,8 @@ Star::Star(const Vector& pos)
   bbox.set_size(32, 32);
   sprite = sprite_manager->create("star");
   physic.set_velocity(SPEED, INITIALJUMP);
+
+  set_group(COLGROUP_MOVING);
 }
 
 Star::~Star()
index 08341c4..4db794b 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include "unstable_tile.hpp"
@@ -40,6 +39,7 @@ UnstableTile::UnstableTile(const lisp::Lisp& lisp)
   bbox.set_size(32, 32);
   sprite = sprite_manager->create("unstable_tile");
   flags |= FLAG_SOLID;
+  set_group(COLGROUP_STATIC);
 }
 
 UnstableTile::~UnstableTile()
index 2464ccc..d828a41 100644 (file)
@@ -467,7 +467,7 @@ Sector::update(float elapsed_time)
 #endif
   
   /* Handle all possible collisions. */
-  collision_handler();                                                                              
+  handle_collisions();
   update_game_objects();
 }
 
@@ -475,6 +475,30 @@ void
 Sector::update_game_objects()
 {
   /** cleanup marked objects */
+  for(std::vector<Bullet*>::iterator i = bullets.begin();
+      i != bullets.end(); /* nothing */) {
+    Bullet* bullet = *i;
+    if(bullet->is_valid()) {
+      ++i;
+      continue;
+    }
+
+    i = bullets.erase(i);
+  }
+  for(MovingObjects::iterator i = moving_objects.begin();
+      i != moving_objects.end(); /* nothing */) {
+    MovingObject* moving_object = *i;
+    if(moving_object->is_valid()) {
+      ++i;
+      continue;
+    }
+
+#ifdef USE_GRID
+    grid->remove_object(moving_object);
+#endif
+    
+    i = moving_objects.erase(i);
+  }
   for(std::vector<GameObject*>::iterator i = gameobjects.begin();
       i != gameobjects.end(); /* nothing */) {
     GameObject* object = *i;
@@ -484,18 +508,6 @@ Sector::update_game_objects()
       continue;
     }
     
-    Bullet* bullet = dynamic_cast<Bullet*> (object);
-    if(bullet) {
-      bullets.erase(
-          std::remove(bullets.begin(), bullets.end(), bullet),
-          bullets.end());
-    }
-#ifdef USE_GRID
-    MovingObject* movingobject = dynamic_cast<MovingObject*> (object);
-    if(movingobject) {
-      grid->remove_object(movingobject);
-    }
-#endif
     delete *i;
     i = gameobjects.erase(i);
   }
@@ -510,11 +522,13 @@ Sector::update_game_objects()
     if(bullet)
       bullets.push_back(bullet);
 
-#ifdef USE_GRID
     MovingObject* movingobject = dynamic_cast<MovingObject*> (object);
-    if(movingobject)
+    if(movingobject) {
+      moving_objects.push_back(movingobject);
+ #ifdef USE_GRID
       grid->add_object(movingobject);
 #endif
+    }
     
     TileMap* tilemap = dynamic_cast<TileMap*> (object);
     if(tilemap && tilemap->is_solid()) {
@@ -703,18 +717,87 @@ Sector::collision_object(MovingObject* object1, MovingObject* object2)
 }
 
 void
-Sector::collision_handler()
+Sector::handle_collisions()
 {
 #ifdef USE_GRID
   grid->check_collisions();
 #else
-  for(std::vector<GameObject*>::iterator i = gameobjects.begin();
-      i != gameobjects.end(); ++i) {
-    GameObject* gameobject = *i;
-    if(!gameobject->is_valid())
+  // part1: COLGROUP_MOVING vs COLGROUP_STATIC and tilemap
+  for(MovingObjects::iterator i = moving_objects.begin();
+      i != moving_objects.end(); ++i) {
+    MovingObject* movingobject = *i;
+    if(movingobject->get_group() != COLGROUP_MOVING
+        || !movingobject->is_valid())
+      continue;
+
+    // collision with tilemap
+    collision_tilemap(movingobject, 0);
+   
+    // collision with other objects
+    for(MovingObjects::iterator i2 = i+1;
+        i2 != moving_objects.end(); ++i2) {
+      MovingObject* movingobject2 = *i2;
+      if(movingobject2->get_group() != COLGROUP_STATIC
+         || !movingobject2->is_valid())
+        continue;
+
+      collision_object(movingobject, movingobject2);
+    }
+  }
+
+  // part2: COLGROUP_MOVING vs COLGROUP_TOUCHABLE
+  for(MovingObjects::iterator i = moving_objects.begin();
+      i != moving_objects.end(); ++i) {
+    MovingObject* moving_object = *i;
+    if(moving_object->get_group() != COLGROUP_MOVING
+        || !moving_object->is_valid())
       continue;
-    MovingObject* movingobject = dynamic_cast<MovingObject*> (gameobject);
-    if(!movingobject)
+
+    for(MovingObjects::iterator i2 = moving_objects.begin();
+        i2 != moving_objects.end(); ++i2) {
+      MovingObject* moving_object_2 = *i2;
+      if(moving_object_2->get_group() != COLGROUP_TOUCHABLE
+         || !moving_object_2->is_valid())
+        continue;
+
+      collision_object(moving_object, moving_object_2);
+    } 
+  }
+
+  // part3: COLGROUP_MOVING vs COLGROUP_MOVING
+  for(MovingObjects::iterator i = moving_objects.begin();
+      i != moving_objects.end(); ++i) {
+    MovingObject* moving_object = *i;
+
+    if(moving_object->get_group() != COLGROUP_MOVING
+        || !moving_object->is_valid())
+      continue;
+
+    for(MovingObjects::iterator i2 = i+1;
+        i2 != moving_objects.end(); ++i2) {
+      MovingObject* moving_object_2 = *i2;
+      if(moving_object_2->get_group() != COLGROUP_MOVING
+         || !moving_object_2->is_valid())
+        continue;
+
+      collision_object(moving_object, moving_object_2);
+    }    
+  }
+
+  // apply object movement
+  for(MovingObjects::iterator i = moving_objects.begin();
+      i != moving_objects.end(); ++i) {
+    MovingObject* moving_object = *i;
+
+    moving_object->bbox.move(moving_object->get_movement());
+    moving_object->movement = Vector(0, 0);
+  }
+#if 0
+  for(MovingObjects::iterator i = moving_objects.begin();
+      i != moving_objects.end(); ++i) {
+    MovingObject* movingobject = *i;
+    if(!movingobject->is_valid())
       continue;
     if(movingobject->get_flags() & GameObject::FLAG_NO_COLLDET) {
       movingobject->bbox.move(movingobject->movement);
@@ -727,14 +810,11 @@ Sector::collision_handler()
       collision_tilemap(movingobject, 0);
 
     // collision with other objects
-    for(std::vector<GameObject*>::iterator i2 = i+1;
-        i2 != gameobjects.end(); ++i2) {
-      GameObject* other_object = *i2;
-      if(!other_object->is_valid() 
-          || other_object->get_flags() & GameObject::FLAG_NO_COLLDET)
-        continue;
-      MovingObject* movingobject2 = dynamic_cast<MovingObject*> (other_object);
-      if(!movingobject2)
+    for(MovingObjects::iterator i2 = i+1;
+        i2 != moving_objects.end(); ++i2) {
+      MovingObject* movingobject2 = *i2;
+      if(!movingobject2->is_valid()
+          || movingobject2->get_flags() & GameObject::FLAG_NO_COLLDET)
         continue;
 
       collision_object(movingobject, movingobject2);
@@ -744,6 +824,8 @@ Sector::collision_handler()
     movingobject->movement = Vector(0, 0);
   }
 #endif
+  
+#endif
 }
 
 bool
index 067e453..265fccf 100644 (file)
@@ -89,7 +89,7 @@ public:
   /** Checks for all possible collisions. And calls the
       collision_handlers, which the collision_objects provide for this
       case (or not). */
-  void collision_handler();
+  void handle_collisions();
 
   bool add_bullet(const Vector& pos, float xm, Direction dir);
   bool add_smoke_cloud(const Vector& pos);
@@ -131,6 +131,8 @@ private:
 public: // TODO make this private again
   typedef std::vector<GameObject*> GameObjects;
   GameObjects gameobjects;
+  typedef std::vector<MovingObject*> MovingObjects;
+  MovingObjects moving_objects;
   typedef std::vector<SpawnPoint*> SpawnPoints;
   SpawnPoints spawnpoints;                       
 
index 411150a..e3c2bf1 100644 (file)
@@ -25,6 +25,7 @@
 TriggerBase::TriggerBase()
   : sprite(0)
 {
+  set_group(COLGROUP_TOUCHABLE);
 }
 
 TriggerBase::~TriggerBase()