Fix #981: karts are sometimes rescued when restarting, or facing the
wrong direction. Reason was an incorrect rotation in the projection code. Instead of fixing it, I let the kart fall a little bit, so the code is now correct, much easier to understand, and the bounce after a reset fits the game imho. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12852 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
6b05b70d04
commit
a529a07c99
@ -636,7 +636,7 @@ void LinearWorld::moveKartAfterRescue(AbstractKart* kart)
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
|
||||
//project kart to surface of track
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(kart);
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
|
||||
if (kart_over_ground)
|
||||
{
|
||||
@ -645,6 +645,9 @@ void LinearWorld::moveKartAfterRescue(AbstractKart* kart)
|
||||
kart->getKartProperties()->getVertRescueOffset()
|
||||
* kart->getKartHeight();
|
||||
kart->getBody()->translate(btVector3(0, vertical_offset, 0));
|
||||
// Also correctly set the graphics, otherwise the kart will
|
||||
// be displayed for one frame at the incorrect position.
|
||||
kart->updateGraphics(0, Vec3(0,0,0), btQuaternion(0, 0, 0, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -653,7 +656,6 @@ void LinearWorld::moveKartAfterRescue(AbstractKart* kart)
|
||||
(kart->getIdent().c_str()), m_track->getIdent().c_str());
|
||||
}
|
||||
|
||||
|
||||
} // moveKartAfterRescue
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -263,7 +263,7 @@ void OverWorld::moveKartAfterRescue(AbstractKart* kart, float angle)
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
|
||||
//project kart to surface of track
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(kart);
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
|
||||
if (kart_over_ground)
|
||||
{
|
||||
|
@ -258,7 +258,7 @@ void SoccerWorld::moveKartAfterRescue(AbstractKart* kart)
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
|
||||
//project kart to surface of track
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(kart);
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
|
||||
if (kart_over_ground)
|
||||
{
|
||||
|
@ -542,7 +542,7 @@ void ThreeStrikesBattle::moveKartAfterRescue(AbstractKart* kart)
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
|
||||
//project kart to surface of track
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(kart);
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
|
||||
if (kart_over_ground)
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ void TutorialWorld::moveKartAfterRescue(AbstractKart* kart)
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
|
||||
//project kart to surface of track
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(kart);
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
|
||||
if (kart_over_ground)
|
||||
{
|
||||
|
@ -496,7 +496,8 @@ void World::resetAllKarts()
|
||||
pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f),
|
||||
m_track->getAngle(quad)) );
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(kart);
|
||||
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
if(kart_over_ground)
|
||||
{
|
||||
const Vec3 &xyz = kart->getTrans().getOrigin()
|
||||
@ -541,7 +542,7 @@ void World::resetAllKarts()
|
||||
btVector3 up_offset(0, 0.5f * ((*i)->getKartHeight()), 0);
|
||||
(*i)->getVehicle()->getRigidBody()->translate (up_offset);
|
||||
|
||||
bool kart_over_ground = m_physics->projectKartDownwards(*i);
|
||||
bool kart_over_ground = m_track->findGround(*i);
|
||||
|
||||
if (!kart_over_ground)
|
||||
{
|
||||
|
@ -962,239 +962,3 @@ btScalar btKart::rayCast(btWheelInfo& wheel, const btVector3& ray)
|
||||
} // rayCast(btWheelInfo& wheel, const btVector3& ray
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//Project vehicle onto surface in a particular direction.
|
||||
//Used in reseting kart positions.
|
||||
//Please align wheel direction with ray direction first.
|
||||
bool btKart::projectVehicleToSurface(const btVector3& ray,
|
||||
bool translate_vehicle)
|
||||
{
|
||||
if (ray.length() <= btScalar(0))
|
||||
return false;
|
||||
|
||||
btVector3 ray_dir = ray / ray.length();
|
||||
|
||||
for (int i=0;i<getNumWheels();i++)
|
||||
{
|
||||
updateWheelTransform(i,false);
|
||||
}
|
||||
|
||||
|
||||
btScalar min_depth(-1); //minimum distance of wheel to surface
|
||||
int min_wheel_index = 0; //wheel with 1st minimum distance to surface
|
||||
int min_wheel_index2 = 0; //wheel with 2nd minimum distance to surface
|
||||
int min_wheel_index3 = 0; //wheel with 3nd minimum distance to surface
|
||||
|
||||
btScalar depth[4];
|
||||
|
||||
for (int i=0;i<m_wheelInfo.size();i++)
|
||||
{
|
||||
depth[i] = rayCast( m_wheelInfo[i], ray);
|
||||
depth[i] -= m_wheelInfo[i].m_wheelsRadius;
|
||||
|
||||
if (!(m_wheelInfo[i].m_raycastInfo.m_isInContact))
|
||||
{
|
||||
return false; //a wheel is not over ground
|
||||
}
|
||||
|
||||
if (depth[i]<min_depth || i ==0)
|
||||
{
|
||||
min_depth = depth[i];
|
||||
min_wheel_index = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool flag = true;
|
||||
|
||||
for (int i=0;i<m_wheelInfo.size();i++)
|
||||
{
|
||||
if (i==min_wheel_index)
|
||||
continue;
|
||||
|
||||
if (depth[i]<min_depth || flag)
|
||||
{
|
||||
min_depth = depth[i];
|
||||
min_wheel_index2 = i;
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
flag = true;
|
||||
for (int i=0;i<m_wheelInfo.size();i++)
|
||||
{
|
||||
if (i==min_wheel_index || i==min_wheel_index2)
|
||||
continue;
|
||||
|
||||
if (depth[i]<min_depth || flag)
|
||||
{
|
||||
min_depth = depth[i];
|
||||
min_wheel_index3 = i;
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
min_depth = depth[min_wheel_index];
|
||||
|
||||
btWheelInfo& min_wheel = m_wheelInfo[min_wheel_index];
|
||||
btWheelInfo& min_wheel2 = m_wheelInfo[min_wheel_index2];
|
||||
btWheelInfo& min_wheel3 = m_wheelInfo[min_wheel_index3];
|
||||
|
||||
btTransform trans = getRigidBody()->getCenterOfMassTransform();
|
||||
btTransform rot_trans;
|
||||
rot_trans.setIdentity();
|
||||
rot_trans.setRotation(trans.getRotation());
|
||||
rot_trans = rot_trans.inverse();
|
||||
|
||||
btTransform offset_trans;
|
||||
offset_trans.setIdentity();
|
||||
btVector3 offset = min_wheel.m_raycastInfo.m_hardPointWS
|
||||
+ min_wheel.m_wheelsRadius * ray_dir;
|
||||
offset -= getRigidBody()->getCenterOfMassPosition();
|
||||
offset_trans.setOrigin(rot_trans*offset);
|
||||
|
||||
|
||||
// The effect of the following rotations is to make the 3 wheels with
|
||||
// initial minimum distance to surface (in the ray direction) in contact
|
||||
// with the plane between the points of intersection (between the ray and
|
||||
// surface).
|
||||
|
||||
//Note - For possible complex surfaces with lots of bumps directly under
|
||||
// vehicle, the raycast needs to be done from a slightly higher
|
||||
// above the surface. For such surfaces, the end result should be
|
||||
// that at least 1 wheel touches the surface, and no wheel goes
|
||||
// below the surface.
|
||||
|
||||
//We need to rotate vehicle, using above contact point as a pivot to put
|
||||
//2nd closest wheel nearer to the surface of the track
|
||||
btScalar d_hpws = ( min_wheel.m_raycastInfo.m_hardPointWS
|
||||
- min_wheel2.m_raycastInfo.m_hardPointWS).length();
|
||||
btScalar d_depth = ( min_wheel2.m_raycastInfo.m_contactPointWS
|
||||
- min_wheel2.m_raycastInfo.m_hardPointWS
|
||||
- ray_dir * min_wheel.m_wheelsRadius).length();
|
||||
d_depth -= min_depth;
|
||||
|
||||
//calculate rotation angle from pivot point and plane perpendicular to ray
|
||||
float rot_angle = atanf(d_depth / d_hpws);
|
||||
rot_angle -= atanf((min_wheel2.m_wheelsRadius - min_wheel.m_wheelsRadius)
|
||||
/ d_hpws);
|
||||
|
||||
getRigidBody()->setAngularVelocity(btVector3(0,0,0));
|
||||
getRigidBody()->setLinearVelocity(btVector3(0,0,0));
|
||||
|
||||
|
||||
btVector3 rot_axis =
|
||||
( min_wheel2.m_raycastInfo.m_hardPointWS
|
||||
- min_wheel.m_raycastInfo.m_hardPointWS).cross(ray_dir);
|
||||
|
||||
btTransform operator_trans;
|
||||
operator_trans.setIdentity();
|
||||
|
||||
//perform pivot rotation
|
||||
if (rot_axis.length() != btScalar(0))
|
||||
{
|
||||
//rotate kart about pivot point, about line perpendicular to
|
||||
//ray and vector between the 2 wheels
|
||||
operator_trans *= offset_trans;
|
||||
operator_trans.setRotation(btQuaternion(rot_trans*rot_axis.normalize(),
|
||||
rot_angle));
|
||||
offset_trans.setOrigin(-(rot_trans*offset));
|
||||
operator_trans *= offset_trans;
|
||||
}
|
||||
|
||||
//apply tranform
|
||||
trans *= operator_trans;
|
||||
getRigidBody()->setCenterOfMassTransform(trans);
|
||||
|
||||
//next, rotate about axis which is a vector between 2 wheels above, so that
|
||||
//the 3rd wheel is correctly positioned.
|
||||
|
||||
rot_axis = min_wheel2.m_raycastInfo.m_contactPointWS
|
||||
- min_wheel.m_raycastInfo.m_contactPointWS;
|
||||
btVector3 wheel_dist = min_wheel3.m_raycastInfo.m_hardPointWS
|
||||
- min_wheel.m_raycastInfo.m_hardPointWS;
|
||||
if (rot_axis.length() != btScalar(0))
|
||||
{
|
||||
btVector3 proj = wheel_dist.dot(rot_axis) * rot_axis.normalize();
|
||||
|
||||
//calculate position on axis when a perpendicular line would go through
|
||||
//3rd wheel position when translated in ray position and rotated as
|
||||
// above
|
||||
btVector3 pos_on_axis =
|
||||
min_wheel.m_raycastInfo.m_contactPointWS + proj;
|
||||
|
||||
btVector3 to_contact_pt = min_wheel3.m_raycastInfo.m_contactPointWS
|
||||
- pos_on_axis;
|
||||
btScalar dz = to_contact_pt.dot(ray_dir);
|
||||
btScalar dw = (to_contact_pt - dz * ray_dir).length();
|
||||
rot_angle = atanf (dz / dw);
|
||||
|
||||
btVector3 rot_point = getRigidBody()->getCenterOfMassPosition()
|
||||
+ min_depth * ray_dir
|
||||
- min_wheel.m_raycastInfo.m_contactPointWS;
|
||||
rot_point = rot_point.dot(rot_axis) * rot_axis.normalize() - rot_point;
|
||||
|
||||
|
||||
//calculate translation offset to axis from center of mass along
|
||||
// perpendicular
|
||||
offset_trans.setIdentity();
|
||||
|
||||
offset= rot_point;
|
||||
offset_trans.setOrigin(rot_trans*offset);
|
||||
|
||||
btVector3 a = min_wheel3.m_raycastInfo.m_hardPointWS
|
||||
- min_wheel.m_raycastInfo.m_hardPointWS;
|
||||
btVector3 b = min_wheel2.m_raycastInfo.m_hardPointWS
|
||||
- min_wheel.m_raycastInfo.m_hardPointWS;
|
||||
|
||||
if ( (a.cross(b)).dot(ray_dir) > 0 )
|
||||
{
|
||||
rot_angle *= btScalar(-1);
|
||||
}
|
||||
|
||||
//rotate about new axis
|
||||
operator_trans.setIdentity();
|
||||
operator_trans *= offset_trans;
|
||||
operator_trans.setRotation(btQuaternion(rot_trans*rot_axis.normalize(),
|
||||
rot_angle));
|
||||
offset_trans.setOrigin(-(rot_trans*offset));
|
||||
operator_trans *= offset_trans;
|
||||
|
||||
//apply tranform
|
||||
trans *= operator_trans;
|
||||
getRigidBody()->setCenterOfMassTransform(trans);
|
||||
}
|
||||
|
||||
if (!translate_vehicle)
|
||||
return true;
|
||||
|
||||
|
||||
for (int i=0;i<getNumWheels();i++)
|
||||
{
|
||||
updateWheelTransform(i,false);
|
||||
}
|
||||
|
||||
min_depth = btScalar(-1); //minimum distance of wheel to surface
|
||||
|
||||
for (int i=0;i<m_wheelInfo.size();i++)
|
||||
{
|
||||
btScalar depth = rayCast( m_wheelInfo[i], ray);
|
||||
depth -= m_wheelInfo[i].m_wheelsRadius;
|
||||
|
||||
if (!(m_wheelInfo[i].m_raycastInfo.m_isInContact))
|
||||
{
|
||||
return false; //a wheel is not over ground
|
||||
}
|
||||
|
||||
if (depth<min_depth || i==0)
|
||||
{
|
||||
min_depth = depth;
|
||||
}
|
||||
}
|
||||
|
||||
//translate along ray so wheel closest to surface is exactly on the surface
|
||||
getRigidBody()->translate((min_depth) * ray_dir);
|
||||
//offset for suspension rest length
|
||||
getRigidBody()->translate(-min_wheel.getSuspensionRestLength() *
|
||||
min_wheel.m_raycastInfo.m_wheelDirectionWS);
|
||||
return true;
|
||||
} // projectVehicleToSurface
|
||||
|
@ -169,8 +169,6 @@ public:
|
||||
void setSliding(bool active);
|
||||
void instantSpeedIncreaseTo(float speed);
|
||||
void capSpeed(float max_speed);
|
||||
bool projectVehicleToSurface(const btVector3& ray,
|
||||
bool translate_vehicle);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** btActionInterface interface. */
|
||||
|
@ -248,18 +248,6 @@ void Physics::update(float dt)
|
||||
m_karts_to_delete.clear();
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Project all karts downwards onto the surface below.
|
||||
* Used in setting the starting positions of all the karts.
|
||||
*/
|
||||
|
||||
bool Physics::projectKartDownwards(const AbstractKart *k)
|
||||
{
|
||||
btVector3 hell(0, -10000, 0);
|
||||
return k->getVehicle()->projectVehicleToSurface(hell,
|
||||
/*allow translation*/true);
|
||||
} //projectKartsDownwards
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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
|
||||
|
@ -164,7 +164,6 @@ public:
|
||||
void nextDebugMode () {m_debug_drawer->nextDebugMode(); }
|
||||
/** Returns true if the debug drawer is enabled. */
|
||||
bool isDebug() const {return m_debug_drawer->debugEnabled(); }
|
||||
bool projectKartDownwards(const AbstractKart *k);
|
||||
virtual btScalar solveGroup(btCollisionObject** bodies, int numBodies,
|
||||
btPersistentManifold** manifold,int numManifolds,
|
||||
btTypedConstraint** constraints,int numConstraints,
|
||||
|
@ -47,6 +47,8 @@ using namespace irr;
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "modes/easter_egg_hunt.hpp"
|
||||
#include "modes/world.hpp"
|
||||
@ -2004,3 +2006,65 @@ const core::vector3df& Track::getSunRotation()
|
||||
{
|
||||
return m_sun->getRotation();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Determines if the kart is over ground.
|
||||
* Used in setting the starting positions of all the karts.
|
||||
* \param k The kart to project downward.
|
||||
* \return True of the kart is on terrain.
|
||||
*/
|
||||
|
||||
bool Track::findGround(AbstractKart *kart)
|
||||
{
|
||||
btVector3 to(kart->getXYZ());
|
||||
to.setY(-100000.f);
|
||||
|
||||
// Material and hit point are not needed;
|
||||
const Material *m;
|
||||
Vec3 hit_point, normal;
|
||||
bool over_ground = m_track_mesh->castRay(kart->getXYZ(), to, &hit_point,
|
||||
&m, &normal);
|
||||
const Vec3 &xyz = kart->getXYZ();
|
||||
if(!over_ground || !m)
|
||||
{
|
||||
Log::warn("physics", "Kart at (%f %f %f) can not be dropped.",
|
||||
xyz.getX(),xyz.getY(),xyz.getZ());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the material the kart is about to be placed on would trigger
|
||||
// a reset. If so, this is not a valid position.
|
||||
if(m->isDriveReset())
|
||||
{
|
||||
Log::warn("physics","Kart at (%f %f %f) over reset terrain '%s'",
|
||||
xyz.getX(),xyz.getY(),xyz.getZ(),
|
||||
m->getTexFname().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if the kart is too high above the ground - it would drop
|
||||
// too long.
|
||||
if(xyz.getY() - hit_point.getY() > 5)
|
||||
{
|
||||
Log::warn("physics",
|
||||
"Kart at (%f %f %f) is too high above ground at (%f %f %f)",
|
||||
xyz.getX(),xyz.getY(),xyz.getZ(),
|
||||
hit_point.getX(),hit_point.getY(),hit_point.getZ());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
btTransform t = kart->getBody()->getCenterOfMassTransform();
|
||||
// The computer offset is slightly too large, it should take
|
||||
// the default suspension rest insteat of suspension rest (i.e. the
|
||||
// length of the suspension with the weight of the kart resting on
|
||||
// it). On the other hand this initial bouncing looks nice imho
|
||||
// - so I'll leave it in for now.
|
||||
float offset = kart->getKartProperties()->getSuspensionRest() +
|
||||
kart->getKartProperties()->getWheelRadius();
|
||||
t.setOrigin(hit_point+Vec3(0, offset, 0) );
|
||||
kart->getBody()->setCenterOfMassTransform(t);
|
||||
kart->setTrans(t);
|
||||
|
||||
return true;
|
||||
} // findGround
|
||||
|
||||
|
@ -402,8 +402,9 @@ public:
|
||||
bool secondary_hits=true) const;
|
||||
void loadTrackModel (bool reverse_track = false,
|
||||
unsigned int mode_id=0);
|
||||
std::vector< std::vector<float> >
|
||||
buildHeightMap();
|
||||
bool findGround(AbstractKart *kart);
|
||||
|
||||
std::vector< std::vector<float> > buildHeightMap();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the texture with the mini map for this track. */
|
||||
const video::ITexture* getMiniMap () const { return m_mini_map; }
|
||||
|
Loading…
Reference in New Issue
Block a user