1) Improved handling of 'moving' or 'physical' objects (e.g. road cone).

You can now shoot them, and they will be pushed aside by a close-by
   explosions.
2) Bugfix: Physical objects are now reset to the correct starting location.
3) Physical objects have now angular friction defined, preventing them from
   rotating endlessly.
4) Karts have now some 'restitution', which adds a bit of bouncing to collisions.




git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1445 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-02-05 11:56:21 +00:00
parent 5767b4f616
commit a3094590d6
17 changed files with 152 additions and 52 deletions

View File

@ -28,6 +28,8 @@
(shortcut-skipped-segments 5 ) ;; skipping more than this number of segments
;; is considered to be a shortcut
(explosion-impulse 10000.0 ) ;; explosion impulse on not directly hit karts
(explosion-impulse-objects 500.0 ) ;; explosion impulse for physics objects (smaller
;; else a cone e.g. will be pushed way too far)
;; Other kart relates values
;; -------------------------

View File

@ -20,12 +20,16 @@
#ifndef CALLBACK_H
#define CALLBACK_H
#include "btBulletDynamicsCommon.h"
class Callback
{
public:
virtual ~Callback() {};
virtual void update (float dt) = 0;
virtual void init () = 0;
virtual ~Callback() {};
virtual void update (float dt) = 0;
virtual void init () = 0;
virtual void reset () {};
virtual void handleExplosion(const btVector3& pos, bool directHit) {};
}
; // Callback

View File

@ -106,6 +106,31 @@ void CallbackManager::initAll() const
(*c)->init();
} // for i
} // update
} // initAll
//-----------------------------------------------------------------------------
// Called when restarting a race
void CallbackManager::reset() const
{
for(int i=0; i<CB_MAX; i++)
{
for(std::vector<Callback*>::const_iterator c = m_allCallbacks[i].begin();
c != m_allCallbacks[i].end(); c++)
(*c)->reset();
} // for i
} // initAll
//-----------------------------------------------------------------------------
void CallbackManager::handleExplosion(const btVector3& pos,
const MovingPhysics* mp) const
{
for(int i=0; i<CB_MAX; i++)
{
for(std::vector<Callback*>::const_iterator c = m_allCallbacks[i].begin();
c != m_allCallbacks[i].end(); c++)
(*c)->handleExplosion(pos, mp==(*c));
} // for i
} // handleExplosion

View File

@ -21,7 +21,9 @@
#define CALLBACK_MANAGER_H
#include <vector>
#include "btBulletDynamicsCommon.h"
#include "callback.hpp"
#include "moving_physics.hpp"
// It might actually be enough to have only two different values: track (which
// get deleted and loaded more than one), and everything else, which only
@ -36,13 +38,14 @@ class CallbackManager
std::vector<Callback*> m_allCallbacks[CB_MAX];
public:
CallbackManager();
~CallbackManager();
void update (float dt) const;
void initAll () const;
void clear (CallbackType cbType);
void addCallback(Callback *c, CallbackType t);
CallbackManager();
~CallbackManager();
void update (float dt) const;
void initAll () const;
void reset () const;
void clear (CallbackType cbType);
void addCallback (Callback *c, CallbackType t);
void handleExplosion(const btVector3& pos, const MovingPhysics* mo) const;
}
; // CallbackManager

View File

@ -23,6 +23,7 @@
#include "world.hpp"
#include "kart.hpp"
#include "projectile_manager.hpp"
#include "callback_manager.hpp"
#include "sound_manager.hpp"
#include "scene.hpp"
#include "ssg_help.hpp"
@ -92,7 +93,7 @@ void Flyable::createPhysics(float y_offset, const btVector3 velocity,
m_shape = shape;
createBody(m_mass, trans, m_shape);
m_user_pointer.set(UserPointer::UP_PROJECTILE, this);
m_user_pointer.set(this);
world->getPhysics()->addBody(getBody());
// Simplified rockets: no gravity
@ -204,7 +205,7 @@ void Flyable::placeModel()
} // placeModel
// -----------------------------------------------------------------------------
void Flyable::explode(Kart *kart_hit)
void Flyable::explode(Kart *kart_hit, MovingPhysics* moving_physics)
{
if(m_exploded) return;
@ -219,6 +220,7 @@ void Flyable::explode(Kart *kart_hit)
m->removeAllKids();
scene->remove(m);
btVector3 pos(m_curr_pos.xyz[0],m_curr_pos.xyz[1],m_curr_pos.xyz[2]);
world->getPhysics()->removeBody(getBody());
m_exploded=true;
@ -228,7 +230,7 @@ void Flyable::explode(Kart *kart_hit)
// handle the actual explosion. Set a flag it if was a direct hit.
kart->handleExplosion(m_curr_pos.xyz, kart==kart_hit);
}
callback_manager->handleExplosion(pos, moving_physics);
} // explode
/* EOF */

