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:
parent
6a9b401d6e
commit
8ab469d4d8
@ -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
|
||||
|
@ -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" );
|
||||
|
@ -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; }
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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*
|
||||
|
Loading…
Reference in New Issue
Block a user