1) Added an additional impulse to push karts away in case of a collision (unused atm)

2) Saved one collision point for each collision pair so that a frontal detection
   can be detected (atm unused).


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10407 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-12-12 05:42:40 +00:00
parent 6a9b401d6e
commit 8ab469d4d8
7 changed files with 163 additions and 81 deletions

View File

@ -277,7 +277,10 @@
<!-- Parameters for the upright constraint, which keeps karts upright. --> <!-- Parameters for the upright constraint, which keeps karts upright. -->
<upright tolerance="0.2" max-force="30"/> <upright tolerance="0.2" max-force="30"/>
<!-- collision-side-impulse is an additional (artificial) impulse that <!-- collision
impulse: an additional impulse to be applied in a non-frontal
collision to push two karts away from each other.
side-impulse is an additional (artificial) impulse that
pushes the slower kart out of the way of the faster karts (i.e. pushes the slower kart out of the way of the faster karts (i.e.
sideways to the faster kart) when a collision happens. This is sideways to the faster kart) when a collision happens. This is
for now disabled since it needs tuning and additionally has the for now disabled since it needs tuning and additionally has the
@ -285,7 +288,7 @@
the orientation - if a kart is pushed in the direction it is the orientation - if a kart is pushed in the direction it is
driving, it will be more (no friction from tires), while when driving, it will be more (no friction from tires), while when
pushed to the side, hardly anything happens. --> pushed to the side, hardly anything happens. -->
<collision side-impulse="0"/> <collision impulse="0" side-impulse="0"/>
<!-- Kart-specific plunger and rubber band handling: max-length is <!-- Kart-specific plunger and rubber band handling: max-length is
the maximum length of rubber band before it snaps. force is the maximum length of rubber band before it snaps. force is

View File

@ -72,7 +72,8 @@ KartProperties::KartProperties(const std::string &filename)
m_wheel_radius = m_chassis_linear_damping = m_max_suspension_force = m_wheel_radius = m_chassis_linear_damping = m_max_suspension_force =
m_chassis_angular_damping = m_suspension_rest = m_chassis_angular_damping = m_suspension_rest =
m_max_speed_reverse_ratio = m_max_speed_reverse_ratio =
m_rescue_vert_offset = m_upright_tolerance = m_collision_side_impulse = m_rescue_vert_offset = m_upright_tolerance =
m_collision_side_impulse = m_collision_impulse =
m_upright_max_force = m_suspension_travel_cm = m_upright_max_force = m_suspension_travel_cm =
m_track_connection_accel = m_track_connection_accel =
m_rubber_band_max_length = m_rubber_band_force = m_rubber_band_max_length = m_rubber_band_force =
@ -425,7 +426,10 @@ void KartProperties::getAllData(const XMLNode * root)
} }
if(const XMLNode *collision_node = root->getNode("collision")) if(const XMLNode *collision_node = root->getNode("collision"))
{
collision_node->get("impulse", &m_collision_impulse );
collision_node->get("side-impulse", &m_collision_side_impulse); collision_node->get("side-impulse", &m_collision_side_impulse);
}
//TODO: wheel front right and wheel front left is not loaded, yet is listed as an attribute in the xml file after wheel-radius //TODO: wheel front right and wheel front left is not loaded, yet is listed as an attribute in the xml file after wheel-radius
//TODO: same goes for their rear equivalents //TODO: same goes for their rear equivalents
@ -589,6 +593,7 @@ void KartProperties::checkAllSet(const std::string &filename)
CHECK_NEG(m_suspension_rest, "suspension rest" ); CHECK_NEG(m_suspension_rest, "suspension rest" );
CHECK_NEG(m_suspension_travel_cm, "suspension travel-cm" ); CHECK_NEG(m_suspension_travel_cm, "suspension travel-cm" );
CHECK_NEG(m_max_suspension_force, "suspension max-force" ); CHECK_NEG(m_max_suspension_force, "suspension max-force" );
CHECK_NEG(m_collision_impulse, "collision impulse" );
CHECK_NEG(m_collision_side_impulse, "collision side-impulse" ); CHECK_NEG(m_collision_side_impulse, "collision side-impulse" );
CHECK_NEG(m_upright_tolerance, "upright tolerance" ); CHECK_NEG(m_upright_tolerance, "upright tolerance" );
CHECK_NEG(m_upright_max_force, "upright max-force" ); CHECK_NEG(m_upright_max_force, "upright max-force" );

View File