View File

@ -21,6 +21,7 @@
#define HEADER_FLYABLE_H
#include "moveable.hpp"
#include "moving_physics.hpp"
#include "kart.hpp"
#include "terrain_info.hpp"
@ -67,7 +68,7 @@ public:
void placeModel ();
virtual void hitTrack () {};
void explode (Kart* kart);
void explode (Kart* kart, MovingPhysics* moving_physics=NULL);
bool hasHit () { return m_has_hit_something; }
void reset () { Moveable::reset();
sgCopyCoord(&m_last_pos,&m_reset_pos ); }

View File

@ -199,7 +199,7 @@ void Kart::createPhysics(ssgEntity *obj)
btTransform trans;
trans.setIdentity();
createBody(mass, trans, &m_kart_chassis);
m_user_pointer.set(UserPointer::UP_KART, this);
m_user_pointer.set(this);
m_body->setDamping(m_kart_properties->getChassisLinearDamping(),
m_kart_properties->getChassisAngularDamping() );

View File

@ -85,14 +85,15 @@ void Moveable::createBody(float mass, btTransform& trans,
m_motion_state = new btDefaultMotionState(trans);
btRigidBody::btRigidBodyConstructionInfo info(mass, m_motion_state, shape, inertia);
info.m_restitution=0.5f;
// Then create a rigid body
// ------------------------
m_body = new btRigidBody(info);
// This MUST actually be set from the actual class, otherwise this
// The value of user_pointer must be set from the actual class, otherwise this
// is only a pointer to moveable, not to (say) kart, and virtual
// functions are not called correctly.
m_user_pointer.set(UserPointer::UP_UNDEF, 0);
// functions are not called correctly. So only init the pointer to zero.
m_user_pointer.zero();
m_body->setUserPointer(&m_user_pointer);
} // createBody

View File

@ -148,12 +148,6 @@ void MovingPhysics::init()
}
} // while
// printf("matrix: ");
// for(int i=0; i<4; i++)
// for(int j=0; j<4; j++)
// printf("%f ",pos[i][j]);
// printf("\n");
// 3. Determine size of the object
// -------------------------------
float x_min, x_max, y_min, y_max, z_min, z_max, radius;
@ -176,15 +170,19 @@ void MovingPhysics::init()
// 4. Create the rigid object
// --------------------------
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(pos[3][0],pos[3][1],pos[3][2]+m_half_height));
m_motion_state = new btDefaultMotionState(trans);
m_init_pos.setIdentity();
m_init_pos.setOrigin(btVector3(pos[3][0],pos[3][1],pos[3][2]+m_half_height));
m_motion_state = new btDefaultMotionState(m_init_pos);
btVector3 inertia;
m_shape->calculateLocalInertia(m_mass, inertia);
btRigidBody::btRigidBodyConstructionInfo info(m_mass, m_motion_state, m_shape, inertia);
// Make sure that the cones stop rolling by defining angular friction != 0.
info.m_angularDamping = 0.5f;
m_body = new btRigidBody(info);
m_user_pointer.set(this);
m_body->setUserPointer(&m_user_pointer);
world->getPhysics()->addBody(m_body);
} // init
@ -196,13 +194,45 @@ void MovingPhysics::update(float dt)
float m[4][4];
t.getOpenGLMatrix((float*)&m);
// printf("%lx is %f %f %f\n",this, t.getOrigin().x(),t.getOrigin().y(),t.getOrigin().z());
// Transfer the new position and hpr to m_curr_pos
sgCoord m_curr_pos;
sgSetCoord(&m_curr_pos, m);
setTransform(&m_curr_pos);
} // update
// -----------------------------------------------------------------------------
void MovingPhysics::reset()
{
m_body->setCenterOfMassTransform(m_init_pos);
} // reset
// -----------------------------------------------------------------------------
void MovingPhysics::handleExplosion(const btVector3& pos, bool direct_hit) {
if(direct_hit) {
btVector3 impulse(0.0f, 0.0f, stk_config->m_explosion_impulse_objects);
m_body->applyCentralImpulse(impulse);
}
else // only affected by a distant explosion
{
btTransform t;
m_motion_state->getWorldTransform(t);
btVector3 diff=t.getOrigin()-pos;
float len2=diff.length2();
// The correct formhale would be to first normalise diff,
// then apply the impulse (which decreases 1/r^2 depending
// on the distance r), so:
// diff/len(diff) * impulseSize/len(diff)^2
// = diff*impulseSize/len(diff)^3
// We use diff*impulseSize/len(diff)^2 here, this makes the impulse
// somewhat larger, which is actually more fun :)
btVector3 impulse=diff*stk_config->m_explosion_impulse_objects/len2;
m_body->applyCentralImpulse(impulse);
}
m_body->activate();
} // handleExplosion
// -----------------------------------------------------------------------------
/* EOF */

