Fix : 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:
hikerstk 2013-06-06 23:08:52 +00:00
parent 6b05b70d04
commit a529a07c99
12 changed files with 78 additions and 261 deletions

View File

@ -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
//-----------------------------------------------------------------------------

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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

View File

@ -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. */

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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; }