@ -248,10 +248,15 @@ private:
float m_suspension_rest; float m_suspension_rest;
float m_suspension_travel_cm; float m_suspension_travel_cm;
/** An additional artifical side-impulse that pushes the slower kart /** An additional artifical side-impulse that pushes the slower kart
* out of the way of the faster kart in case of a collision. */ * out of the way of the faster kart in case of a frontal collision. */
float m_collision_side_impulse; float m_collision_side_impulse;
/** An additiojnal artificial impulse that pushes two karts in a
* side-side collision away from each other. */
float m_collision_impulse;
float m_upright_tolerance; float m_upright_tolerance;
float m_upright_max_force; float m_upright_max_force;
@ -499,6 +504,10 @@ public:
* to a slower kart in case of a collision. */ * to a slower kart in case of a collision. */
float getCollisionSideImpulse () const {return m_collision_side_impulse;} float getCollisionSideImpulse () const {return m_collision_side_impulse;}
/** Returns the (artificial) collision impulse this kart will apply
* to another kart in case of a non-frontal collision. */
float getCollisionImpulse () const {return m_collision_impulse;}
/** Returns the vertical offset when rescuing karts to avoid karts being /** Returns the vertical offset when rescuing karts to avoid karts being
* rescued in (or under) the track. */ * rescued in (or under) the track. */
float getVertRescueOffset () const {return m_rescue_vert_offset; } float getVertRescueOffset () const {return m_rescue_vert_offset; }

View File

