From: Matthias Braun Date: Tue, 27 Dec 2005 23:25:59 +0000 (+0000) Subject: Changed collision code, we now have several collision groups: X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=d62647592b4ccffa89794af6fa03faaced46999d;p=supertux.git Changed collision code, we now have several collision groups: 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 --- diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index b1e27903e..91b4bc9e9 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -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; diff --git a/src/badguy/snowball.cpp b/src/badguy/snowball.cpp index 65319d85d..e1c0e519c 100644 --- a/src/badguy/snowball.cpp +++ b/src/badguy/snowball.cpp @@ -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; } diff --git a/src/collision_grid.cpp b/src/collision_grid.cpp index bf6cc9332..311811a8e 100644 --- a/src/collision_grid.cpp +++ b/src/collision_grid.cpp @@ -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 #include @@ -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); diff --git a/src/game_object.hpp b/src/game_object.hpp index 1131847fb..547353be5 100644 --- a/src/game_object.hpp +++ b/src/game_object.hpp @@ -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 diff --git a/src/game_session.cpp b/src/game_session.cpp index 5bca083cf..613d14322 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -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), diff --git a/src/main.cpp b/src/main.cpp index 22073bbb5..ae2dad177 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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"; } } diff --git a/src/moving_object.cpp b/src/moving_object.cpp index 513375a5c..bd44896e6 100644 --- a/src/moving_object.cpp +++ b/src/moving_object.cpp @@ -22,6 +22,7 @@ MovingObject::MovingObject() { + group = COLGROUP_MOVING; } MovingObject::~MovingObject() diff --git a/src/moving_object.hpp b/src/moving_object.hpp index 753914be0..7117777a5 100644 --- a/src/moving_object.hpp +++ b/src/moving_object.hpp @@ -27,6 +27,16 @@ 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 diff --git a/src/object/block.cpp b/src/object/block.cpp index d68b02afe..ac5bc577c 100644 --- a/src/object/block.cpp +++ b/src/object/block.cpp @@ -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; } diff --git a/src/object/coin.cpp b/src/object/coin.cpp index 88c0d9ebf..d3eb1f5fd 100644 --- a/src/object/coin.cpp +++ b/src/object/coin.cpp @@ -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 #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() diff --git a/src/object/flower.cpp b/src/object/flower.cpp index c71ec6947..9c2ac9149 100644 --- a/src/object/flower.cpp +++ b/src/object/flower.cpp @@ -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() diff --git a/src/object/growup.cpp b/src/object/growup.cpp index 6f0fe5ecb..1e8406b58 100644 --- a/src/object/growup.cpp +++ b/src/object/growup.cpp @@ -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() diff --git a/src/object/oneup.cpp b/src/object/oneup.cpp index 668bbe28a..464a3ebc0 100644 --- a/src/object/oneup.cpp +++ b/src/object/oneup.cpp @@ -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 #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() diff --git a/src/object/player.cpp b/src/object/player.cpp index aee2daa96..2adc8bfaf 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -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); } } diff --git a/src/object/powerup.cpp b/src/object/powerup.cpp index c9733c690..c7df31590 100644 --- a/src/object/powerup.cpp +++ b/src/object/powerup.cpp @@ -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() diff --git a/src/object/rock.cpp b/src/object/rock.cpp index 0600b11c7..e6862f315 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -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; diff --git a/src/object/skull_tile.cpp b/src/object/skull_tile.cpp index 4afb2075b..d49f40759 100644 --- a/src/object/skull_tile.cpp +++ b/src/object/skull_tile.cpp @@ -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 #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() diff --git a/src/object/star.cpp b/src/object/star.cpp index a504e4052..e0a89ebae 100644 --- a/src/object/star.cpp +++ b/src/object/star.cpp @@ -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 #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() diff --git a/src/object/unstable_tile.cpp b/src/object/unstable_tile.cpp index 08341c49e..4db794b6e 100644 --- a/src/object/unstable_tile.cpp +++ b/src/object/unstable_tile.cpp @@ -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 #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() diff --git a/src/sector.cpp b/src/sector.cpp index 2464ccc83..d828a41c4 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -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::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::iterator i = gameobjects.begin(); i != gameobjects.end(); /* nothing */) { GameObject* object = *i; @@ -484,18 +508,6 @@ Sector::update_game_objects() continue; } - Bullet* bullet = dynamic_cast (object); - if(bullet) { - bullets.erase( - std::remove(bullets.begin(), bullets.end(), bullet), - bullets.end()); - } -#ifdef USE_GRID - MovingObject* movingobject = dynamic_cast (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 (object); - if(movingobject) + if(movingobject) { + moving_objects.push_back(movingobject); + #ifdef USE_GRID grid->add_object(movingobject); #endif + } TileMap* tilemap = dynamic_cast (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::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 (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::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 (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 diff --git a/src/sector.hpp b/src/sector.hpp index 067e453d1..265fccff2 100644 --- a/src/sector.hpp +++ b/src/sector.hpp @@ -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 GameObjects; GameObjects gameobjects; + typedef std::vector MovingObjects; + MovingObjects moving_objects; typedef std::vector SpawnPoints; SpawnPoints spawnpoints; diff --git a/src/trigger/trigger_base.cpp b/src/trigger/trigger_base.cpp index 411150a3a..e3c2bf1b4 100644 --- a/src/trigger/trigger_base.cpp +++ b/src/trigger/trigger_base.cpp @@ -25,6 +25,7 @@ TriggerBase::TriggerBase() : sprite(0) { + set_group(COLGROUP_TOUCHABLE); } TriggerBase::~TriggerBase()