A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartJump.cc
1#include "KartJump.hh"
2
3#include "game/kart/KartCollide.hh"
4#include "game/kart/KartMove.hh"
5#include "game/kart/KartParam.hh"
6#include "game/kart/KartPhysics.hh"
7#include "game/kart/KartState.hh"
8
9#include "game/system/KPadController.hh"
10
11#include <egg/math/Math.hh>
12
13namespace Kart {
14
16KartJump::KartJump(KartMove *move) : m_move(move) {
17 m_cooldown = 0;
18
19 // The base game doesn't initialize this explicitly, since EGG::Heaps are memset to 0.
20 m_nextAllowTimer = 0;
21}
22
24KartJump::~KartJump() = default;
25
27void KartJump::calcRot() {
28 m_angleDelta *= m_angleDeltaFactor;
29 m_angleDelta = std::max(m_angleDelta, m_properties.angleDeltaMin);
30 m_angleDeltaFactor -= m_angleDeltaFactorDec;
31 m_angleDeltaFactor = std::max(m_angleDeltaFactor, m_properties.angleDeltaFactorMin);
32 m_angle += m_angleDelta;
33 m_angle = std::min(m_angle, m_finalAngle);
34
35 switch (m_type) {
36 case TrickType::KartFlipTrickZ:
37 m_rot.setRPY(0.0f, 0.0f, -(m_angle * DEG2RAD) * m_rotSign);
38 break;
39 case TrickType::FlipTrickYLeft:
40 case TrickType::FlipTrickYRight:
41 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
42 break;
43 default:
44 break;
45 }
46
47 physics()->composeStuntRot(m_rot);
48}
49
51void KartJump::setupProperties() {
52 static constexpr std::array<TrickProperties, 3> TRICK_PROPERTIES = {{
53 {11.0f, 1.5f, 0.9f, 0.0018f},
54 {14.0f, 1.5f, 0.9f, 0.0006f},
55 {7.5f, 2.5f, 0.93f, 0.05f},
56 }};
57
58 static constexpr std::array<f32, 3> FINAL_ANGLES = {{
59 360.0f,
60 720.0f,
61 180.0f,
62 }};
63
64 if (m_variant == SurfaceVariant::SingleFlipTrick) {
65 m_properties = TRICK_PROPERTIES[0];
66 m_finalAngle = FINAL_ANGLES[0];
67 } else if (m_variant == SurfaceVariant::StuntTrick) {
68 m_properties = TRICK_PROPERTIES[1];
69 m_finalAngle = FINAL_ANGLES[1];
70 } else if (m_type == TrickType::BikeSideStuntTrick) {
71 m_properties = TRICK_PROPERTIES[2];
72 m_finalAngle = FINAL_ANGLES[2];
73 }
74
75 m_angleDelta = m_properties.initialAngleDiff;
76 m_angleDeltaFactorDec = m_properties.angleDiffMulDec;
77 m_angle = 0.0f;
78 m_angleDeltaFactor = 1.0f;
79 m_rot = EGG::Quatf::ident;
80}
81
83void KartJump::reset() {
84 m_cooldown = 0;
85}
86
88void KartJump::tryStart(const EGG::Vector3f &left) {
89 auto &status = KartObjectProxy::status();
90
91 if (status.offBit(eStatus::TrickStart)) {
92 return;
93 }
94
95 if (m_move->speedRatioCapped() > 0.5f) {
96 s32 boostRampType = state()->boostRampType();
97
98 if (boostRampType == 0) {
99 m_variant = SurfaceVariant::StuntTrick;
100 } else if (boostRampType == 1) {
101 m_variant = SurfaceVariant::SingleFlipTrick;
102 } else {
103 m_variant = SurfaceVariant::DoubleFlipTrick;
104 }
105
106 start(left);
107 }
108
109 status.resetBit(eStatus::TrickStart);
110}
111
113void KartJump::calc() {
114 m_cooldown = std::max(0, m_cooldown - 1);
115
116 if (status().onBit(eStatus::TrickRot)) {
117 calcRot();
118 }
119
120 calcInput();
121}
122
123bool KartJump::someFlagCheck() {
124 return status().onBit(eStatus::InAction, eStatus::TrickStart, eStatus::InATrick,
125 eStatus::OverZipper);
126}
127
129void KartJump::calcInput() {
130 constexpr s16 TRICK_ALLOW_TIMER = 14;
131
132 System::Trick trick = inputs()->currentState().trick;
133
134 if (!someFlagCheck() && trick != System::Trick::None) {
135 m_nextTrick = trick;
136 m_nextAllowTimer = TRICK_ALLOW_TIMER;
137 }
138
139 auto &status = KartObjectProxy::status();
140
141 u32 airtime = state()->airtime();
142 if (airtime == 0 || m_nextAllowTimer < 1 || airtime > 10 ||
143 (status.offBit(eStatus::Trickable) && state()->boostRampType() < 0) ||
144 someFlagCheck()) {
145 m_nextAllowTimer = std::max(0, m_nextAllowTimer - 1);
146 } else {
147 if (airtime > 2) {
148 status.setBit(eStatus::TrickStart);
149 }
150 if (status.onBit(eStatus::RampBoost)) {
151 m_boostRampEnabled = true;
152 }
153 }
154 if (status.onBit(eStatus::TouchingGround) &&
155 collide()->surfaceFlags().offBit(KartCollide::eSurfaceFlags::BoostRamp)) {
156 m_boostRampEnabled = false;
157 }
158}
159
161void KartJump::end() {
162 auto &status = KartObjectProxy::status();
163
164 if (status.onBit(eStatus::TrickRot)) {
165 physics()->composeDecayingStuntRot(m_rot);
166 }
167
168 status.resetBit(eStatus::InATrick, eStatus::TrickRot);
169 m_boostRampEnabled = false;
170}
171
173void KartJump::setAngle(const EGG::Vector3f &left) {
174 static constexpr std::array<std::array<AngleProperties, 3>, 3> ANGLE_PROPERTIES = {{
175 {{
176 {40.0f, 15.0f},
177 {45.0f, 20.0f},
178 {45.0f, 20.0f},
179 }},
180 {{
181 {36.0f, 13.0f},
182 {42.0f, 18.0f},
183 {42.0f, 18.0f},
184 }},
185 {{
186 {32.0f, 11.0f},
187 {39.0f, 16.0f},
188 {39.0f, 16.0f},
189 }},
190 }};
191
192 f32 vel1YDot = m_move->vel1Dir().dot(EGG::Vector3f::ey);
193 EGG::Vector3f vel1YCross = m_move->vel1Dir().cross(EGG::Vector3f::ey);
194 f32 vel1YCrossMag = vel1YCross.length();
195 f32 pitch = EGG::Mathf::abs(EGG::Mathf::atan2(vel1YCrossMag, vel1YDot));
196 f32 angle = 90.0f - (pitch * RAD2DEG);
197 u32 weightClass = static_cast<u32>(param()->stats().weightClass);
198 f32 targetAngle = ANGLE_PROPERTIES[weightClass][static_cast<u32>(m_variant)].targetAngle;
199
200 if (status().onBit(eStatus::JumpPad) || angle > targetAngle) {
201 return;
202 }
203
204 f32 rotAngle = ANGLE_PROPERTIES[weightClass][static_cast<u32>(m_variant)].rotAngle;
205
206 if (angle + rotAngle > targetAngle) {
207 rotAngle = targetAngle - angle;
208 }
209
210 EGG::Matrix34f nextDir;
211 nextDir.setAxisRotation(-rotAngle * DEG2RAD, left);
212 m_move->setDir(nextDir.ps_multVector(m_move->dir()));
213 m_move->setVel1Dir(m_move->dir());
214}
215
217void KartJump::start(const EGG::Vector3f &left) {
218 init();
219 setAngle(left);
220 status().setBit(eStatus::InATrick);
221 m_cooldown = 5;
222}
223
225void KartJump::init() {
226 if (m_variant == SurfaceVariant::DoubleFlipTrick) {
227 m_type = TrickType::StuntTrickBasic;
228 return;
229 }
230
231 if (m_nextTrick < System::Trick::Left) {
232 m_type = TrickType::KartFlipTrickZ;
233 m_rotSign = (m_nextTrick == System::Trick::Up) ? -1.0f : 1.0f;
234 } else {
235 m_type = static_cast<TrickType>(m_nextTrick);
236 m_rotSign = (m_type == TrickType::FlipTrickYRight) ? -1.0f : 1.0f;
237 }
238
239 setupProperties();
240 status().setBit(eStatus::TrickRot);
241}
242
243KartJumpBike::KartJumpBike(KartMove *move) : KartJump(move) {}
244
246KartJumpBike::~KartJumpBike() = default;
247
249void KartJumpBike::calcRot() {
251 constexpr f32 PI_OVER_9 = 0.34906584f;
253 constexpr f32 PI_OVER_3 = 1.0471976f;
254
255 m_angleDelta *= m_angleDeltaFactor;
256 m_angleDelta = std::max(m_angleDelta, m_properties.angleDeltaMin);
257 m_angleDeltaFactor -= m_angleDeltaFactorDec;
258 m_angleDeltaFactor = std::max(m_angleDeltaFactor, m_properties.angleDeltaFactorMin);
259 m_angle += m_angleDelta;
260 m_angle = std::min(m_angle, m_finalAngle);
261
262 switch (m_type) {
263 case TrickType::BikeFlipTrickNose:
264 case TrickType::BikeFlipTrickTail:
265 m_rot.setRPY(-(m_angle * DEG2RAD) * m_rotSign, 0.0f, 0.0f);
266 break;
267 case TrickType::FlipTrickYLeft:
268 case TrickType::FlipTrickYRight:
269 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
270 break;
271 case TrickType::BikeSideStuntTrick: {
272 f32 sin = EGG::Mathf::SinFIdx(m_angle * DEG2FIDX);
273 m_rot.setRPY(sin * -PI_OVER_9, (sin * m_rotSign) * -PI_OVER_3,
274 (sin * m_rotSign) * PI_OVER_9);
275 } break;
276 default:
277 break;
278 }
279
280 physics()->composeStuntRot(m_rot);
281}
282
284void KartJumpBike::start(const EGG::Vector3f &left) {
285 KartJump::start(left);
286
287 KartMoveBike *moveBike = static_cast<KartMoveBike *>(m_move);
288 moveBike->cancelWheelie();
289}
290
292void KartJumpBike::init() {
293 constexpr f32 DOUBLE_FLIP_TRICK_FINAL_ANGLE = 180.0f;
294
295 if (m_variant == SurfaceVariant::DoubleFlipTrick) {
296 if (m_nextTrick < System::Trick::Left) {
297 return;
298 }
299
300 m_type = TrickType::BikeSideStuntTrick;
301 m_rotSign = (m_nextTrick == System::Trick::Right) ? -1.0f : 1.0f;
302 setupProperties();
303 m_finalAngle = DOUBLE_FLIP_TRICK_FINAL_ANGLE;
304 } else {
305 m_type = static_cast<TrickType>(m_nextTrick);
306 m_rotSign =
307 (m_type == TrickType::FlipTrickYRight || m_type == TrickType::BikeFlipTrickTail) ?
308 -1.0f :
309 1.0f;
310 setupProperties();
311 }
312
313 status().setBit(eStatus::TrickRot);
314}
315
316} // namespace Kart
A 3 x 4 matrix.
Definition Matrix.hh:8
void setAxisRotation(f32 angle, const Vector3f &axis)
Rotates the matrix about an axis.
Definition Matrix.cc:167
Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.
Definition Matrix.cc:224
Responsible for reacting to player inputs and moving the bike.
Definition KartMove.hh:448
virtual void cancelWheelie()
Clears the wheelie bit flag and resets the rotation decrement.
Definition KartMove.cc:2387
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:88
f32 length() const
The square root of the vector's dot product.
Definition Vector.hh:192