@ -89,6 +89,26 @@ btWheelInfo& btKart::addWheel(const btVector3& connectionPointCS,
updateWheelTransformsWS( wheel , false ); updateWheelTransformsWS( wheel , false );
updateWheelTransform(getNumWheels()-1,false); updateWheelTransform(getNumWheels()-1,false);
m_forwardWS.resize(m_wheelInfo.size());
m_axle.resize(m_wheelInfo.size());
m_forwardImpulse.resize(m_wheelInfo.size());
m_sideImpulse.resize(m_wheelInfo.size());
// The average of all front wheel chassis points define the
// front center. This is always adjusted after adding a wheel
// to avoid calling a separate function just for that.
m_front_center_pointCS = btVector3(0,0,0);
unsigned int count=0;
for(int i=0; i<m_wheelInfo.size(); i++)
{
if(m_wheelInfo[i].m_chassisConnectionPointCS.getZ()>0)
{
m_front_center_pointCS += m_wheelInfo[i].m_chassisConnectionPointCS;
count ++;
}
}
m_front_center_pointCS *= 1.0f/count;
return wheel; return wheel;
} // addWheel } // addWheel
@ -586,28 +606,10 @@ btScalar btKart::calcRollingFriction(btWheelContactPoint& contactPoint)
void btKart::updateFriction(btScalar timeStep) void btKart::updateFriction(btScalar timeStep)
{ {
//calculate the impulse, so that the wheels don't move sidewards //calculate the impulse, so that the wheels don't move sidewards
int numWheel = getNumWheels();
if (!numWheel)
return;
m_forwardWS.resize(numWheel);
m_axle.resize(numWheel);
m_forwardImpulse.resize(numWheel);
m_sideImpulse.resize(numWheel);
//collapse all those loops into one!
for (int i=0;i<getNumWheels();i++) for (int i=0;i<getNumWheels();i++)
{ {
m_sideImpulse[i] = btScalar(0.); m_sideImpulse[i] = btScalar(0.);
m_forwardImpulse[i] = btScalar(0.);
}
for (int i=0;i<getNumWheels();i++)
{
btWheelInfo& wheelInfo = m_wheelInfo[i]; btWheelInfo& wheelInfo = m_wheelInfo[i];
btRigidBody* groundObject = btRigidBody* groundObject =

View File

@ -89,6 +89,9 @@ protected:
*/ */
bool m_allow_sliding; bool m_allow_sliding;
/** The center point of the front (in car coordinates). */
btVector3 m_front_center_pointCS;
btRigidBody* m_chassisBody; btRigidBody* m_chassisBody;
int m_num_wheels_on_ground; int m_num_wheels_on_ground;
@ -256,6 +259,13 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the number of wheels on the ground. */ /** Returns the number of wheels on the ground. */
unsigned int getNumWheelsOnGround() const {return m_num_wheels_on_ground;} unsigned int getNumWheelsOnGround() const {return m_num_wheels_on_ground;}
// ------------------------------------------------------------------------
/** Returns the middle point of the front wheel connection points in
* world coordinates. */
btVector3 getFrontCenterPointWS() const
{
return m_chassisBody->getWorldTransform()(m_front_center_pointCS);
} // getFrontCenterPointWS
}; };
#endif //BT_RAYCASTVEHICLE_H #endif //BT_RAYCASTVEHICLE_H

View File

@ -127,7 +127,8 @@ void Physics::update(float dt)
Kart *b=p->b->getPointerKart(); Kart *b=p->b->getPointerKart();
race_state->addCollision(a->getWorldKartId(), race_state->addCollision(a->getWorldKartId(),
b->getWorldKartId()); b->getWorldKartId());
KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart()); KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart(),
p->getContactPoint());
continue; continue;
} // if kart-kart collision } // if kart-kart collision
@ -211,15 +212,16 @@ bool Physics::projectKartDownwards(const Kart *k)
* explode immediately. This function is called from physics::update() on the * 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 * server and if no networking is used, and from race_state on the client to
* replay what happened on the server. * replay what happened on the server.
* \param kartA First kart involved in the collision. * \param kart_a First kart involved in the collision.
* \param kartB Second kart involved in the collision. * \param kart_b Second kart involved in the collision.
*/ */
void Physics::KartKartCollision(Kart *kartA, Kart *kartB) void Physics::KartKartCollision(Kart *kart_a, Kart *kart_b,
const Vec3 &contact_point)
{ {
kartA->crashed(kartB); // will play crash sound for player karts kart_a->crashed(kart_b); // will play crash sound for player karts
kartB->crashed(kartA); kart_b->crashed(kart_a);
Attachment *attachmentA=kartA->getAttachment(); Attachment *attachmentA=kart_a->getAttachment();
Attachment *attachmentB=kartB->getAttachment(); Attachment *attachmentB=kart_b->getAttachment();
if(attachmentA->getType()==Attachment::ATTACH_BOMB) if(attachmentA->getType()==Attachment::ATTACH_BOMB)
{ {
@ -231,41 +233,63 @@ void Physics::KartKartCollision(Kart *kartA, Kart *kartB)
} }
else // only A has a bomb, move it to B (unless it was from B) else // only A has a bomb, move it to B (unless it was from B)
{ {
if(attachmentA->getPreviousOwner()!=kartB) if(attachmentA->getPreviousOwner()!=kart_b)
{ {
attachmentA->moveBombFromTo(kartA, kartB); attachmentA->moveBombFromTo(kart_a, kart_b);
// Play appropriate SFX // Play appropriate SFX
kartB->playCustomSFX(SFXManager::CUSTOM_ATTACH); kart_b->playCustomSFX(SFXManager::CUSTOM_ATTACH);
} }
} }
} }
else if(attachmentB->getType()==Attachment::ATTACH_BOMB && else if(attachmentB->getType()==Attachment::ATTACH_BOMB &&
attachmentB->getPreviousOwner()!=kartA) attachmentB->getPreviousOwner()!=kart_a)
{ {
attachmentB->moveBombFromTo(kartB, kartA); attachmentB->moveBombFromTo(kart_b, kart_a);
kartA->playCustomSFX(SFXManager::CUSTOM_ATTACH); kart_a->playCustomSFX(SFXManager::CUSTOM_ATTACH);
} }
else else
{ {
kartA->playCustomSFX(SFXManager::CUSTOM_CRASH); kart_a->playCustomSFX(SFXManager::CUSTOM_CRASH);
kartB->playCustomSFX(SFXManager::CUSTOM_CRASH); kart_b->playCustomSFX(SFXManager::CUSTOM_CRASH);
} }
// If bouncing crashes is enabled, add an additional force to the // If bouncing crashes is enabled, add an additional force to the
// slower kart // slower kart
Kart *faster_kart, *slower_kart; Kart *faster_kart, *slower_kart;
if(kartA->getSpeed()>=kartB->getSpeed()) if(kart_a->getSpeed()>=kart_b->getSpeed())
{ {
faster_kart = kartA; faster_kart = kart_a;
slower_kart = kartB; slower_kart = kart_b;
} }
else else
{ {
faster_kart = kartB; faster_kart = kart_b;
slower_kart = kartA; slower_kart = kart_a;
} }
float side_impulse = faster_kart->getKartProperties()->getCollisionSideImpulse();
if(side_impulse>0) Vec3 front_center = faster_kart->getVehicle()->getFrontCenterPointWS();
float radius = 0.5f*faster_kart->getKartWidth();
bool frontal_collision =
(contact_point-front_center).length2_2d() < radius*radius;
float side_impulse =
faster_kart->getKartProperties()->getCollisionSideImpulse();
if(!frontal_collision)
{
Vec3 diff = faster_kart->getXYZ() - slower_kart->getXYZ();
// Remove any y component to reduce the chance of karts
// toppling over
diff.setY(0);
diff = diff.normalize();
float impulse_base = 10.0f;
Vec3 impulse_fast =
slower_kart->getKartProperties()->getCollisionImpulse()*diff;
faster_kart->getBody()->applyCentralImpulse(impulse_fast);
Vec3 impulse_slow =
(-faster_kart->getKartProperties()->getCollisionImpulse())*diff;
slower_kart->getBody()->applyCentralImpulse(impulse_slow);
}
else if(side_impulse>0) // and frontal collision
{ {
Vec3 forwards_ws(0, 1, 0); Vec3 forwards_ws(0, 1, 0);
Vec3 forwards = faster_kart->getTrans()*forwards_ws; Vec3 forwards = faster_kart->getTrans()*forwards_ws;
@ -340,7 +364,8 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
if(upA->is(UserPointer::UP_TRACK)) if(upA->is(UserPointer::UP_TRACK))
{ {
if(upB->is(UserPointer::UP_FLYABLE)) // 1.1 projectile hits track if(upB->is(UserPointer::UP_FLYABLE)) // 1.1 projectile hits track
m_all_collisions.push_back(upB, upA); m_all_collisions.push_back(upB, upA,
contactManifold->getContactPoint(0).getPositionWorldOnA());
else if(upB->is(UserPointer::UP_KART)) else if(upB->is(UserPointer::UP_KART))
{ {
Kart *kart=upB->getPointerKart(); Kart *kart=upB->getPointerKart();
@ -368,15 +393,19 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
} }
else if(upB->is(UserPointer::UP_FLYABLE)) else if(upB->is(UserPointer::UP_FLYABLE))
// 2.1 projectile hits kart // 2.1 projectile hits kart
m_all_collisions.push_back(upB, upA); m_all_collisions.push_back(upB, upA,
contactManifold->getContactPoint(0).getPositionWorldOnA());
else if(upB->is(UserPointer::UP_KART)) else if(upB->is(UserPointer::UP_KART))
// 2.2 kart hits kart // 2.2 kart hits kart
m_all_collisions.push_back(upA, upB); m_all_collisions.push_back(upA, upB,
contactManifold->getContactPoint(0).getPositionWorldOnA());
else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT)) else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT))
// 2.3 kart hits physical object // 2.3 kart hits physical object
m_all_collisions.push_back(upB, upA); m_all_collisions.push_back(upB, upA,
contactManifold->getContactPoint(0).getPositionWorldOnA());
else if(upB->is(UserPointer::UP_ANIMATION)) else if(upB->is(UserPointer::UP_ANIMATION))
m_all_collisions.push_back(upB, upA); m_all_collisions.push_back(upB, upA,
contactManifold->getContactPoint(0).getPositionWorldOnA());
} }
// 3) object is a projectile // 3) object is a projectile
// ========================= // =========================
@ -391,7 +420,8 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
upB->is(UserPointer::UP_PHYSICAL_OBJECT) || upB->is(UserPointer::UP_PHYSICAL_OBJECT) ||
upB->is(UserPointer::UP_KART ) ) upB->is(UserPointer::UP_KART ) )
{ {
m_all_collisions.push_back(upA, upB); m_all_collisions.push_back(upA, upB,
contactManifold->getContactPoint(0).getPositionWorldOnA());
} }
} }
// Object is a physical object // Object is a physical object
@ -399,14 +429,17 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT)) else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT))
{ {
if(upB->is(UserPointer::UP_FLYABLE)) if(upB->is(UserPointer::UP_FLYABLE))
m_all_collisions.push_back(upB, upA); m_all_collisions.push_back(upB, upA,
contactManifold->getContactPoint(0).getPositionWorldOnA());
else if(upB->is(UserPointer::UP_KART)) else if(upB->is(UserPointer::UP_KART))
m_all_collisions.push_back(upA, upB); m_all_collisions.push_back(upA, upB,
contactManifold->getContactPoint(0).getPositionWorldOnA());
} }
else if (upA->is(UserPointer::UP_ANIMATION)) else if (upA->is(UserPointer::UP_ANIMATION))
{ {
if(upB->is(UserPointer::UP_KART)) if(upB->is(UserPointer::UP_KART))
m_all_collisions.push_back(upA, upB); m_all_collisions.push_back(upA, upB,
contactManifold->getContactPoint(0).getPositionWorldOnA());
} }
else assert("Unknown user pointer"); // 4) Should never happen else assert("Unknown user pointer"); // 4) Should never happen
} // for i<numManifolds } // for i<numManifolds

