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 if (state()->isZipperStick()) {
58 switch (action) {
59 case Action::UNK_2:
60 case Action::UNK_3:
61 case Action::UNK_4:
62 case Action::UNK_5:
63 case Action::UNK_6:
64 action = Action::UNK_1;
65 break;
66 default:
67 break;
68 }
69 }
70
71 size_t actionIdx = static_cast<size_t>(action);
72
73 if (m_currentAction != Action::None && s_actionParams[actionIdx].priority <= m_priority) {
74 return false;
75 }
76
77 calcEndAction(true);
78 m_currentAction = action;
79 m_actionParams = &s_actionParams[actionIdx];
80 m_priority = m_actionParams->priority;
81 m_onStart = s_onStart[actionIdx];
82 m_onCalc = s_onCalc[actionIdx];
83 m_onEnd = s_onEnd[actionIdx];
84 state()->setInAction(true);
85 m_frame = 0;
86 m_flags.makeAllZero();
87 m_up = move()->up();
88 move()->clear();
89
90 applyStartSpeed();
91 (this->*m_onStart)();
92 return true;
93}
94
100void KartAction::startRotation(size_t idx) {
101 m_rotation = EGG::Quatf::ident;
102
103 EGG::Vector3f dir = move()->dir();
104 if (speed() < 0.0f) {
105 dir = -dir;
106 }
107
108 m_rotationDirection = dir.cross(bodyFront()).dot(bodyUp()) > 0.0f ? 1.0f : -1.0f;
109 setRotation(idx);
110 m_flags.setBit(eFlags::Rotating);
111}
112
114void KartAction::calcSideFromHitDepth() {
115 m_hitDepth.normalise();
116 m_side = m_hitDepth.perpInPlane(move()->smoothedUp(), true);
117
118 if (m_side.squaredLength() <= std::numeric_limits<f32>::epsilon()) {
119 m_side = EGG::Vector3f::ey;
120 }
121}
122
124void KartAction::calcSideFromHitDepthAndTranslation() {
125 calcSideFromHitDepth();
126
127 EGG::Vector3f cross = m_translation.cross(m_side);
128 f32 sign = (cross.y > 0.0f) ? 1.0f : -1.0f;
129
130 EGG::Vector3f worldSide = EGG::Vector3f::ey.cross(m_translation);
131 worldSide.normalise();
132
133 m_side = worldSide.perpInPlane(move()->smoothedUp(), true);
134
135 if (m_side.squaredLength() > std::numeric_limits<f32>::epsilon()) {
136 m_side *= sign;
137 } else {
138 m_side = EGG::Vector3f::ey;
139 }
140}
141
143void KartAction::end() {
144 state()->setInAction(false);
145 dynamics()->setForceUpright(true);
146
147 m_currentAction = Action::None;
148 m_priority = 0;
149 m_flags.makeAllZero();
150}
151
155bool KartAction::calcCurrentAction() {
156 ++m_frame;
157 return (this->*m_onCalc)();
158}
159
161void KartAction::calcEndAction(bool endArg) {
162 if (m_currentAction == Action::None) {
163 return;
164 }
165
166 if (m_onEnd) {
167 (this->*m_onEnd)(endArg);
168 end();
169 }
170}
171
173bool KartAction::calcRotation() {
174 if (!m_rotationParams) {
175 return false;
176 }
177
178 // Slow the rotation down as we approach the end of the spinout
179 if (m_currentAngle > m_finalAngle * m_rotationParams->slowdownThreshold) {
180 m_angleIncrement *= m_multiplier;
181 if (m_rotationParams->minAngleIncrement > m_angleIncrement) {
182 m_angleIncrement = m_rotationParams->minAngleIncrement;
183 }
184
185 m_multiplier -= m_multiplierDecrement;
186 if (m_rotationParams->minMultiplier > m_multiplier) {
187 m_multiplier = m_rotationParams->minMultiplier;
188 }
189 }
190
191 m_currentAngle += m_angleIncrement;
192 if (m_finalAngle < m_currentAngle) {
193 m_currentAngle = m_finalAngle;
194 return true;
195 }
196
197 return false;
198}
199
201void KartAction::calcUp() {
202 m_up += (move()->up() - m_up) * 0.3f;
203 m_up.normalise();
204}
205
206void KartAction::calcLanding() {
207 if (m_currentAngle < m_targetRot || !state()->isTouchingGround()) {
208 return;
209 }
210
211 m_flags.setBit(eFlags::Landing);
212
213 if (!isBike()) {
214 dynamics()->setForceUpright(false);
215 }
216
217 physics()->composeDecayingExtraRot(m_rotation);
218}
219
221void KartAction::startLaunch(f32 extVelScalar, f32 extVelKart, f32 extVelBike, f32 numRotations,
222 u32 param6) {
223 m_targetRot = 360.0f * numRotations;
224
225 EGG::Vector3f extVel = EGG::Vector3f::zero;
226 extVel.y = isBike() ? extVelBike : extVelKart;
227
228 if (param6 == 0) {
229 m_hitDepth = move()->dir();
230 calcSideFromHitDepth();
231 } else if (param6 == 1) {
232 calcSideFromHitDepth();
233 extVel += extVelScalar * m_side;
234 } else if (param6 == 2) {
235 calcSideFromHitDepthAndTranslation();
236 extVel += extVelScalar * m_side;
237 }
238
239 setRotation(static_cast<size_t>(numRotations + 3.0f));
240 m_rotAxis = move()->smoothedUp().cross(m_side);
241
242 dynamics()->setExtVel(dynamics()->extVel() + extVel);
243}
244
246void KartAction::activateCrush(u16 timer) {
247 move()->activateCrush(m_crushTimer + timer);
248 Item::ItemDirector::Instance()->kartItem(0).clear();
249}
250
252void KartAction::applyStartSpeed() {
253 move()->setSpeed(m_actionParams->startSpeedMult * move()->speed());
254 if (m_actionParams->startSpeedMult == 0.0f) {
255 move()->clearDrift();
256 }
257}
258
260void KartAction::setRotation(size_t idx) {
261 ASSERT(idx - 1 < s_rotationParams.size());
262 m_rotationParams = &s_rotationParams[--idx];
263
264 m_finalAngle = m_rotationParams->finalAngle;
265 m_angleIncrement = m_rotationParams->initialAngleIncrement;
266 m_multiplierDecrement = m_rotationParams->initialMultiplierDecrement;
267 m_currentAngle = 0.0f;
268 m_multiplier = 1.0f;
269}
270
271/* ================================ *
272 * START FUNCTIONS
273 * ================================ */
274
275void KartAction::startStub() {}
276
278void KartAction::startAction1() {
279 startRotation(2);
280}
281
283void KartAction::startAction2() {
284 constexpr f32 EXT_VEL_SCALAR = 0.0f;
285 constexpr f32 EXT_VEL_KART = 30.0f;
286 constexpr f32 EXT_VEL_BIKE = 30.0f;
287 constexpr f32 NUM_ROTATIONS = 1.0f;
288
289 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 0);
290}
291
293void KartAction::startAction3() {
294 constexpr f32 EXT_VEL_SCALAR = 25.0f;
295 constexpr f32 EXT_VEL_KART = 30.0f;
296 constexpr f32 EXT_VEL_BIKE = 30.0f;
297 constexpr f32 NUM_ROTATIONS = 1.0f;
298
299 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 1);
300 Item::ItemDirector::Instance()->kartItem(0).clear();
301}
302
304void KartAction::startAction5() {
305 constexpr f32 EXT_VEL_SCALAR = 13.0f;
306 constexpr f32 EXT_VEL_KART = 40.0f;
307 constexpr f32 EXT_VEL_BIKE = 45.0f;
308 constexpr f32 NUM_ROTATIONS = 1.0f;
309
310 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 2);
311}
312
314void KartAction::startAction9() {
315 startRotation(2);
316}
317
319void KartAction::startLongPressAction() {
320 constexpr u32 ACTION_DURATION = 90;
321 constexpr u16 CRUSH_DURATION = 480;
322
323 m_crushTimer = ACTION_DURATION;
324 activateCrush(CRUSH_DURATION);
325}
326
328void KartAction::startShortPressAction() {
329 constexpr u32 ACTION_DURATION = 30;
330 constexpr u16 CRUSH_DURATION = 240;
331
332 m_crushTimer = ACTION_DURATION;
333 activateCrush(CRUSH_DURATION);
334}
335
336/* ================================ *
337 * CALC FUNCTIONS
338 * ================================ */
339
340bool KartAction::calcStub() {
341 return false;
342}
343
345bool KartAction::calcAction1() {
346 calcUp();
347 bool finished = calcRotation();
348
349 m_rotation.setAxisRotation(DEG2RAD * (m_currentAngle * m_rotationDirection), m_up);
350 physics()->composeExtraRot(m_rotation);
351 return finished;
352}
353
355bool KartAction::calcLaunchAction() {
356 constexpr u32 ACTION_DURATION = 100;
357
358 if (m_flags.offBit(eFlags::Landing)) {
359 calcRotation();
360 calcLanding();
361 }
362
363 bool actionEnded = m_frame >= ACTION_DURATION;
364
365 if (actionEnded) {
366 if (m_flags.offBit(eFlags::Landing)) {
367 physics()->composeDecayingExtraRot(m_rotation);
368 }
369 } else if (m_flags.offBit(eFlags::Landing)) {
370 m_rotation.setAxisRotation(DEG2RAD * m_currentAngle, m_rotAxis);
371 physics()->composeExtraRot(m_rotation);
372 }
373
374 return actionEnded;
375}
376
378bool KartAction::calcPressAction() {
379 EGG::Vector3f extVel = KartObjectProxy::extVel();
380 extVel.y = std::min(0.0f, extVel.y);
381 dynamics()->setExtVel(extVel);
382
383 return m_frame > m_crushTimer;
384}
385
386/* ================================ *
387 * END FUNCTIONS
388 * ================================ */
389
390void KartAction::endStub(bool /*arg*/) {}
391
393void KartAction::endAction1(bool arg) {
394 if (arg) {
395 physics()->composeDecayingExtraRot(m_rotation);
396 }
397}
398
400void KartAction::endLaunchAction(bool arg) {
401 if (arg) {
402 physics()->composeDecayingExtraRot(m_rotation);
403 }
404}
405
406/* ================================ *
407 * ACTION TABLES
408 * ================================ */
409
410const std::array<KartAction::ActionParams, KartAction::MAX_ACTION> KartAction::s_actionParams = {{
411 {0.98f, 0.98f, 1},
412 {0.98f, 0.98f, 2},
413 {0.96f, 0.96f, 4},
414 {0.0f, 0.96f, 4},
415 {0.0f, 0.98f, 4},
416 {0.0f, 0.96f, 4},
417 {0.0f, 0.96f, 4},
418 {0.0f, 0.0f, 6},
419 {0.0f, 0.99f, 6},
420 {0.98f, 0.98f, 3},
421 {0.98f, 0.98f, 3},
422 {1.0f, 1.0f, 5},
423 {0.0f, 0.0f, 3},
424 {0.0f, 0.0f, 3},
425 {0.0f, 0.0f, 3},
426 {0.98f, 0.98f, 3},
427 {0.0f, 0.0f, 3},
428 {0.98f, 0.98f, 3},
429}};
430
431const std::array<KartAction::RotationParams, 5> KartAction::s_rotationParams = {{
432 {10.0f, 1.5f, 0.9f, 0.005f, 0.6f, 360.0f},
433 {11.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 720.0f},
434 {11.0f, 1.5f, 0.9f, 0.0028f, 0.8f, 1080.0f},
435 {7.0f, 1.5f, 0.9f, 0.005f, 0.6f, 450.0f},
436 {9.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 810.0f},
437}};
438
439const std::array<KartAction::StartActionFunc, KartAction::MAX_ACTION> KartAction::s_onStart = {{
440 &KartAction::startStub,
441 &KartAction::startAction1,
442 &KartAction::startAction2,
443 &KartAction::startAction3,
444 &KartAction::startStub,
445 &KartAction::startAction5,
446 &KartAction::startStub,
447 &KartAction::startStub,
448 &KartAction::startStub,
449 &KartAction::startAction9,
450 &KartAction::startStub,
451 &KartAction::startStub,
452 &KartAction::startLongPressAction,
453 &KartAction::startStub,
454 &KartAction::startShortPressAction,
455 &KartAction::startStub,
456 &KartAction::startStub,
457 &KartAction::startStub,
458}};
459
460const std::array<KartAction::CalcActionFunc, KartAction::MAX_ACTION> KartAction::s_onCalc = {{
461 &KartAction::calcStub,
462 &KartAction::calcAction1,
463 &KartAction::calcLaunchAction,
464 &KartAction::calcLaunchAction,
465 &KartAction::calcStub,
466 &KartAction::calcLaunchAction,
467 &KartAction::calcStub,
468 &KartAction::calcStub,
469 &KartAction::calcStub,
470 &KartAction::calcAction1,
471 &KartAction::calcStub,
472 &KartAction::calcStub,
473 &KartAction::calcPressAction,
474 &KartAction::calcStub,
475 &KartAction::calcPressAction,
476 &KartAction::calcStub,
477 &KartAction::calcStub,
478 &KartAction::calcStub,
479}};
480
481const std::array<KartAction::EndActionFunc, KartAction::MAX_ACTION> KartAction::s_onEnd = {{
482 &KartAction::endStub,
483 &KartAction::endAction1,
484 &KartAction::endLaunchAction,
485 &KartAction::endLaunchAction,
486 &KartAction::endStub,
487 &KartAction::endLaunchAction,
488 &KartAction::endStub,
489 &KartAction::endStub,
490 &KartAction::endStub,
491 &KartAction::endAction1,
492 &KartAction::endStub,
493 &KartAction::endStub,
494 &KartAction::endStub,
495 &KartAction::endStub,
496 &KartAction::endStub,
497 &KartAction::endStub,
498 &KartAction::endStub,
499 &KartAction::endStub,
500}};
501
502} // 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