From 2b805c7d69f6e1c99702dc592dbf07ad06855fb9 Mon Sep 17 00:00:00 2001 From: hikerstk Date: Wed, 28 Sep 2011 10:52:41 +0000 Subject: [PATCH] Added support for physical objects triggering rescue on collision (#163). Objects must be declared with 'reset="Y"' in order to trigger rescue. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9910 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/physics/physical_object.cpp | 8 +- src/physics/physical_object.hpp | 21 +++++- src/physics/physics.cpp | 126 +++++++++++++++++++++----------- 3 files changed, 107 insertions(+), 48 deletions(-) diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp index 7f11763c2..822b808e6 100644 --- a/src/physics/physical_object.cpp +++ b/src/physics/physical_object.cpp @@ -45,11 +45,13 @@ PhysicalObject::PhysicalObject(const XMLNode &xml_node) m_motion_state = NULL; m_mass = 1; m_radius = -1; + m_crash_reset = false; std::string shape; - xml_node.get("mass", &m_mass ); - xml_node.get("radius", &m_radius); - xml_node.get("shape", &shape ); + xml_node.get("mass", &m_mass ); + xml_node.get("radius", &m_radius ); + xml_node.get("shape", &shape ); + xml_node.get("reset", &m_crash_reset); m_body_type = MP_NONE; if (shape=="cone" || diff --git a/src/physics/physical_object.hpp b/src/physics/physical_object.hpp index ccdc8030e..7cf7e5b1b 100644 --- a/src/physics/physical_object.hpp +++ b/src/physics/physical_object.hpp @@ -42,20 +42,26 @@ public: MP_CYLINDER_Y, MP_CYLINDER_X, MP_CYLINDER_Z, MP_BOX, MP_SPHERE}; -protected: +private: /** The shape of this object. */ bodyTypes m_body_type; + /** The bullet collision shape. */ btCollisionShape *m_shape; + /** The corresponding bullet rigid body. */ btRigidBody *m_body; + /** Bullet's motion state for this object. */ btDefaultMotionState *m_motion_state; + /** The mass of this object. */ float m_mass; + /** The pointer that is stored in the bullet rigid body back to * this object. */ UserPointer m_user_pointer; + /** This is the initial position of the object for the physics. */ btTransform m_init_pos; @@ -66,6 +72,10 @@ protected: * details, but is supposed to be a sphere). In this case the radius * can be set in the scene file. */ float m_radius; + + /** True if a kart colliding with this object should be rescued. */ + bool m_crash_reset; + public: PhysicalObject (const XMLNode &node); @@ -76,12 +86,17 @@ public: const core::vector3df& scale); virtual ~PhysicalObject (); + virtual void reset (); + virtual void handleExplosion(const Vec3& pos, bool directHit); void update (float dt); void init (); - virtual void reset (); + // ------------------------------------------------------------------------ /** Returns the rigid body of this physical object. */ btRigidBody *getBody () { return m_body; } - virtual void handleExplosion(const Vec3& pos, bool directHit); + // ------------------------------------------------------------------------ + /** Returns true if this object should trigger a rescue in a kart that + * hits it. */ + bool isCrashReset() const { return m_crash_reset; } }; // PhysicalObject #endif diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index ef8754255..be76d8cbc 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -25,6 +25,7 @@ #include "physics/btKart.hpp" #include "physics/btUprightConstraint.hpp" #include "physics/irr_debug_drawer.hpp" +#include "physics/physical_object.hpp" #include "physics/triangle_mesh.hpp" #include "tracks/track.hpp" @@ -99,7 +100,7 @@ void Physics::removeKart(const Kart *kart) void Physics::update(float dt) { // Bullet can report the same collision more than once (up to 4 - // contact points per collision. Additionally, more than one internal + // contact points per collision). Additionally, more than one internal // substep might be taken, resulting in potentially even more // duplicates. To handle this, all collisions (i.e. pair of objects) // are stored in a vector, but only one entry per collision pair @@ -110,45 +111,72 @@ void Physics::update(float dt) // 20 FPS (bullet default frequency is 60 HZ). m_dynamics_world->stepSimulation(dt, 3); - // Now handle the actual collision. Note: rockets can not be removed - // inside of this loop, since the same rocket might hit more than one - // other object. So, only a flag is set in the rockets, the actual + // Now handle the actual collision. Note: flyables can not be removed + // inside of this loop, since the same flyables might hit more than one + // other object. So only a flag is set in the flyables, the actual // clean up is then done later in the projectile manager. std::vector::iterator p; for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p) { - if(p->a->is(UserPointer::UP_KART)) { // kart-kart collision + // Kart-kart collision + // -------------------- + if(p->a->is(UserPointer::UP_KART)) + { Kart *a=p->a->getPointerKart(); Kart *b=p->b->getPointerKart(); race_state->addCollision(a->getWorldKartId(), b->getWorldKartId()); KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart()); + continue; } // if kart-kart collision - else // now the first object must be a projectile - { - if(p->b->is(UserPointer::UP_TRACK)) // must be projectile hit track - { - p->a->getPointerFlyable()->hitTrack(); - } - else if(p->b->is(UserPointer::UP_PHYSICAL_OBJECT)) - { - p->a->getPointerFlyable()->hit(NULL, p->b->getPointerPhysicalObject()); - } - else if(p->b->is(UserPointer::UP_KART)) // projectile hit kart + if(p->a->is(UserPointer::UP_PHYSICAL_OBJECT)) + { + // Kart hits physical object + // ------------------------- + PhysicalObject *obj = p->a->getPointerPhysicalObject(); + if(obj->isCrashReset()) { - // Only explode a bowling ball if the target is - // not invulnerable - if(p->a->getPointerFlyable()->getType() - !=PowerupManager::POWERUP_BOWLING || - !p->b->getPointerKart()->isInvulnerable() ) + Kart *kart = p->b->getPointerKart(); + kart->forceRescue(); + } + continue; + } + + + // now the first object must be a projectile + // ========================================= + if(p->b->is(UserPointer::UP_TRACK)) + { + // Projectile hits track + // --------------------- + p->a->getPointerFlyable()->hitTrack(); + } + else if(p->b->is(UserPointer::UP_PHYSICAL_OBJECT)) + { + // Projectile hits physical object + // ------------------------------- + p->a->getPointerFlyable() + ->hit(NULL, p->b->getPointerPhysicalObject()); + + } + else if(p->b->is(UserPointer::UP_KART)) + { + // Projectile hits kart + // -------------------- + // Only explode a bowling ball if the target is + // not invulnerable + if(p->a->getPointerFlyable()->getType() + !=PowerupManager::POWERUP_BOWLING || + !p->b->getPointerKart()->isInvulnerable() ) p->a->getPointerFlyable()->hit(p->b->getPointerKart()); - } - else // projectile hits projectile - { - p->a->getPointerFlyable()->hit(NULL); - p->b->getPointerFlyable()->hit(NULL); - } + } + else + { + // Projectile hits projectile + // -------------------------- + p->a->getPointerFlyable()->hit(NULL); + p->b->getPointerFlyable()->hit(NULL); } } // for all p in m_all_collisions } // update @@ -161,15 +189,16 @@ void Physics::update(float dt) bool Physics::projectKartDownwards(const Kart *k) { btVector3 hell(0, -10000, 0); - return k->getVehicle()->projectVehicleToSurface(hell, true /*allow translation*/); + return k->getVehicle()->projectVehicleToSurface(hell, + /*allow translation*/true); } //projectKartsDownwards //----------------------------------------------------------------------------- -/** Handles the special case of two karts colliding with each other, which means - * that bombs must be passed on. If both karts have a bomb, they'll explode - * immediately. This function is called from physics::update() on the server - * and if no networking is used, and from race_state on the client to replay - * what happened on the server. +/** Handles the special case of two karts colliding with each other, which + * means that bombs must be passed on. If both karts have a bomb, they'll + * explode immediately. This function is called from physics::update() on the + * server and if no networking is used, and from race_state on the client to + * replay what happened on the server. * \param kartA First kart involved in the collision. * \param kartB Second kart involved in the collision. */ @@ -253,9 +282,10 @@ void Physics::KartKartCollision(Kart *kartA, Kart *kartB) * physics time step might miss some collisions (when more than one internal * time step was done, and the collision is added and removed). So this * function stores all collisions in a list, which is then handled after the - * actual physics timestep. This list only stores a collision, if it's not + * actual physics timestep. This list only stores a collision if it's not * already in the list, so a collisions which is reported more than once is * nevertheless only handled once. + * The list of collision * Parameters: see bullet documentation for details. */ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, @@ -292,6 +322,7 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, // FIXME: Must be a moving physics object // FIXME: A rocket should explode here! if(!upA || !upB) continue; + // 1) object A is a track // ======================= if(upA->is(UserPointer::UP_TRACK)) @@ -324,28 +355,39 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, kart->crashed(NULL, m); // Kart hit track } else if(upB->is(UserPointer::UP_FLYABLE)) - m_all_collisions.push_back(upB, upA); // 2.1 projectile hits kart + // 2.1 projectile hits kart + m_all_collisions.push_back(upB, upA); else if(upB->is(UserPointer::UP_KART)) - m_all_collisions.push_back(upA, upB); // 2.2 kart hits kart + // 2.2 kart hits kart + m_all_collisions.push_back(upA, upB); + else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT)) + // 2.3 kart hits physical object + m_all_collisions.push_back(upB, upA); } // 3) object is a projectile // ========================= else if(upA->is(UserPointer::UP_FLYABLE)) { - if(upB->is(UserPointer::UP_TRACK ) || // 3.1) projectile hits track - upB->is(UserPointer::UP_FLYABLE ) || // 3.2) projectile hits projectile - upB->is(UserPointer::UP_PHYSICAL_OBJECT) || // 3.3) projectile hits projectile - upB->is(UserPointer::UP_KART ) ) // 3.4) projectile hits kart + // 3.1) projectile hits track + // 3.2) projectile hits projectile + // 3.3) projectile hits physical object + // 3.4) projectile hits kart + if(upB->is(UserPointer::UP_TRACK ) || + upB->is(UserPointer::UP_FLYABLE ) || + upB->is(UserPointer::UP_PHYSICAL_OBJECT) || + upB->is(UserPointer::UP_KART ) ) { m_all_collisions.push_back(upA, upB); } } + // Object is a physical object + // =========================== else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT)) { if(upB->is(UserPointer::UP_FLYABLE)) - { m_all_collisions.push_back(upB, upA); - } + else if(upB->is(UserPointer::UP_KART)) + m_all_collisions.push_back(upA, upB); } else assert("Unknown user pointer"); // 4) Should never happen } // for i