1 //
2 // SuperTuxKart - a fun racing game with go-kart
3 // Copyright (C) 2010-2015 Joerg Henrichs
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 3
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include "karts/abstract_kart_animation.hpp"
20
21 #include "graphics/slip_stream.hpp"
22 #include "items/powerup.hpp"
23 #include "karts/abstract_kart.hpp"
24 #include "karts/kart_model.hpp"
25 #include "karts/skidding.hpp"
26 #include "modes/world.hpp"
27 #include "network/network_string.hpp"
28 #include "physics/btKart.hpp"
29 #include "physics/physics.hpp"
30 #include "physics/triangle_mesh.hpp"
31 #include "tracks/track.hpp"
32 #include "utils/mini_glm.hpp"
33
34 #include <limits>
35
36 /** Constructor. Note that kart can be NULL in case that the animation is
37 * used for a basket ball in a cannon animation.
38 * \param kart Pointer to the kart that is animated, or NULL if the
39 * the animation is meant for a basket ball etc.
40 */
AbstractKartAnimation(AbstractKart * kart,const std::string & name)41 AbstractKartAnimation::AbstractKartAnimation(AbstractKart* kart,
42 const std::string &name)
43 {
44 m_kart = kart;
45 m_name = name;
46 m_created_ticks = World::getWorld()->getTicksSinceStart();
47 m_created_transform = btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
48 // Remove previous animation if there is one
49 #ifndef DEBUG
50 // Use this code in non-debug mode to avoid a memory leak (and messed
51 // up animations) if this should happen. In debug mode this condition
52 // is caught by setKartAnimation(), and useful error messages are
53 // printed
54 if (kart && kart->getKartAnimation())
55 {
56 AbstractKartAnimation* ka = kart->getKartAnimation();
57 kart->setKartAnimation(NULL);
58 delete ka;
59 }
60 #endif
61 // Register this animation with the kart (which will free it
62 // later).
63 if (kart)
64 {
65 m_created_transform = kart->getTrans();
66 kart->setKartAnimation(this);
67 Physics::get()->removeKart(m_kart);
68 kart->getSkidding()->reset();
69 kart->getSlipstream()->reset();
70 if (kart->isSquashed())
71 {
72 // A time of 0 reset the squashing
73 kart->setSquash(0.0f, 0.0f);
74 }
75 }
76 MiniGLM::compressbtTransform(m_created_transform,
77 m_created_transform_compressed);
78 } // AbstractKartAnimation
79
80 // ----------------------------------------------------------------------------
~AbstractKartAnimation()81 AbstractKartAnimation::~AbstractKartAnimation()
82 {
83 // If m_end_ticks != int max, this object is deleted because the kart
84 // is deleted (at the end of a race), which means that
85 // world is in the process of being deleted. In this case
86 // we can't call getPhysics() anymore.
87 if (m_end_ticks != std::numeric_limits<int>::max() && m_kart)
88 {
89 Vec3 linear_velocity = m_kart->getBody()->getLinearVelocity();
90 Vec3 angular_velocity = m_kart->getBody()->getAngularVelocity();
91 // Use getTrans so the setXYZ and setRotation from subclass result
92 // can be used here
93 btTransform transform = m_kart->getTrans();
94 m_kart->getBody()->setLinearVelocity(linear_velocity);
95 m_kart->getBody()->setAngularVelocity(angular_velocity);
96 m_kart->getBody()->proceedToTransform(transform);
97 m_kart->setTrans(transform);
98 // Reset all btKart members (bounce back ticks / rotation ticks..)
99 m_kart->getVehicle()->reset();
100 Physics::get()->addKart(m_kart);
101 }
102 } // ~AbstractKartAnimation
103
104 // ----------------------------------------------------------------------------
105 /** In CTF mode call this to reset kart powerup when get hit.
106 */
resetPowerUp()107 void AbstractKartAnimation::resetPowerUp()
108 {
109 if (m_kart)
110 m_kart->getPowerup()->reset();
111 } // resetPowerUp
112
113 // ----------------------------------------------------------------------------
114 /** Updates the timer, and if it expires, the kart animation will be
115 * removed from the kart and this object will be deleted.
116 * NOTE: calling this function must be the last thing done in any kart
117 * animation class, since this object might be deleted, so accessing any
118 * members might be invalid.
119 * \param ticks Number of time steps - should be 1.
120 */
update(int ticks)121 void AbstractKartAnimation::update(int ticks)
122 {
123 // See if the timer expires, if so return the kart to normal game play
124 World* w = World::getWorld();
125 if (!w)
126 return;
127
128 if (m_end_ticks - w->getTicksSinceStart() == 0)
129 {
130 if (m_kart)
131 m_kart->setKartAnimation(NULL);
132 delete this;
133 }
134 } // update
135
136 // ----------------------------------------------------------------------------
updateGraphics(float dt)137 void AbstractKartAnimation::updateGraphics(float dt)
138 {
139 // Reset the wheels (and any other animation played for that kart)
140 // This avoid the effect that some wheels might be way below the kart
141 // which is very obvious in the rescue animation.
142 if (m_kart)
143 m_kart->getKartModel()->resetVisualWheelPosition();
144 } // updateGraphics
145
146 // ----------------------------------------------------------------------------
147 /** Returns the current animation timer.
148 */
getAnimationTimer() const149 float AbstractKartAnimation::getAnimationTimer() const
150 {
151 World* w = World::getWorld();
152 if (!w)
153 return 0.0f;
154 return stk_config->ticks2Time(m_end_ticks - w->getTicksSinceStart());
155 } // getAnimationTimer
156
157 // ----------------------------------------------------------------------------
158 /** Determine maximum rescue height with up-raycast
159 */
getMaximumHeight(const Vec3 & up_vector,float height_remove)160 float AbstractKartAnimation::getMaximumHeight(const Vec3& up_vector,
161 float height_remove)
162 {
163 float hit_dest = 9999999.9f;
164 Vec3 hit;
165 const Material* m = NULL;
166 Vec3 to = up_vector * 10000.0f;
167 const TriangleMesh &tm = Track::getCurrentTrack()->getTriangleMesh();
168 if (tm.castRay(m_created_transform.getOrigin(), to, &hit, &m,
169 NULL/*normal*/, /*interpolate*/true))
170 {
171 hit_dest = (hit - m_created_transform.getOrigin()).length();
172 hit_dest -= height_remove;
173 if (hit_dest < 1.0f)
174 {
175 hit_dest = 1.0f;
176 }
177 }
178 return hit_dest;
179 } // getMaximumHeight
180
181 // ----------------------------------------------------------------------------
saveState(BareNetworkString * buffer)182 void AbstractKartAnimation::saveState(BareNetworkString* buffer)
183 {
184 buffer->addUInt32(m_created_ticks);
185 buffer->addInt24(m_created_transform_compressed[0])
186 .addInt24(m_created_transform_compressed[1])
187 .addInt24(m_created_transform_compressed[2])
188 .addUInt32(m_created_transform_compressed[3]);
189 } // saveState
190
191 // ----------------------------------------------------------------------------
192 /** Used in constructor of sub-class as no virtual function can be used there.
193 */
restoreBasicState(BareNetworkString * buffer)194 void AbstractKartAnimation::restoreBasicState(BareNetworkString* buffer)
195 {
196 m_created_ticks = buffer->getUInt32();
197 m_created_transform_compressed[0] = buffer->getInt24();
198 m_created_transform_compressed[1] = buffer->getInt24();
199 m_created_transform_compressed[2] = buffer->getInt24();
200 m_created_transform_compressed[3] = buffer->getUInt32();
201 m_created_transform =
202 MiniGLM::decompressbtTransform(m_created_transform_compressed);
203 } // restoreBasicState
204