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,15 +277,18 @@
<!-- Parameters for the upright constraint, which keeps karts upright. -->
<upright tolerance="0.2" max-force="30"/>
<!-- collision-side-impulse is an additional (artificial) impulse that
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
for now disabled since it needs tuning and additionally has the
problem that the amount of push a hit kart receives depends on
the orientation - if a kart is pushed in the direction it is
driving, it will be more (no friction from tires), while when
pushed to the side, hardly anything happens. -->
<collision side-impulse="0"/>
<!-- 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.
sideways to the faster kart) when a collision happens. This is
for now disabled since it needs tuning and additionally has the
problem that the amount of push a hit kart receives depends on
the orientation - if a kart is pushed in the direction it is
driving, it will be more (no friction from tires), while when
pushed to the side, hardly anything happens. -->
<collision impulse="0" side-impulse="0"/>
<!-- Kart-specific plunger and rubber band handling: max-length 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_chassis_angular_damping = m_suspension_rest =
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_track_connection_accel =
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"))
{
collision_node->get("impulse", &m_collision_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: 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_travel_cm, "suspension travel-cm" );
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_upright_tolerance, "upright tolerance" );
CHECK_NEG(m_upright_max_force, "upright max-force" );

View File

@ -248,10 +248,15 @@ private:
float m_suspension_rest;
float m_suspension_travel_cm;
/** 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;
/** 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_max_force;
@ -499,6 +504,10 @@ public:
* to a slower kart in case of a collision. */
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
* rescued in (or under) the track. */
float getVertRescueOffset () const {return m_rescue_vert_offset; }

View File

