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::startAction2() {
269 constexpr f32 EXT_VEL_SCALAR = 0.0f;
270 constexpr f32 EXT_VEL_KART = 30.0f;
271 constexpr f32 EXT_VEL_BIKE = 30.0f;
272 constexpr f32 NUM_ROTATIONS = 1.0f;
273
274 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 0);
275}
276
278void KartAction::startAction3() {
279 constexpr f32 EXT_VEL_SCALAR = 25.0f;
280 constexpr f32 EXT_VEL_KART = 30.0f;
281 constexpr f32 EXT_VEL_BIKE = 30.0f;
282 constexpr f32 NUM_ROTATIONS = 1.0f;
283
284 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 1);
285 Item::ItemDirector::Instance()->kartItem(0).clear();
286}
287
289void KartAction::startAction5() {
290 constexpr f32 EXT_VEL_SCALAR = 13.0f;
291 constexpr f32 EXT_VEL_KART = 40.0f;
292 constexpr f32 EXT_VEL_BIKE = 45.0f;
293 constexpr f32 NUM_ROTATIONS = 1.0f;
294
295 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 2);
296}
297
299void KartAction::startAction9() {
300 startRotation(2);
301}
302
304void KartAction::startLongPressAction() {
305 constexpr u32 ACTION_DURATION = 90;
306 constexpr u16 CRUSH_DURATION = 480;
307
308 m_crushTimer = ACTION_DURATION;
309 activateCrush(CRUSH_DURATION);
310}
311
313void KartAction::startShortPressAction() {
314 constexpr u32 ACTION_DURATION = 30;
315 constexpr u16 CRUSH_DURATION = 240;
316
317 m_crushTimer = ACTION_DURATION;
318 activateCrush(CRUSH_DURATION);
319}
320
321/* ================================ *
322 * CALC FUNCTIONS
323 * ================================ */
324
325bool KartAction::calcStub() {
326 return false;
327}
328
330bool KartAction::calcAction1() {
331 calcUp();
332 bool finished = calcRotation();
333
334 m_rotation.setAxisRotation(DEG2RAD * (m_currentAngle * m_rotationDirection), m_up);
335 physics()->composeExtraRot(m_rotation);
336 return finished;
337}
338
340bool KartAction::calcLaunchAction() {
341 constexpr u32 ACTION_DURATION = 100;
342
343 if (m_flags.offBit(eFlags::Landing)) {
344 calcRotation();
345 calcLanding();
346 }
347
348 bool actionEnded = m_frame >= ACTION_DURATION;
349
350 if (actionEnded) {
351 if (m_flags.offBit(eFlags::Landing)) {
352 physics()->composeDecayingExtraRot(m_rotation);
353 }
354 } else if (m_flags.offBit(eFlags::Landing)) {
355 m_rotation.setAxisRotation(DEG2RAD * m_currentAngle, m_rotAxis);
356 physics()->composeExtraRot(m_rotation);
357 }
358
359 return actionEnded;
360}
361
363bool KartAction::calcPressAction() {
364 EGG::Vector3f extVel = KartObjectProxy::extVel();
365 extVel.y = std::min(0.0f, extVel.y);
366 dynamics()->setExtVel(extVel);
367
368 return m_frame > m_crushTimer;
369}
370
371/* ================================ *
372 * END FUNCTIONS
373 * ================================ */
374
375void KartAction::endStub(bool /*arg*/) {}
376
378void KartAction::endAction1(bool arg) {
379 if (arg) {
380 physics()->composeDecayingExtraRot(m_rotation);
381 }
382}
383
385void KartAction::endLaunchAction(bool arg) {
386 if (arg) {
387 physics()->composeDecayingExtraRot(m_rotation);
388 }
389}
390
391/* ================================ *
392 * ACTION TABLES
393 * ================================ */
394
395const std::array<KartAction::ActionParams, KartAction::MAX_ACTION> KartAction::s_actionParams = {{
396 {0.98f, 0.98f, 1},
397 {0.98f, 0.98f, 2},
398 {0.96f, 0.96f, 4},
399 {0.0f, 0.96f, 4},
400 {0.0f, 0.98f, 4},
401 {0.0f, 0.96f, 4},
402 {0.0f, 0.96f, 4},
403 {0.0f, 0.0f, 6},
404 {0.0f, 0.99f, 6},
405 {0.98f, 0.98f, 3},
406 {0.98f, 0.98f, 3},
407 {1.0f, 1.0f, 5},
408 {0.0f, 0.0f, 3},
409 {0.0f, 0.0f, 3},
410 {0.0f, 0.0f, 3},
411 {0.98f, 0.98f, 3},
412 {0.0f, 0.0f, 3},
413 {0.98f, 0.98f, 3},
414}};
415
416const std::array<KartAction::RotationParams, 5> KartAction::s_rotationParams = {{
417 {10.0f, 1.5f, 0.9f, 0.005f, 0.6f, 360.0f},
418 {11.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 720.0f},
419 {11.0f, 1.5f, 0.9f, 0.0028f, 0.8f, 1080.0f},
420 {7.0f, 1.5f, 0.9f, 0.005f, 0.6f, 450.0f},
421 {9.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 810.0f},
422}};
423
424const std::array<KartAction::StartActionFunc, KartAction::MAX_ACTION> KartAction::s_onStart = {{
425 &KartAction::startStub,
426 &KartAction::startAction1,
427 &KartAction::startAction2,
428 &KartAction::startAction3,
429 &KartAction::startStub,
430 &KartAction::startAction5,
431 &KartAction::startStub,
432 &KartAction::startStub,
433 &KartAction::startStub,
434 &KartAction::startAction9,
435 &KartAction::startStub,
436 &KartAction::startStub,
437 &KartAction::startLongPressAction,
438 &KartAction::startStub,
439 &KartAction::startShortPressAction,
440 &KartAction::startStub,
441 &KartAction::startStub,
442 &KartAction::startStub,
443}};
444
445const std::array<KartAction::CalcActionFunc, KartAction::MAX_ACTION> KartAction::s_onCalc = {{
446 &KartAction::calcStub,
447 &KartAction::calcAction1,
448 &KartAction::calcLaunchAction,
449 &KartAction::calcLaunchAction,
450 &KartAction::calcStub,
451 &KartAction::calcLaunchAction,
452 &KartAction::calcStub,
453 &KartAction::calcStub,
454 &KartAction::calcStub,
455 &KartAction::calcAction1,
456 &KartAction::calcStub,
457 &KartAction::calcStub,
458 &KartAction::calcPressAction,
459 &KartAction::calcStub,
460 &KartAction::calcPressAction,
461 &KartAction::calcStub,
462 &KartAction::calcStub,
463 &KartAction::calcStub,
464}};
465
466const std::array<KartAction::EndActionFunc, KartAction::MAX_ACTION> KartAction::s_onEnd = {{
467 &KartAction::endStub,
468 &KartAction::endAction1,
469 &KartAction::endLaunchAction,
470 &KartAction::endLaunchAction,
471 &KartAction::endStub,
472 &KartAction::endLaunchAction,
473 &KartAction::endStub,
474 &KartAction::endStub,
475 &KartAction::endStub,
476 &KartAction::endAction1,
477 &KartAction::endStub,
478 &KartAction::endStub,
479 &KartAction::endStub,
480 &KartAction::endStub,
481 &KartAction::endStub,
482 &KartAction::endStub,
483 &KartAction::endStub,
484 &KartAction::endStub,
485}};
486
487} // namespace Kart
EGG core library.
Definition Archive.cc:6
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:88
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:52
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:187
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:104