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_offset = Vec3(-2, 2, 2);
Vec3 Referee::m_st_start_rotation = Vec3(0, 180, 0); Vec3 Referee::m_st_start_rotation = Vec3(0, 180, 0);
Vec3 Referee::m_st_scale = Vec3(1, 1, 1); Vec3 Referee::m_st_scale = Vec3(1, 1, 1);
float Referee::m_height = 0.0f;
scene::IAnimatedMesh *Referee::m_st_referee_mesh = NULL; 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: // and for y the lowest point are at 0,0,0:
Vec3 min,max; Vec3 min,max;
MeshTools::minMax3D(m_st_referee_mesh, &min, &max); MeshTools::minMax3D(m_st_referee_mesh, &min, &max);
m_height = max.y() - min.y();
Vec3 offset_from_center = -0.5f*(max+min); Vec3 offset_from_center = -0.5f*(max+min);
offset_from_center.setY(0); offset_from_center.setY(0);
scene::IMeshManipulator *mani = scene::IMeshManipulator *mani =

View File

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

View File

@ -25,11 +25,18 @@
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp" #include "karts/kart_properties.hpp"
#include "modes/three_strikes_battle.hpp" #include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp" #include "modes/world_with_rank.hpp"
#include "physics/physics.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 "ISceneNode.h"
#include <algorithm>
/** The constructor stores a pointer to the kart this object is animating, /** The constructor stores a pointer to the kart this object is animating,
* and initialised the timer. * and initialised the timer.
* \param kart Pointer to the kart which is animated. * \param kart Pointer to the kart which is animated.
@ -40,25 +47,49 @@ RescueAnimation::RescueAnimation(AbstractKart *kart, bool is_auto_rescue)
m_referee = new Referee(*m_kart); m_referee = new Referee(*m_kart);
m_kart->getNode()->addChild(m_referee->getSceneNode()); m_kart->getNode()->addChild(m_referee->getSceneNode());
m_timer = m_kart->getKartProperties()->getRescueDuration(); 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_xyz = m_kart->getXYZ();
m_orig_rotation = m_kart->getRotation();
m_kart->getAttachment()->clear(); m_kart->getAttachment()->clear();
// Get the current rotation of the kart // Determine maximum rescue height with up-raycast
m_curr_rotation = m_kart->getNode()->getRotation() * DEGREE_TO_RAD; 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 // Determine the rotation that will rotate the kart from the current
// up direction to the right up direction it should have according to // up direction to the right up direction it should have according to
// the normal at the kart's location // the last vaild quad of the kart
Vec3 up = m_kart->getTrans().getBasis().getColumn(1); WorldWithRank* wwr = dynamic_cast<WorldWithRank*>(World::getWorld());
btQuaternion q = shortestArcQuat(up, m_kart->getNormal()); if (DriveGraph::get() && wwr)
{
// Store this rotation as 'delta HPR', which is added over time to the const int sector = wwr->getTrackSector(m_kart->getWorldKartId())
// current rotation to end up (after m_timer seconds) with the right up ->getCurrentGraphNode();
// rotation const Vec3& quad_normal = DriveGraph::get()->getQuad(sector)
m_add_rotation.setHPR(q); ->getNormal();
m_add_rotation /= m_timer; 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 // 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 &&
@ -107,14 +138,12 @@ RescueAnimation::~RescueAnimation()
*/ */
void RescueAnimation::update(float dt) 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_kart->setXYZ(m_xyz);
m_curr_rotation += dt*m_add_rotation; btQuaternion result = m_des_rotation.slerp(m_orig_rotation,
btMatrix3x3 m; m_timer / m_kart->getKartProperties()->getRescueDuration());
m.setEulerZYX(m_curr_rotation.getPitch(), m_curr_rotation.getHeading(), result.normalize();
m_curr_rotation.getRoll()); m_kart->setRotation(result);
m_kart->setRotation(m);
AbstractKartAnimation::update(dt); AbstractKartAnimation::update(dt);
} // update } // update

View File

@ -34,21 +34,18 @@ protected:
/** The coordinates where the kart was hit originally. */ /** The coordinates where the kart was hit originally. */
Vec3 m_xyz; Vec3 m_xyz;
/** The kart's current rotation. */ /** Column 1 of btTransform of kart. */
Vec3 m_curr_rotation; Vec3 m_up_vector;
/** The artificial rotation to toss the kart around. It's in units /** The kart's original rotation. */
* of rotation per second. */ btQuaternion m_orig_rotation;
Vec3 m_add_rotation;
/** Desired rotation for rescue determined by last valid quad. */
btQuaternion m_des_rotation;
/** The velocity with which the kart is moved. */ /** The velocity with which the kart is moved. */
float m_velocity; 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. */ /** The referee during a rescue operation. */
Referee *m_referee; Referee *m_referee;