View File

@ -19,10 +19,11 @@
#ifndef HEADER_MOVING_PHYSICS_H
#define HEADER_MOVING_PHYSICS_H
#include <string>
#include <plib/ssg.h>
#include "btBulletDynamicsCommon.h"
#include "callback.hpp"
#include <string>
#include "user_pointer.hpp"
class MovingPhysics : public ssgTransform, public Callback
{
@ -36,12 +37,16 @@ protected:
btDefaultMotionState *m_motion_state;
float m_half_height;
float m_mass;
UserPointer m_user_pointer;
btTransform m_init_pos;
public:
MovingPhysics (const std::string data);
~MovingPhysics ();
void update (float dt);
void init ();
virtual void reset ();
const char *getTypeName() {return "moving physics";}
virtual void handleExplosion(const btVector3& pos, bool directHit);
}; // MovingPhysics
#endif

View File

@ -38,7 +38,7 @@ MovingTexture::MovingTexture(char *data, ssgBranch *branch)
parseData(data);
} // Callback
} // MovingTexture
//-----------------------------------------------------------------------------
MovingTexture::~MovingTexture()

View File

@ -112,6 +112,11 @@ void Physics::update(float dt)
{
p->a->getPointerFlyable()->hitTrack();
}
else if(p->b->is(UserPointer::UP_MOVING_PHYSICS))
{
p->a->getPointerFlyable()->explode(NULL, p->b->getPointerMovingPhysics());
}
else if(p->b->is(UserPointer::UP_KART)) // projectile hit kart
{
p->a->getPointerFlyable()->explode((Kart*)(p->b));
@ -207,7 +212,7 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
// =======================
if(upA->is(UserPointer::UP_TRACK))
{
if(upB->is(UserPointer::UP_PROJECTILE)) // 1.1 projectile hits track
if(upB->is(UserPointer::UP_FLYABLE)) // 1.1 projectile hits track
m_all_collisions.push_back(upB, upA);
else if(upB->is(UserPointer::UP_KART))
upB->getPointerKart()->crashed();
@ -218,21 +223,29 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
{
if(upB->is(UserPointer::UP_TRACK))
upA->getPointerKart()->crashed(); // Kart hit track
else if(upB->is(UserPointer::UP_PROJECTILE))
else if(upB->is(UserPointer::UP_FLYABLE))
m_all_collisions.push_back(upB, upA); // 2.1 projectile hits kart
else if(upB->is(UserPointer::UP_KART))
m_all_collisions.push_back(upA, upB); // 2.2 kart hits kart
}
// 3) object is a projectile
// ========================
else if(upA->is(UserPointer::UP_PROJECTILE))
else if(upA->is(UserPointer::UP_FLYABLE))
{
if(upB->is(UserPointer::UP_TRACK ) || // 3.1) projectile hits track
upB->is(UserPointer::UP_PROJECTILE) || // 3.2) projectile hits projectile
upB->is(UserPointer::UP_KART ) ) // 3.3) projectile hits kart
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_MOVING_PHYSICS) || // 3.3) projectile hits projectile
upB->is(UserPointer::UP_KART ) ) // 3.4) projectile hits kart
{
m_all_collisions.push_back(upA, upB);
}
}
else if(upA->is(UserPointer::UP_MOVING_PHYSICS))
{
if(upB->is(UserPointer::UP_FLYABLE))
{
m_all_collisions.push_back(upB, upA);
}
}
else assert("Unknown user pointer"); // 4) Should never happen
} // for i<numManifolds

View File

