diff --git a/src/karts/cannon_animation.cpp b/src/karts/cannon_animation.cpp index 799b8d026..1034871f1 100644 --- a/src/karts/cannon_animation.cpp +++ b/src/karts/cannon_animation.cpp @@ -27,18 +27,37 @@ #include "LinearMath/btTransform.h" -CannonAnimation::CannonAnimation(AbstractKart *kart, Ipo *ipo, - const Vec3 &delta) +CannonAnimation::CannonAnimation(AbstractKart *kart, Ipo *ipo) : AbstractKartAnimation(kart, "CannonAnimation") { m_curve = new AnimationBase(ipo); m_timer = ipo->getEndTime(); - Vec3 xyz = m_kart->getXYZ(); - Vec3 hpr, scale; - // Get the curve position at t=0 - m_curve->update(0, &xyz, &hpr, &scale); - m_offset = m_kart->getXYZ() - xyz-delta; - m_delta = delta; + + // Compute the delta between the kart position and the start of the curve. + // This delta is rotated with the kart and added to the interpolated curve + // position to get the actual kart position during the animation. + m_curve->update(0, &m_previous_orig_xyz); + m_delta = kart->getXYZ() - m_previous_orig_xyz; + + // Now the delta vector needs to be rotated back, so that it will point + // in the right direction when it is (in update) rotated to be the same + // as the kart's heading. To estimate the angle at the start, use the + // interpolated value at t=dt: + const float dt = 0.1f; + Vec3 xyz1; + m_curve->update(dt, &xyz1); + core::vector3df rot1 = (xyz1-m_previous_orig_xyz).toIrrVector() + .getHorizontalAngle(); + core::vector3df rot = (m_previous_orig_xyz-xyz1).toIrrVector() + .getHorizontalAngle(); + btQuaternion q(Vec3(0,1,0),rot.Y*DEGREE_TO_RAD); + btMatrix3x3 m(q); + m_delta = m * m_delta; + + // The previous call to m_curve->update will set the internal timer + // of the curve to dt. Reset it to 0 to make sure the timer is in + // synch with the timer of the CanonAnimation + m_curve->reset(); } // CannonAnimation // ---------------------------------------------------------------------------- @@ -48,9 +67,10 @@ CannonAnimation::~CannonAnimation() float epsilon = 0.5f * m_kart->getKartHeight(); btTransform pos; - pos.setOrigin(m_kart->getXYZ()+btVector3(0, m_kart->getKartHeight() + epsilon, - 0)); - pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f), m_kart->getHeading())); + pos.setOrigin(m_kart->getXYZ() + +btVector3(0, m_kart->getKartHeight() + epsilon, 0) ); + pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f), + m_kart->getHeading() )); m_kart->getBody()->setCenterOfMassTransform(pos); Vec3 v(0, 0, m_kart->getKartProperties()->getMaxSpeed()); @@ -69,18 +89,26 @@ void CannonAnimation::update(float dt) AbstractKartAnimation::update(dt); return; } - Vec3 xyz = m_kart->getXYZ(); - core::vector3df old_xyz = xyz.toIrrVector(); - Vec3 hpr, scale; - m_curve->update(dt, &xyz, &hpr, &scale); + + Vec3 xyz; + m_curve->update(dt, &xyz); + + // It can happen that the same position is returned, e.g. if the end of + // the curve is reached, but due to floating point differences the + // end is not detected in the above test. To avoid that the kart then + // rotates to a heading of 0, do not rotate in this case at all, i.e. + // the previous rotation is kept. + if(xyz!=m_previous_orig_xyz) + { + core::vector3df rot = (xyz-m_previous_orig_xyz).toIrrVector() + .getHorizontalAngle(); + btQuaternion q(Vec3(0,1,0),rot.Y*DEGREE_TO_RAD); + m_kart->setRotation(q); + } + m_previous_orig_xyz = xyz; Vec3 rotated_delta = m_kart->getTrans().getBasis()*m_delta; - rotated_delta = Vec3(0,0,0); - Vec3 new_xyz = xyz+rotated_delta+m_offset; - m_kart->setXYZ(new_xyz); + m_kart->setXYZ(xyz + rotated_delta); - core::vector3df rot = (new_xyz.toIrrVector()-old_xyz).getHorizontalAngle(); - btQuaternion q(Vec3(0,1,0),rot.Y*DEGREE_TO_RAD); - m_kart->setRotation(q); AbstractKartAnimation::update(dt); } // update diff --git a/src/karts/cannon_animation.hpp b/src/karts/cannon_animation.hpp index f0d6fdf76..d276a17bc 100644 --- a/src/karts/cannon_animation.hpp +++ b/src/karts/cannon_animation.hpp @@ -34,21 +34,21 @@ class Ipo; class CannonAnimation: public AbstractKartAnimation { protected: - /** The offset between the origin of the curve (relative to which - * all points are interpolated) and the position of the kart. */ - Vec3 m_offset; - - /** An offset that is rotated with the kart and is added to the - * interpolated point. This basically shifts the curve (usually) - * to the left/right to be aligned with the crossing point of the - * kart. */ + /** This is the difference between the position of the kart when the + * cannon line is crossed and the curve interpolation at t=0. This + * is added to each interpolated curve value to give the final + * kart position (so the kart moves relative to the curve). */ Vec3 m_delta; /** Stores the curve interpolation for the cannon. */ AnimationBase *m_curve; - + + /** This stores the original (unmodified) interpolated curve value. THis + * is used to determine the orientation of the kart. */ + Vec3 m_previous_orig_xyz; + public: - CannonAnimation(AbstractKart *kart, Ipo *ipo, const Vec3 &delta); + CannonAnimation(AbstractKart *kart, Ipo *ipo); virtual ~CannonAnimation(); virtual void update(float dt); diff --git a/src/tracks/check_cannon.cpp b/src/tracks/check_cannon.cpp index 668444492..42968c165 100644 --- a/src/tracks/check_cannon.cpp +++ b/src/tracks/check_cannon.cpp @@ -26,20 +26,6 @@ #include "modes/world.hpp" -CheckCannon::CannonCurve::CannonCurve(const XMLNode &node) - : AnimationBase(node) -{ - m_speed = -1; - node.get("speed", &m_speed); -} // CannonCurve - -// ------------------------------------------------------------------------ -void CheckCannon::CannonCurve::update(float dt) -{ -} // update - -// ============================================================================ - /** Constructor for a check cannon. * \param node XML node containing the parameters for this checkline. * \param index Index of this check structure in the check manager. @@ -49,30 +35,34 @@ CheckCannon::CheckCannon(const XMLNode &node, unsigned int index) { core::vector3df p1, p2; if(!node.get("target-p1", &p1) || - !node.get("target-p2", &p2) ) - { - printf("CheckCannon has no target line specified.\n"); - exit(-1); - } + !node.get("target-p2", &p2) ) + { + printf("CheckCannon has no target line specified.\n"); + exit(-1); + } m_target.setLine(p1, p2); m_curve = new Ipo(*(node.getNode("curve"))); } // CheckCannon // ---------------------------------------------------------------------------- +/** Destructor, frees the curve data (which the cannon animation objects only + * have a read-only copy of). + */ CheckCannon::~CheckCannon() { delete m_curve; } // ~CheckCannon // ---------------------------------------------------------------------------- +/** Called when the check line is triggered. This function creates a cannon + * animation object and attaches it to the kart. + * \param kart_index The index of the kart that triggered the check line. + */ void CheckCannon::trigger(unsigned int kart_index) { - Vec3 target(m_target.getMiddle()); - AbstractKart *kart = World::getWorld()->getKart(kart_index); + Vec3 target(m_target.getMiddle()); + AbstractKart *kart = World::getWorld()->getKart(kart_index); if(kart->getKartAnimation()) return; - const core::vector2df &cross = getCrossPoint(); - const core::line2df &line = getLine2D(); - Vec3 delta = Vec3(1,0,0) * (line.start-cross).getLength(); - new CannonAnimation(kart, m_curve->clone(), delta); + new CannonAnimation(kart, m_curve->clone()); } // CheckCannon diff --git a/src/tracks/check_cannon.hpp b/src/tracks/check_cannon.hpp index 5f69b147b..ee6e2845a 100644 --- a/src/tracks/check_cannon.hpp +++ b/src/tracks/check_cannon.hpp @@ -38,20 +38,6 @@ private: /** The target point the kart will fly to. */ core::line3df m_target; - - // ------------------------------------------------------------------------ -protected: - class CannonCurve : public AnimationBase - { - private: - /** The speed with which the kart moves. */ - float m_speed; - public: - CannonCurve(const XMLNode &node); - void update(float dt); - }; // CannonCurve - - // ------------------------------------------------------------------------ /** Stores the cannon curve data. */ Ipo *m_curve;