@ -89,6 +89,26 @@ btWheelInfo& btKart::addWheel(const btVector3& connectionPointCS,
updateWheelTransformsWS( wheel , 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;
} // addWheel
@ -586,28 +606,10 @@ btScalar btKart::calcRollingFriction(btWheelContactPoint& contactPoint)
void btKart::updateFriction(btScalar timeStep)
{
//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++)
{
m_sideImpulse[i] = btScalar(0.);
m_forwardImpulse[i] = btScalar(0.);
}
for (int i=0;i<getNumWheels();i++)
{
m_sideImpulse[i] = btScalar(0.);
btWheelInfo& wheelInfo = m_wheelInfo[i];
btRigidBody* groundObject =

View File

@ -89,6 +89,9 @@ protected:
*/
bool m_allow_sliding;
/** The center point of the front (in car coordinates). */
btVector3 m_front_center_pointCS;
btRigidBody* m_chassisBody;
int m_num_wheels_on_ground;
@ -256,6 +259,13 @@ public:
// ------------------------------------------------------------------------
/** Returns the number of wheels on the 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

View File

@ -127,7 +127,8 @@ void Physics::update(float dt)
Kart *b=p->b->getPointerKart();
race_state->addCollision(a->getWorldKartId(),
b->getWorldKartId());
KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart());
KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart(),
p->getContactPoint());
continue;
} // 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
* 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.
* \param kart_a First 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
kartB->crashed(kartA);
Attachment *attachmentA=kartA->getAttachment();
Attachment *attachmentB=kartB->getAttachment();
kart_a->crashed(kart_b); // will play crash sound for player karts
kart_b->crashed(kart_a);
Attachment *attachmentA=kart_a->getAttachment();
Attachment *attachmentB=kart_b->getAttachment();
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)
{
if(attachmentA->getPreviousOwner()!=kartB)
if(attachmentA->getPreviousOwner()!=kart_b)
{
attachmentA->moveBombFromTo(kartA, kartB);
attachmentA->moveBombFromTo(kart_a, kart_b);
// Play appropriate SFX
kartB->playCustomSFX(SFXManager::CUSTOM_ATTACH);
kart_b->playCustomSFX(SFXManager::CUSTOM_ATTACH);
}
}
}
else if(attachmentB->getType()==Attachment::ATTACH_BOMB &&
attachmentB->getPreviousOwner()!=kartA)
attachmentB->getPreviousOwner()!=kart_a)
{
attachmentB->moveBombFromTo(kartB, kartA);
kartA->playCustomSFX(SFXManager::CUSTOM_ATTACH);
attachmentB->moveBombFromTo(kart_b, kart_a);
kart_a->playCustomSFX(SFXManager::CUSTOM_ATTACH);
}
else
{
kartA->playCustomSFX(SFXManager::CUSTOM_CRASH);
kartB->playCustomSFX(SFXManager::CUSTOM_CRASH);
kart_a->playCustomSFX(SFXManager::CUSTOM_CRASH);
kart_b->playCustomSFX(SFXManager::CUSTOM_CRASH);
}
// If bouncing crashes is enabled, add an additional force to the
// slower kart
Kart *faster_kart, *slower_kart;
if(kartA->getSpeed()>=kartB->getSpeed())
if(kart_a->getSpeed()>=kart_b->getSpeed())
{
faster_kart = kartA;
slower_kart = kartB;
faster_kart = kart_a;
slower_kart = kart_b;
}
else
{
faster_kart = kartB;
slower_kart = kartA;
faster_kart = kart_b;
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 = faster_kart->getTrans()*forwards_ws;
@ -340,7 +364,8 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
if(upA->is(UserPointer::UP_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))
{
Kart *kart=upB->getPointerKart();
@ -368,15 +393,19 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
}
else if(upB->is(UserPointer::UP_FLYABLE))
// 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))
// 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))
// 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))
m_all_collisions.push_back(upB, upA);
m_all_collisions.push_back(upB, upA,
contactManifold->getContactPoint(0).getPositionWorldOnA());
}
// 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_KART ) )
{
m_all_collisions.push_back(upA, upB);
m_all_collisions.push_back(upA, upB,
contactManifold->getContactPoint(0).getPositionWorldOnA());
}
}
// Object is a physical object
@ -399,14 +429,17 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT))
{
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))
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))
{
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
} // for i<numManifolds

View File

@ -44,38 +44,53 @@ class Physics : public btSequentialImpulseConstraintSolver
{
private:
// Bullet can report the same collision more than once (up to 4
// 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
// of objects.
// 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).
// Considering that the number of collisions is usually rather small
// a simple list and linear search is faster is is being used here.
/** Bullet can report the same collision more than once (up to 4
* 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
* of objects.
* 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).
* Considering that the number of collisions is usually rather small
* a simple list and linear search is faster is is being used here. */
class CollisionPair {
public:
/** The user pointer of the objects involved in this collision. */
const UserPointer *a, *b;
// 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) {
/** A contact point of the collision. For now only one of the two
* contact points is needed (since they are close). */
Vec3 m_contact_point;
/** 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) &&
b1->is(UserPointer::UP_KART) && a1>b1) {
a=b1;b=a1;
} else {
a=a1; b=b1;
}
m_contact_point = contact_point;
}; // 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);}
// --------------------------------------------------------------------
/** Returns the contact point of the collision. */
const Vec3 &getContactPoint() const { return m_contact_point; }
}; // CollisionPair
// ========================================================================
// This class is the list of collision objects, where each collision
// pair is stored as most once.
class CollisionList : public std::vector<CollisionPair> {
class CollisionList : public std::vector<CollisionPair>
{
private:
void push_back(CollisionPair p) {
// only add a pair if it's not already in there
@ -85,10 +100,14 @@ private:
std::vector<CollisionPair>::push_back(p);
}; // push_back
public:
void push_back(const UserPointer* a, const UserPointer*b) {
push_back(CollisionPair(a, b));
/** Adds information about a collision to this vector. */
void push_back(const UserPointer* a, const UserPointer*b,
const btVector3 &contact_point)
{
push_back(CollisionPair(a, b, contact_point));
}
}; // CollisionList
// ========================================================================
/** Pointer to the physics dynamics world. */
STKDynamicsWorld *m_dynamics_world;
@ -108,7 +127,8 @@ public:
void addBody (btRigidBody* b) {m_dynamics_world->addRigidBody(b);}
void removeKart (const Kart *k);
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 draw ();
STKDynamicsWorld*