View File

@ -44,38 +44,53 @@ class Physics : public btSequentialImpulseConstraintSolver
{ {
private: private:
// Bullet can report the same collision more than once (up to 4 /** 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 * substep might be taken, resulting in potentially even more
// duplicates. To handle this, all collisions (i.e. pair of objects) * duplicates. To handle this, all collisions (i.e. pair of objects)
// are stored in a vector, but only one entry per collision pair * are stored in a vector, but only one entry per collision pair
// of objects. * of objects.
// While this is a natural application of std::set, the set has some * While this is a natural application of std::set, the set has some
// overhead (since it will likely use a tree to sort the entries). * overhead (since it will likely use a tree to sort the entries).
// Considering that the number of collisions is usually rather small * Considering that the number of collisions is usually rather small
// a simple list and linear search is faster is is being used here. * a simple list and linear search is faster is is being used here. */
class CollisionPair { class CollisionPair {
public: public:
/** The user pointer of the objects involved in this collision. */
const UserPointer *a, *b; const UserPointer *a, *b;
// The entries in Collision Pairs are sorted: if a projectile /** A contact point of the collision. For now only one of the two
// is included, it's always 'a'. If only two karts are reported * contact points is needed (since they are close). */
// the first kart pointer is the smaller one Vec3 m_contact_point;
CollisionPair(const UserPointer *a1, const UserPointer *b1) {
/** The entries in Collision Pairs are sorted: if a projectile
* is included, it's always 'a'. If only two karts are reported
* the first kart pointer is the smaller one. */
CollisionPair(const UserPointer *a1, const UserPointer *b1,
const btVector3 &contact_point) {
if(a1->is(UserPointer::UP_KART) && if(a1->is(UserPointer::UP_KART) &&
b1->is(UserPointer::UP_KART) && a1>b1) { b1->is(UserPointer::UP_KART) && a1>b1) {
a=b1;b=a1; a=b1;b=a1;
} else { } else {
a=a1; b=b1; a=a1; b=b1;
} }
m_contact_point = contact_point;
}; // CollisionPair }; // CollisionPair
// --------------------------------------------------------------------
/** Tests if two collision pairs involve the same objects. This test
* is simplified (i.e. no test if p.b==a and p.a==b) since the
* elements are sorted. */
bool operator==(const CollisionPair p) {return (p.a==a && p.b==b);} bool operator==(const CollisionPair p) {return (p.a==a && p.b==b);}
// --------------------------------------------------------------------
/** Returns the contact point of the collision. */
const Vec3 &getContactPoint() const { return m_contact_point; }
}; // CollisionPair }; // CollisionPair
// ========================================================================
// This class is the list of collision objects, where each collision // This class is the list of collision objects, where each collision
// pair is stored as most once. // pair is stored as most once.
class CollisionList : public std::vector<CollisionPair> { class CollisionList : public std::vector<CollisionPair>
{
private: private:
void push_back(CollisionPair p) { void push_back(CollisionPair p) {
// only add a pair if it's not already in there // only add a pair if it's not already in there
@ -85,10 +100,14 @@ private:
std::vector<CollisionPair>::push_back(p); std::vector<CollisionPair>::push_back(p);
}; // push_back }; // push_back
public: public:
void push_back(const UserPointer* a, const UserPointer*b) { /** Adds information about a collision to this vector. */
push_back(CollisionPair(a, b)); void push_back(const UserPointer* a, const UserPointer*b,
const btVector3 &contact_point)
{
push_back(CollisionPair(a, b, contact_point));
} }
}; // CollisionList }; // CollisionList
// ========================================================================
/** Pointer to the physics dynamics world. */ /** Pointer to the physics dynamics world. */
STKDynamicsWorld *m_dynamics_world; STKDynamicsWorld *m_dynamics_world;
@ -108,7 +127,8 @@ public:
void addBody (btRigidBody* b) {m_dynamics_world->addRigidBody(b);} void addBody (btRigidBody* b) {m_dynamics_world->addRigidBody(b);}
void removeKart (const Kart *k); void removeKart (const Kart *k);
void removeBody (btRigidBody* b) {m_dynamics_world->removeRigidBody(b);} void removeBody (btRigidBody* b) {m_dynamics_world->removeRigidBody(b);}
void KartKartCollision(Kart *ka, Kart *kb); void KartKartCollision(Kart *ka, Kart *kb,
const Vec3 &contact_point);
void update (float dt); void update (float dt);
void draw (); void draw ();
STKDynamicsWorld* STKDynamicsWorld*