@ -112,6 +112,7 @@ void STKConfig::load(const std::string filename)
CHECK_NEG(m_suspension_rest, "suspension-rest" );
CHECK_NEG(m_jump_velocity, "jump-velocity" );
CHECK_NEG(m_explosion_impulse, "explosion-impulse" );
CHECK_NEG(m_explosion_impulse_objects, "explosion-impulse-objects" );
} // load
@ -137,7 +138,8 @@ void STKConfig::init_defaults()
m_wheelie_lean_recovery = m_wheelie_step = m_wheelie_balance_recovery =
m_wheelie_power_boost = m_chassis_linear_damping = m_chassis_angular_damping =
m_maximum_speed = m_brake_force = m_gravity_center_shift = m_suspension_rest =
m_max_speed_reverse_ratio = m_explosion_impulse = m_jump_velocity = -99.9f;
m_max_speed_reverse_ratio = m_explosion_impulse = m_jump_velocity =
m_explosion_impulse_objects = -99.9f;
m_max_karts = -100;
m_grid_order = -100;
@ -166,6 +168,7 @@ void STKConfig::getAllData(const lisp::Lisp* lisp)
lisp->get("zipper-time", m_zipper_time );
lisp->get("zipper-force", m_zipper_force );
lisp->get("explosion-impulse", m_explosion_impulse );
lisp->get("explosion-impulse-objects", m_explosion_impulse_objects);
lisp->get("max-karts", m_max_karts );
lisp->get("grid-order", m_grid_order );

View File

@ -42,6 +42,7 @@ public:
float m_shortcut_segments; // skipping more than this number of segments is
// considered to be a shortcut
float m_explosion_impulse; // impulse affecting each non-hit kart
float m_explosion_impulse_objects;// impulse of explosion on moving objects, e.g. road cones, ...
int m_max_karts; // maximum number of karts
int m_grid_order; // whether grand prix grid is in point order or reverse point order

View File

@ -59,7 +59,7 @@ void TriangleMesh::createBody(btCollisionObject::CollisionFlags flags)
m_body=new btRigidBody(info);
world->getPhysics()->addBody(m_body);
m_user_pointer.set(UserPointer::UP_TRACK, this);
m_user_pointer.set(this);
m_body->setUserPointer(&m_user_pointer);
m_body->setCollisionFlags(m_body->getCollisionFlags() |
flags |

View File

@ -27,25 +27,34 @@ class TriangleMesh;
class Moveable;
class Flyable;
class Kart;
class MovingPhysics;
class UserPointer
{
public:
enum UserPointerType {UP_UNDEF, UP_KART, UP_PROJECTILE, UP_TRACK};
enum UserPointerType {UP_UNDEF, UP_KART, UP_FLYABLE, UP_TRACK,
UP_MOVING_PHYSICS};
private:
void* m_pointer;
UserPointerType m_user_pointer_type;
public:
bool is(UserPointerType t) const {return m_user_pointer_type==t; }
TriangleMesh* getPointerTriangleMesh() const {return (TriangleMesh*)m_pointer;}
Moveable* getPointerMoveable() const {return (Moveable*)m_pointer; }
Flyable* getPointerFlyable() const {return (Flyable*)m_pointer; }
Kart* getPointerKart() const {return (Kart*)m_pointer; }
void set(UserPointerType t, void* p)
{ m_user_pointer_type=t;
m_pointer =p; }
UserPointer(): m_pointer(NULL),m_user_pointer_type(UP_UNDEF) {};
UserPointer(UserPointerType t, void* p) {set(t,p);}
bool is(UserPointerType t) const {return m_user_pointer_type==t; }
TriangleMesh* getPointerTriangleMesh() const {return (TriangleMesh*)m_pointer; }
Moveable* getPointerMoveable() const {return (Moveable*)m_pointer; }
Flyable* getPointerFlyable() const {return (Flyable*)m_pointer; }
Kart* getPointerKart() const {return (Kart*)m_pointer; }
MovingPhysics* getPointerMovingPhysics() const {return (MovingPhysics*)m_pointer; }
void set(MovingPhysics* p) { m_user_pointer_type=UP_MOVING_PHYSICS;
m_pointer =p; }
void set(Kart* p) { m_user_pointer_type=UP_KART;
m_pointer =p; }
void set(Flyable* p) { m_user_pointer_type=UP_FLYABLE;
m_pointer =p; }
void set(TriangleMesh* p) { m_user_pointer_type=UP_TRACK;
m_pointer =p; }
UserPointer() { zero(); }
void zero() { m_user_pointer_type=UP_UNDEF;
m_pointer = NULL; }
};
#endif
/* EOF */

View File

@ -615,6 +615,7 @@ void World::restartRace()
herring_manager->reset();
projectile_manager->cleanup();
race_manager->reset();
callback_manager->reset();
#ifdef HAVE_GHOST_REPLAY
m_replay_recorder.destroy();