Add a better rescue animation

Also fix #2501
This commit is contained in:
Benau 2017-10-06 23:42:23 +08:00
parent cf2a9f7089
commit 4f1becb20d
4 changed files with 65 additions and 32 deletions

View File

@ -36,6 +36,7 @@ int Referee::m_st_traffic_buffer = -1;
Vec3 Referee::m_st_start_offset = Vec3(-2, 2, 2);
Vec3 Referee::m_st_start_rotation = Vec3(0, 180, 0);
Vec3 Referee::m_st_scale = Vec3(1, 1, 1);
float Referee::m_height = 0.0f;
scene::IAnimatedMesh *Referee::m_st_referee_mesh = NULL;
// ----------------------------------------------------------------------------
@ -72,6 +73,7 @@ void Referee::init()
// and for y the lowest point are at 0,0,0:
Vec3 min,max;
MeshTools::minMax3D(m_st_referee_mesh, &min, &max);
m_height = max.y() - min.y();
Vec3 offset_from_center = -0.5f*(max+min);
offset_from_center.setY(0);
scene::IMeshManipulator *mani =

View File

@ -76,6 +76,8 @@ private:
/** A rotation to be applied to the referee before displaying it. */
static Vec3 m_st_start_rotation;
static float m_height;
/** The scene node for an instance of the referee. */
scene::IAnimatedMeshSceneNode *m_scene_node;
@ -113,6 +115,9 @@ public:
/** Returns the rotation of the mesh so that it faces the kart (when
* applied to a kart with heading 0). */
static const Vec3& getStartRotation() {return m_st_start_rotation; }
// ------------------------------------------------------------------------
/** Returns the height of the referee. */
static const float getHeight() {return m_height; }
}; // Referee
#endif

View File

@ -25,11 +25,18 @@
#include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp"
#include "modes/world_with_rank.hpp"
#include "physics/physics.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/drive_graph.hpp"
#include "tracks/quad.hpp"
#include "tracks/track.hpp"
#include "tracks/track_sector.hpp"
#include "ISceneNode.h"
#include <algorithm>
/** The constructor stores a pointer to the kart this object is animating,
* and initialised the timer.
* \param kart Pointer to the kart which is animated.
@ -40,28 +47,52 @@ RescueAnimation::RescueAnimation(AbstractKart *kart, bool is_auto_rescue)
m_referee = new Referee(*m_kart);
m_kart->getNode()->addChild(m_referee->getSceneNode());
m_timer = m_kart->getKartProperties()->getRescueDuration();
m_velocity = m_kart->getKartProperties()->getRescueHeight() / m_timer;
m_up_vector = m_kart->getTrans().getBasis().getColumn(1);
m_xyz = m_kart->getXYZ();
m_orig_rotation = m_kart->getRotation();
m_kart->getAttachment()->clear();
// Get the current rotation of the kart
m_curr_rotation = m_kart->getNode()->getRotation() * DEGREE_TO_RAD;
// Determine maximum rescue height with up-raycast
float max_height = m_kart->getKartProperties()->getRescueHeight();
float hit_dest = 9999999.9f;
Vec3 hit;
const Material* m = NULL;
Vec3 to = m_up_vector * 10000.0f;
const TriangleMesh &tm = Track::getCurrentTrack()->getTriangleMesh();
if (tm.castRay(m_xyz, to, &hit, &m, NULL/*normal*/, /*interpolate*/true))
{
hit_dest = (hit - m_xyz).length();
hit_dest -= Referee::getHeight();
if (hit_dest < 1.0f)
{
hit_dest = 1.0f;
}
}
max_height = std::min(hit_dest, max_height);
m_velocity = max_height / m_timer;
// Determine the rotation that will rotate the kart from the current
// up direction to the right up direction it should have according to
// the normal at the kart's location
Vec3 up = m_kart->getTrans().getBasis().getColumn(1);
btQuaternion q = shortestArcQuat(up, m_kart->getNormal());
// Store this rotation as 'delta HPR', which is added over time to the
// current rotation to end up (after m_timer seconds) with the right up
// rotation
m_add_rotation.setHPR(q);
m_add_rotation /= m_timer;
// the last vaild quad of the kart
WorldWithRank* wwr = dynamic_cast<WorldWithRank*>(World::getWorld());
if (DriveGraph::get() && wwr)
{
const int sector = wwr->getTrackSector(m_kart->getWorldKartId())
->getCurrentGraphNode();
const Vec3& quad_normal = DriveGraph::get()->getQuad(sector)
->getNormal();
btQuaternion angle_rot(btVector3(0, 1, 0),
Track::getCurrentTrack()->getAngle(sector));
m_des_rotation = shortestArcQuat(Vec3(0, 1, 0), quad_normal) * angle_rot;
m_des_rotation.normalize();
}
else
{
m_des_rotation = m_orig_rotation;
}
// Add a hit unless it was auto-rescue
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES &&
if (race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES &&
!is_auto_rescue)
{
ThreeStrikesBattle *world=(ThreeStrikesBattle*)World::getWorld();
@ -107,14 +138,12 @@ RescueAnimation::~RescueAnimation()
*/
void RescueAnimation::update(float dt)
{
m_xyz += dt*m_velocity * m_kart->getNormal();
m_xyz += dt * m_velocity * m_up_vector;
m_kart->setXYZ(m_xyz);
m_curr_rotation += dt*m_add_rotation;
btMatrix3x3 m;
m.setEulerZYX(m_curr_rotation.getPitch(), m_curr_rotation.getHeading(),
m_curr_rotation.getRoll());
m_kart->setRotation(m);
btQuaternion result = m_des_rotation.slerp(m_orig_rotation,
m_timer / m_kart->getKartProperties()->getRescueDuration());
result.normalize();
m_kart->setRotation(result);
AbstractKartAnimation::update(dt);
} // update

View File

@ -34,21 +34,18 @@ protected:
/** The coordinates where the kart was hit originally. */
Vec3 m_xyz;
/** The kart's current rotation. */
Vec3 m_curr_rotation;
/** Column 1 of btTransform of kart. */
Vec3 m_up_vector;
/** The artificial rotation to toss the kart around. It's in units
* of rotation per second. */
Vec3 m_add_rotation;
/** The kart's original rotation. */
btQuaternion m_orig_rotation;
/** Desired rotation for rescue determined by last valid quad. */
btQuaternion m_des_rotation;
/** The velocity with which the kart is moved. */
float m_velocity;
/** Duration for the animation. This can potentially be set
* with different values for different karts, or depending
* on difficulty (so that on easy you can drive again earlier. */
float m_duration;
/** The referee during a rescue operation. */
Referee *m_referee;