A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartAction.cc
1#include "KartAction.hh"
2
3#include "game/kart/KartMove.hh"
4#include "game/kart/KartPhysics.hh"
5#include "game/kart/KartState.hh"
6
7#include "game/item/ItemDirector.hh"
8#include "game/item/KartItem.hh"
9
10#include <egg/math/Math.hh>
11
12namespace Kart {
13
15KartAction::KartAction()
16 : m_currentAction(Action::None), m_hitDepth(EGG::Vector3f::zero),
17 m_translation(EGG::Vector3f::ez), m_onStart(nullptr), m_onCalc(nullptr), m_onEnd(nullptr),
18 m_actionParams(nullptr), m_rotationParams(nullptr), m_priority(0) {}
19
21KartAction::~KartAction() = default;
22
24void KartAction::init() {
25 m_currentAction = Action::None;
26 m_flags.makeAllZero();
27}
28
30void KartAction::calc() {
31 if (m_currentAction == Action::None || !m_onCalc) {
32 return;
33 }
34
35 if (calcCurrentAction()) {
36 calcEndAction(false);
37 }
38}
39
41void KartAction::calcVehicleSpeed() {
42 move()->setSpeed(m_actionParams->calcSpeedMult * move()->speed());
43}
44
49bool KartAction::start(Action action) {
50 ASSERT(action != Action::None);
51
52 if (state()->isInRespawn() || state()->isAfterRespawn() || state()->isBeforeRespawn() ||
53 state()->isInCannon()) {
54 return false;
55 }
56
57 size_t actionIdx = static_cast<size_t>(action);
58 if (m_currentAction != Action::None && s_actionParams[actionIdx].priority <= m_priority) {
59 return false;
60 }
61
62 calcEndAction(true);
63 m_currentAction = action;
64 m_actionParams = &s_actionParams[actionIdx];
65 m_priority = m_actionParams->priority;
66 m_onStart = s_onStart[actionIdx];
67 m_onCalc = s_onCalc[actionIdx];
68 m_onEnd = s_onEnd[actionIdx];
69 state()->setInAction(true);
70 m_frame = 0;
71 m_flags.makeAllZero();
72 m_up = move()->up();
73 move()->clear();
74
75 applyStartSpeed();
76 (this->*m_onStart)();
77 return true;
78}
79
85void KartAction::startRotation(size_t idx) {
86 m_rotation = EGG::Quatf::ident;
87
88 EGG::Vector3f dir = move()->dir();
89 if (speed() < 0.0f) {
90 dir = -dir;
91 }
92
93 m_rotationDirection = dir.cross(bodyFront()).dot(bodyUp()) > 0.0f ? 1.0f : -1.0f;
94 setRotation(idx);
95 m_flags.setBit(eFlags::Rotating);
96}
97
99void KartAction::calcSideFromHitDepth() {
100 m_hitDepth.normalise();
101 m_side = m_hitDepth.perpInPlane(move()->smoothedUp(), true);
102
103 if (m_side.squaredLength() <= std::numeric_limits<f32>::epsilon()) {
104 m_side = EGG::Vector3f::ey;
105 }
106}
107
109void KartAction::calcSideFromHitDepthAndTranslation() {
110 calcSideFromHitDepth();
111
112 EGG::Vector3f cross = m_translation.cross(m_side);
113 f32 sign = (cross.y > 0.0f) ? 1.0f : -1.0f;
114
115 EGG::Vector3f worldSide = EGG::Vector3f::ey.cross(m_translation);
116 worldSide.normalise();
117
118 m_side = worldSide.perpInPlane(move()->smoothedUp(), true);
119
120 if (m_side.squaredLength() > std::numeric_limits<f32>::epsilon()) {
121 m_side *= sign;
122 } else {
123 m_side = EGG::Vector3f::ey;
124 }
125}
126
128void KartAction::end() {
129 state()->setInAction(false);
130 dynamics()->setForceUpright(true);
131
132 m_currentAction = Action::None;
133 m_priority = 0;
134 m_flags.makeAllZero();
135}
136
140bool KartAction::calcCurrentAction() {
141 ++m_frame;
142 return (this->*m_onCalc)();
143}
144
146void KartAction::calcEndAction(bool endArg) {
147 if (m_currentAction == Action::None) {
148 return;
149 }
150
151 if (m_onEnd) {
152 (this->*m_onEnd)(endArg);
153 end();
154 }
155}
156
158bool KartAction::calcRotation() {
159 if (!m_rotationParams) {
160 return false;
161 }
162
163 // Slow the rotation down as we approach the end of the spinout
164 if (m_currentAngle > m_finalAngle * m_rotationParams->slowdownThreshold) {
165 m_angleIncrement *= m_multiplier;
166 if (m_rotationParams->minAngleIncrement > m_angleIncrement) {
167 m_angleIncrement = m_rotationParams->minAngleIncrement;
168 }
169
170 m_multiplier -= m_multiplierDecrement;
171 if (m_rotationParams->minMultiplier > m_multiplier) {
172 m_multiplier = m_rotationParams->minMultiplier;
173 }
174 }
175
176 m_currentAngle += m_angleIncrement;
177 if (m_finalAngle < m_currentAngle) {
178 m_currentAngle = m_finalAngle;
179 return true;
180 }
181
182 return false;
183}
184
186void KartAction::calcUp() {
187 m_up += (move()->up() - m_up) * 0.3f;
188 m_up.normalise();
189}
190
191void KartAction::calcLanding() {
192 if (m_currentAngle < m_targetRot || !state()->isTouchingGround()) {
193 return;
194 }
195
196 m_flags.setBit(eFlags::Landing);
197
198 if (!isBike()) {
199 dynamics()->setForceUpright(false);
200 }
201
202 physics()->composeDecayingExtraRot(m_rotation);
203}
204
206void KartAction::startLaunch(f32 extVelScalar, f32 extVelKart, f32 extVelBike, f32 numRotations,
207 u32 param6) {
208 m_targetRot = 360.0f * numRotations;
209
210 EGG::Vector3f extVel = EGG::Vector3f::zero;
211 extVel.y = isBike() ? extVelBike : extVelKart;
212
213 if (param6 == 0) {
214 m_hitDepth = move()->dir();
215 calcSideFromHitDepth();
216 } else if (param6 == 1) {
217 calcSideFromHitDepth();
218 extVel += extVelScalar * m_side;
219 } else if (param6 == 2) {
220 calcSideFromHitDepthAndTranslation();
221 extVel += extVelScalar * m_side;
222 }
223
224 setRotation(static_cast<size_t>(numRotations + 3.0f));
225 m_rotAxis = move()->smoothedUp().cross(m_side);
226
227 dynamics()->setExtVel(dynamics()->extVel() + extVel);
228}
229
231void KartAction::activateCrush(u16 timer) {
232 move()->activateCrush(m_crushTimer + timer);
233 Item::ItemDirector::Instance()->kartItem(0).clear();
234}
235
237void KartAction::applyStartSpeed() {
238 move()->setSpeed(m_actionParams->startSpeedMult * move()->speed());
239 if (m_actionParams->startSpeedMult == 0.0f) {
240 move()->clearDrift();
241 }
242}
243
245void KartAction::setRotation(size_t idx) {
246 ASSERT(idx - 1 < s_rotationParams.size());
247 m_rotationParams = &s_rotationParams[--idx];
248
249 m_finalAngle = m_rotationParams->finalAngle;
250 m_angleIncrement = m_rotationParams->initialAngleIncrement;
251 m_multiplierDecrement = m_rotationParams->initialMultiplierDecrement;
252 m_currentAngle = 0.0f;
253 m_multiplier = 1.0f;
254}
255
256/* ================================ *
257 * START FUNCTIONS
258 * ================================ */
259
260void KartAction::startStub() {}
261
263void KartAction::startAction1() {
264 startRotation(2);
265}
266
268void KartAction::startAction5() {
269 constexpr f32 EXT_VEL_SCALAR = 13.0f;
270 constexpr f32 EXT_VEL_KART = 40.0f;
271 constexpr f32 EXT_VEL_BIKE = 45.0f;
272 constexpr f32 NUM_ROTATIONS = 1.0f;
273
274 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 2);
275}
276
278void KartAction::startAction9() {
279 startRotation(2);
280}
281
283void KartAction::startLongPressAction() {
284 constexpr u32 ACTION_DURATION = 90;
285 constexpr u16 CRUSH_DURATION = 480;
286
287 m_crushTimer = ACTION_DURATION;
288 activateCrush(CRUSH_DURATION);
289}
290
292void KartAction::startShortPressAction() {
293 constexpr u32 ACTION_DURATION = 30;
294 constexpr u16 CRUSH_DURATION = 240;
295
296 m_crushTimer = ACTION_DURATION;
297 activateCrush(CRUSH_DURATION);
298}
299
300/* ================================ *
301 * CALC FUNCTIONS
302 * ================================ */
303
304bool KartAction::calcStub() {
305 return false;
306}
307
309bool KartAction::calcAction1() {
310 calcUp();
311 bool finished = calcRotation();
312
313 m_rotation.setAxisRotation(DEG2RAD * (m_currentAngle * m_rotationDirection), m_up);
314 physics()->composeExtraRot(m_rotation);
315 return finished;
316}
317
319bool KartAction::calcAction5() {
320 constexpr u32 ACTION_DURATION = 100;
321
322 if (m_flags.offBit(eFlags::Landing)) {
323 calcRotation();
324 calcLanding();
325 }
326
327 bool actionEnded = m_frame >= ACTION_DURATION;
328
329 if (actionEnded) {
330 if (m_flags.offBit(eFlags::Landing)) {
331 physics()->composeDecayingExtraRot(m_rotation);
332 }
333 } else if (m_flags.offBit(eFlags::Landing)) {
334 m_rotation.setAxisRotation(DEG2RAD * m_currentAngle, m_rotAxis);
335 physics()->composeExtraRot(m_rotation);
336 }
337
338 return actionEnded;
339}
340
342bool KartAction::calcPressAction() {
343 EGG::Vector3f extVel = KartObjectProxy::extVel();
344 extVel.y = std::min(0.0f, extVel.y);
345 dynamics()->setExtVel(extVel);
346
347 return m_frame > m_crushTimer;
348}
349
350/* ================================ *
351 * END FUNCTIONS
352 * ================================ */
353
354void KartAction::endStub(bool /*arg*/) {}
355
357void KartAction::endAction1(bool arg) {
358 if (arg) {
359 physics()->composeDecayingExtraRot(m_rotation);
360 }
361}
362
364void KartAction::endAction5(bool arg) {
365 if (arg) {
366 physics()->composeDecayingExtraRot(m_rotation);
367 }
368}
369
370/* ================================ *
371 * ACTION TABLES
372 * ================================ */
373
374const std::array<KartAction::ActionParams, KartAction::MAX_ACTION> KartAction::s_actionParams = {{
375 {0.98f, 0.98f, 1},
376 {0.98f, 0.98f, 2},
377 {0.96f, 0.96f, 4},
378 {0.0f, 0.96f, 4},
379 {0.0f, 0.98f, 4},
380 {0.0f, 0.96f, 4},
381 {0.0f, 0.96f, 4},
382 {0.0f, 0.0f, 6},
383 {0.0f, 0.99f, 6},
384 {0.98f, 0.98f, 3},
385 {0.98f, 0.98f, 3},
386 {1.0f, 1.0f, 5},
387 {0.0f, 0.0f, 3},
388 {0.0f, 0.0f, 3},
389 {0.0f, 0.0f, 3},
390 {0.98f, 0.98f, 3},
391 {0.0f, 0.0f, 3},
392 {0.98f, 0.98f, 3},
393}};
394
395const std::array<KartAction::RotationParams, 5> KartAction::s_rotationParams = {{
396 {10.0f, 1.5f, 0.9f, 0.005f, 0.6f, 360.0f},
397 {11.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 720.0f},
398 {11.0f, 1.5f, 0.9f, 0.0028f, 0.8f, 1080.0f},
399 {7.0f, 1.5f, 0.9f, 0.005f, 0.6f, 450.0f},
400 {9.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 810.0f},
401}};
402
403const std::array<KartAction::StartActionFunc, KartAction::MAX_ACTION> KartAction::s_onStart = {{
404 &KartAction::startStub,
405 &KartAction::startAction1,
406 &KartAction::startStub,
407 &KartAction::startStub,
408 &KartAction::startStub,
409 &KartAction::startAction5,
410 &KartAction::startStub,
411 &KartAction::startStub,
412 &KartAction::startStub,
413 &KartAction::startAction9,
414 &KartAction::startStub,
415 &KartAction::startStub,
416 &KartAction::startLongPressAction,
417 &KartAction::startStub,
418 &KartAction::startShortPressAction,
419 &KartAction::startStub,
420 &KartAction::startStub,
421 &KartAction::startStub,
422}};
423
424const std::array<KartAction::CalcActionFunc, KartAction::MAX_ACTION> KartAction::s_onCalc = {{
425 &KartAction::calcStub,
426 &KartAction::calcAction1,
427 &KartAction::calcStub,
428 &KartAction::calcStub,
429 &KartAction::calcStub,
430 &KartAction::calcAction5,
431 &KartAction::calcStub,
432 &KartAction::calcStub,
433 &KartAction::calcStub,
434 &KartAction::calcAction1,
435 &KartAction::calcStub,
436 &KartAction::calcStub,
437 &KartAction::calcPressAction,
438 &KartAction::calcStub,
439 &KartAction::calcPressAction,
440 &KartAction::calcStub,
441 &KartAction::calcStub,
442 &KartAction::calcStub,
443}};
444
445const std::array<KartAction::EndActionFunc, KartAction::MAX_ACTION> KartAction::s_onEnd = {{
446 &KartAction::endStub,
447 &KartAction::endAction1,
448 &KartAction::endStub,
449 &KartAction::endStub,
450 &KartAction::endStub,
451 &KartAction::endAction5,
452 &KartAction::endStub,
453 &KartAction::endStub,
454 &KartAction::endStub,
455 &KartAction::endAction1,
456 &KartAction::endStub,
457 &KartAction::endStub,
458 &KartAction::endStub,
459 &KartAction::endStub,
460 &KartAction::endStub,
461 &KartAction::endStub,
462 &KartAction::endStub,
463 &KartAction::endStub,
464}};
465
466} // namespace Kart
EGG core library.
Definition Archive.cc:6
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:87
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:44
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:186
Vector3f perpInPlane(const EGG::Vector3f &rhs, bool normalise) const
Calculates the orthogonal vector, based on the plane defined by this vector and rhs.
Definition Vector.cc:96