From d06acf1f7b7336783de39afc8f1984979aaf5ff7 Mon Sep 17 00:00:00 2001 From: hikerstk Date: Wed, 14 Dec 2011 21:02:15 +0000 Subject: [PATCH] 1) Added an (additional) impulse to push karts away from each other. This impulse does not cause any rotation of the kart, it just pushes the kart orthogonal to its velocity. 2) The rotational velocity is set to 0 in case of a collision, hopefully avoiding the problem that karts will rotate as result of a collision. 3) A collision pair now stores the exact collision point for both bodies (which is then used to determine the side in which the impulse to be applied). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10422 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- data/stk_config.xml | 2 +- src/network/race_state.cpp | 8 +- src/physics/btKart.cpp | 14 --- src/physics/btKart.hpp | 12 +- src/physics/physics.cpp | 244 +++++++++++++++++++++++++------------ src/physics/physics.hpp | 61 +++++++--- 6 files changed, 210 insertions(+), 131 deletions(-) diff --git a/data/stk_config.xml b/data/stk_config.xml index 1fefc766e..e1fada9e9 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -289,7 +289,7 @@ 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. --> - + right side + { + if(contact_point.getZ()>0) // --> front or right side + { + result = fabsf(extend.getX() - contact_point.getX()) < + fabsf(extend.getZ() - contact_point.getZ()) ? COL_RIGHT + : COL_FRONT; + } + else // getZ()<0 --> back or right side + { + result = fabsf( extend.getX() - contact_point.getX()) < + fabsf( extend.getZ() + contact_point.getZ()) ? COL_RIGHT + : COL_BACK; + } + } + else // getX() < 0 --> left side + { + if(contact_point.getZ()>0) // --> front or left side + { + result = fabsf(extend.getX() + contact_point.getX()) < + fabsf(extend.getZ() - contact_point.getZ()) ? COL_LEFT + : COL_FRONT; + } + else // --> back or left side + { + result = fabsf(extend.getX() + contact_point.getX()) < + fabsf(extend.getZ() + contact_point.getZ()) ? COL_LEFT + : COL_BACK; + } + } + + return result; +} // getCollisionSide + //----------------------------------------------------------------------------- /** 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 @@ -215,8 +268,8 @@ bool Physics::projectKartDownwards(const Kart *k) * \param kart_a First kart involved in the collision. * \param kart_b Second kart involved in the collision. */ -void Physics::KartKartCollision(Kart *kart_a, Kart *kart_b, - const Vec3 &contact_point) +void Physics::KartKartCollision(Kart *kart_a, const Vec3 &contact_point_a, + Kart *kart_b, const Vec3 &contact_point_b) { kart_a->crashed(kart_b); // will play crash sound for player karts kart_b->crashed(kart_a); @@ -256,60 +309,80 @@ void Physics::KartKartCollision(Kart *kart_a, Kart *kart_b, // If bouncing crashes is enabled, add an additional force to the // slower kart Kart *faster_kart, *slower_kart; + Vec3 faster_cp, slower_cp; if(kart_a->getSpeed()>=kart_b->getSpeed()) { faster_kart = kart_a; + faster_cp = contact_point_a; slower_kart = kart_b; + slower_cp = contact_point_b; } else { faster_kart = kart_b; + faster_cp = contact_point_b; slower_kart = kart_a; + slower_cp = contact_point_a; } - 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; + CollisionSide faster_side = getCollisionSide(faster_kart->getBody(), + faster_cp); + CollisionSide slower_side = getCollisionSide(slower_kart->getBody(), + slower_cp); - float side_impulse = - faster_kart->getKartProperties()->getCollisionSideImpulse(); - if(!frontal_collision) + // This probably needs adjusting once we have different kart properties. + // E.g. besides speed we might also want to take mass into account(?) + if(faster_side==COL_FRONT) { - 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; - core::line2df f(faster_kart->getXYZ().getX(), - faster_kart->getXYZ().getY(), - forwards.getX(), forwards.getY()); - core::vector2df p(slower_kart->getXYZ().getX(), - slower_kart->getXYZ().getY()); + // Special case: the faster kart hits a kart front on. In this case + // the slower kart will be pushed out of the faster kart's way + Vec3 dir = faster_kart->getVelocity(); - float orientation=f.getPointOrientation(p); - // Now compute the vector to the side (right or left depending - // on where the kart was hit). - Vec3 side((orientation>=0) ? -1.0f : 1.0f, 0, 0); - float speed_frac = faster_kart->getSpeed()/faster_kart->getCurrentMaxSpeed(); - Vec3 impulse = - faster_kart->getTrans().getBasis()*side*side_impulse*speed_frac; - printf("orientation is %f impulse is %f %f %f\n", - orientation, impulse.getX(),impulse.getY(),impulse.getZ()); + // The direction in which the impulse will be applied depends on + // which side of the faster kart was hitting it: if the hit is + // on the right side of the faster kart, it will push the slower + // kart to the right and vice versa. This is based on the + // assumption that a hit to the right indicates that it's + // shorter to push the slower kart to the right. + Vec3 impulse; + if(faster_cp.getX()>0) + impulse = Vec3( dir.getZ(), 0, -dir.getX()); + else + impulse = Vec3(-dir.getZ(), 0, dir.getX()); + impulse.normalize(); + impulse *= faster_kart->getKartProperties()->getCollisionImpulse(); slower_kart->getBody()->applyCentralImpulse(impulse); + slower_kart->getBody()->setAngularVelocity(btVector3(0,0,0)); + // Apply some impulse to the slower kart as well? } + else + { + // Non-frontal collision, push the two karts away from each other + // First the faster kart + Vec3 dir = faster_kart->getVelocity(); + Vec3 impulse; + if(faster_cp.getX()>0) + impulse = Vec3(-dir.getZ(), 0, dir.getX()); + else + impulse = Vec3( dir.getZ(), 0, -dir.getX()); + impulse.normalize(); + impulse *= slower_kart->getKartProperties()->getCollisionImpulse(); + faster_kart->getBody()->applyCentralImpulse(impulse); + faster_kart->getBody()->setAngularVelocity(btVector3(0,0,0)); + + // Then the slower kart + dir = slower_kart->getVelocity(); + if(slower_cp.getX()>0) + impulse = Vec3(-dir.getZ(), 0, dir.getX()); + else + impulse = Vec3( dir.getZ(), 0, -dir.getX()); + + impulse.normalize(); + impulse *= faster_kart->getKartProperties()->getCollisionImpulse(); + slower_kart->getBody()->applyCentralImpulse(impulse); + slower_kart->getBody()->setAngularVelocity(btVector3(0,0,0)); + } + } // KartKartCollision //----------------------------------------------------------------------------- @@ -364,8 +437,9 @@ 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, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upB, contactManifold->getContactPoint(0).m_localPointB, + upA, contactManifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_KART)) { Kart *kart=upB->getPointerKart(); @@ -393,19 +467,23 @@ 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, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upB, contactManifold->getContactPoint(0).m_localPointB, + upA, contactManifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_KART)) // 2.2 kart hits kart - m_all_collisions.push_back(upA, upB, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upA, contactManifold->getContactPoint(0).m_localPointA, + upB, contactManifold->getContactPoint(0).m_localPointB); else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT)) // 2.3 kart hits physical object - m_all_collisions.push_back(upB, upA, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upB, contactManifold->getContactPoint(0).m_localPointB, + upA, contactManifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_ANIMATION)) - m_all_collisions.push_back(upB, upA, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upB, contactManifold->getContactPoint(0).m_localPointB, + upA, contactManifold->getContactPoint(0).m_localPointA); } // 3) object is a projectile // ========================= @@ -420,8 +498,9 @@ 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, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upA, contactManifold->getContactPoint(0).m_localPointA, + upB, contactManifold->getContactPoint(0).m_localPointB); } } // Object is a physical object @@ -429,17 +508,20 @@ 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, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upB, contactManifold->getContactPoint(0).m_localPointB, + upA, contactManifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_KART)) - m_all_collisions.push_back(upA, upB, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upA, contactManifold->getContactPoint(0).m_localPointA, + upB, contactManifold->getContactPoint(0).m_localPointB); } else if (upA->is(UserPointer::UP_ANIMATION)) { if(upB->is(UserPointer::UP_KART)) - m_all_collisions.push_back(upA, upB, - contactManifold->getContactPoint(0).getPositionWorldOnA()); + m_all_collisions.push_back( + upA, contactManifold->getContactPoint(0).m_localPointA, + upB, contactManifold->getContactPoint(0).m_localPointB); } else assert("Unknown user pointer"); // 4) Should never happen } // for iis(UserPointer::UP_KART) && - b1->is(UserPointer::UP_KART) && a1>b1) { - a=b1;b=a1; + CollisionPair(const UserPointer *a, const btVector3 &contact_point_a, + const UserPointer *b, const btVector3 &contact_point_b) + { + if(a->is(UserPointer::UP_KART) && + b->is(UserPointer::UP_KART) && a>b) { + m_up[0]=b; m_contact_point[0] = contact_point_b; + m_up[1]=a; m_contact_point[1] = contact_point_a; } else { - a=a1; b=b1; + m_up[0]=a; m_contact_point[0] = contact_point_a; + m_up[1]=b; m_contact_point[1] = contact_point_b; } - 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);} + bool operator==(const CollisionPair p) + { + return (p.m_up[0]==m_up[0] && p.m_up[1]==m_up[1]); + } // operator== // -------------------------------------------------------------------- - /** Returns the contact point of the collision. */ - const Vec3 &getContactPoint() const { return m_contact_point; } + const UserPointer *getUserPointer(unsigned int n) const + { + assert(n>=0 && n<=1); + return m_up[n]; + } // getUserPointer + // -------------------------------------------------------------------- + /** Returns the contact point of the collision in + * car (local) coordinates. */ + const Vec3 &getContactPointCS(unsigned int n) const + { + assert(n>=0 && n<=1); + return m_contact_point[n]; + } // getContactPointCS }; // CollisionPair // ======================================================================== @@ -101,10 +122,10 @@ private: }; // push_back public: /** Adds information about a collision to this vector. */ - void push_back(const UserPointer* a, const UserPointer*b, - const btVector3 &contact_point) + void push_back(const UserPointer *a, const btVector3 &contact_point_a, + const UserPointer *b, const btVector3 &contact_point_b) { - push_back(CollisionPair(a, b, contact_point)); + push_back(CollisionPair(a, contact_point_a, b, contact_point_b)); } }; // CollisionList // ======================================================================== @@ -127,8 +148,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, - const Vec3 &contact_point); + void KartKartCollision(Kart *ka, const Vec3 &contact_point_a, + Kart *kb, const Vec3 &contact_point_b); void update (float dt); void draw (); STKDynamicsWorld*