A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartState.cc
Go to the documentation of this file.
1#include "KartState.hh"
2
8
10
11namespace Kinoko::Kart {
12
17
20static constexpr std::array<StartBoostEntry, 6> START_BOOST_ENTRIES = {{
21 {0.85f, 0},
22 {0.88f, 10},
23 {0.905f, 20},
24 {0.925f, 30},
25 {0.94f, 45},
26 {0.95f, 70},
27}};
28
39
42 reset();
43}
44
47 // In the base game, we only wipe bitfield 0, 1, 2, and 3, so we need to bring back bitfield4.
48 bool isAutoDrift = m_status.onBit(eStatus::AutoDrift);
49 m_status.makeAllZero().changeBit(isAutoDrift, eStatus::AutoDrift);
50
51 m_airtime = 0;
52 m_top.setZero();
53 m_hwgTimer = 0;
54 m_boostRampType = -1;
57 m_startBoostCharge = 0.0f;
58 m_stickX = 0.0f;
61}
62
67 const auto *raceMgr = System::RaceManager::Instance();
68 if (raceMgr->isStageReached(System::RaceManager::Stage::Race)) {
71 const auto &currentState = inputs()->currentState();
72 const auto &lastState = inputs()->lastState();
73 m_stickX = currentState.stick.x;
74 m_stickY = currentState.stick.y;
75
77 if (m_stickX < 0.0f) {
79 } else if (m_stickX > 0.0f) {
81 }
82 }
83
85 m_status.changeBit(currentState.accelerate(), eStatus::Accelerate)
86 .changeBit(currentState.accelerate() && !lastState.accelerate(),
88 .changeBit(currentState.brake(), eStatus::Brake);
89
91 m_status.changeBit(currentState.drift(), eStatus::DriftInput)
92 .changeBit(currentState.drift() && !lastState.drift(),
94 }
95 }
96 }
97
99 } else {
100 if (!raceMgr->isStageReached(System::RaceManager::Stage::Countdown)) {
101 return;
102 }
103
104 const auto &currentState = inputs()->currentState();
105 m_stickX = currentState.stick.x;
106 m_status.changeBit(currentState.accelerate(), eStatus::ChargeStartBoost);
107
109 }
110}
111
116 resetFlags();
117
119
122}
123
135
144 bool wasTouchingGround = m_status.onBit(eStatus::TouchingGround);
146
150
151 if (m_hwgTimer > 0) {
152 if (--m_hwgTimer == 0) {
154 }
155 }
156
157 m_top.setZero();
158 bool softWallCollision = false;
159
160 if (collide()->numSoftWallCollisions() > 0) {
161 if (collide()->numFloorOnlyCollisions() == 0) {
162 softWallCollision = true;
163 } else {
164 f32 avgSoftWallColHeight = collide()->sumHitboxBottomHeightSoftWall() /
165 static_cast<f32>(collide()->numSoftWallCollisions());
166 f32 avgFloorOnlyColHeight = collide()->sumHitboxBottomHeightFloorOnly() /
167 static_cast<f32>(collide()->numFloorOnlyCollisions());
168
169 if (avgSoftWallColHeight - avgFloorOnlyColHeight >= 40.0f) {
171 } else {
172 softWallCollision = true;
173 }
174 }
175 }
176
177 u16 wheelCollisions = 0;
178 u16 effectiveSoftWallCount = 0;
180 bool trickable = false;
181
182 for (u16 tireIdx = 0; tireIdx < tireCount(); ++tireIdx) {
183 const auto &colData = collisionData(tireIdx);
184 if (hasFloorCollision(tirePhysics(tireIdx))) {
185 m_top += colData.floorNrm;
186 trickable = trickable || colData.bTrickable;
187 ++wheelCollisions;
188 }
189
190 if (softWallCollision && colData.bSoftWall) {
191 ++effectiveSoftWallCount;
192 wallNrm += colData.noBounceWallNrm;
193 }
194 }
195
196 if (wheelCollisions > 0) {
198 if (wheelCollisions == tireCount()) {
200 }
201 }
202
203 CollisionData &colData = collisionData();
204 if (colData.bFloor) {
206 m_top += colData.floorNrm;
207 trickable = trickable || colData.bTrickable;
208
210 halfPipe()->end(true);
211 }
212 }
213
214 bool bodySoftWallCollision = false;
215 if (softWallCollision && colData.bSoftWall) {
216 bodySoftWallCollision = true;
217 ++effectiveSoftWallCount;
218 wallNrm += colData.wallNrm;
219 }
220
221 bool bVar3 = colData.bInvisibleWallOnly && m_halfPipeInvisibilityTimer > 0;
223
224 m_wallBonkTimer = std::max(0, m_wallBonkTimer - 1);
225
226 bool hwg = false;
227
228 if ((colData.bWall || colData.bWall3) && !bVar3) {
229 if (colData.bWall) {
231 }
232
233 if (colData.bWall3) {
235 }
236
237 if (!wasWallCollision) {
239
245 }
246 }
247 }
248
249 m_wallBonkTimer = 2;
250
251 if (m_hwgTimer == 0 && colData.movement.y > 1.0f) {
252 EGG::Vector3f movement = colData.movement;
253 movement.normalise();
254
255 if (movement.dot(EGG::Vector3f::ey) > 0.8f &&
256 colData.wallNrm.dot(EGG::Vector3f::ey) > 0.85f &&
257 (movement.x * colData.wallNrm.x + movement.z * colData.wallNrm.z < 0.0f ||
258 collide()->colPerpendicularity() >= 1.0f)) {
259 colData.wallNrm.y = 0.0f;
260 colData.wallNrm.normalise();
261 wallNrm = colData.wallNrm;
262
263 if (wallNrm.length() < 0.05f) {
264 wallNrm = movement;
265 wallNrm.y = 0.0f;
266 }
267
268 hwg = true;
269 }
270 }
271 }
272
274 collide()->surfaceFlags().offBit(KartCollide::eSurfaceFlags::StopHalfPipeState)) {
276 }
277
278 if (effectiveSoftWallCount > 0 || hwg) {
280 m_softWallSpeed = wallNrm;
282 if (effectiveSoftWallCount > 0 && m_status.offBit(eStatus::Hop)) {
284 }
285
286 if (hwg) {
288 }
289
290 if (bodySoftWallCollision || hwg || isBike()) {
292 m_hwgTimer = 10;
293
294 if (hwg) {
295 m_hwgTimer *= 2;
296 }
297 }
298 }
299
301 m_trickableTimer = std::max(0, m_trickableTimer - 1);
302
303 if (wheelCollisions < 1 && !colData.bFloor) {
304 if (wasTouchingGround) {
306 }
307
308 if (++m_airtime > 20) {
310 }
311 } else {
313
315
318 }
319
321 halfPipe()->end(true);
322 }
323
324 if (trickable) {
326 }
327
329
332 }
333
334 if (!wasTouchingGround) {
336 }
337
338 if (m_status.onBit(eStatus::InATrick) && jump()->cooldown() == 0) {
339 move()->landTrick();
340 dynamics()->setForceUpright(true);
341 jump()->end();
342 }
343
344 m_airtime = 0;
345 }
346}
347
353 constexpr f32 START_BOOST_DELTA_ONE = 0.02f;
354 constexpr f32 START_BOOST_DELTA_TWO = 0.002f;
355 constexpr f32 START_BOOST_FALLOFF = 0.96f;
356
358 m_startBoostCharge += START_BOOST_DELTA_ONE -
359 (START_BOOST_DELTA_ONE - START_BOOST_DELTA_TWO) * m_startBoostCharge;
360 } else {
361 m_startBoostCharge *= START_BOOST_FALLOFF;
362 }
363
364 m_startBoostCharge = std::clamp(m_startBoostCharge, 0.0f, 1.0f);
365}
366
371 if (System::RaceManager::Instance()->getCountdownTimer() != 0) {
372 return;
373 }
374
376 if (m_startBoostCharge > START_BOOST_ENTRIES.back().range) {
377 m_startBoostIdx = std::numeric_limits<size_t>::max();
378 } else if (m_startBoostCharge > START_BOOST_ENTRIES.front().range) {
379 // Ranges are exclusive on the lower bound and inclusive on the upper bound
380 for (size_t i = 1; i < START_BOOST_ENTRIES.size(); ++i) {
381 if (m_startBoostCharge > START_BOOST_ENTRIES[i - 1].range &&
383 m_startBoostIdx = i;
384 break;
385 }
386 }
387 }
388 }
389
390 if (m_startBoostIdx <= 0) {
391 return;
392 }
393
396}
397
402 if (m_startBoostIdx == std::numeric_limits<size_t>::max()) {
403 move()->burnout().start();
404 } else {
406 }
407}
408
414
415} // namespace Kinoko::Kart
@ COL_TYPE_SPECIAL_WALL
Various other wall types, determined by variant.
constexpr TBitFlagExt< N, E > & changeBit(bool on, Es... es)
Changes the state of the corresponding bits for the provided enum values.
Definition BitFlag.hh:379
constexpr bool offBit(Es... es) const
Checks if all of the corresponding bits for the provided enum values are off.
Definition BitFlag.hh:424
constexpr bool onBit(Es... es) const
Checks if any of the corresponding bits for the provided enum values are on.
Definition BitFlag.hh:391
constexpr TBitFlagExt< N, E > & makeAllZero()
Resets all the bits to zero across the entire bitfield array.
Definition BitFlag.hh:344
constexpr TBitFlagExt< N, E > & resetBit(Es... es)
Resets the corresponding bits for the provided enum values.
Definition BitFlag.hh:367
constexpr TBitFlagExt< N, E > & setBit(Es... es)
Sets the corresponding bits for the provided enum values.
Definition BitFlag.hh:356
bool start(Action action)
Starts an action.
Definition KartAction.cc:49
f32 sumHitboxBottomHeightSoftWall() const
u16 numSoftWallCollisions() const
f32 sumHitboxBottomHeightFloorOnly() const
u16 numFloorOnlyCollisions() const
void setForceUpright(bool isSet)
KartBurnout & burnout()
Definition KartMove.hh:347
void applyStartBoost(s16 frames)
Definition KartMove.cc:2125
Field::KCLTypeMask wallKclType() const
bool hasFloorCollision(const WheelPhysics *wheelPhysics) const
WheelPhysics * tirePhysics(u16 tireIdx)
const System::KPad * inputs() const
f32 m_startBoostCharge
0-1 representation of start boost charge. Burnout if >0.95f.
Definition KartState.hh:122
f32 m_stickY
One of 15 discrete stick values from [-1.0, 1.0].
Definition KartState.hh:121
void calc()
Every frame, resets the input state and saves collision-related bit flags.
Definition KartState.cc:115
void resetEjection()
Resets certain bitfields pertaining to ejections (reject road, half pipe zippers, etc....
Definition KartState.cc:411
size_t m_startBoostIdx
Used to map m_startBoostCharge to a start boost duration.
Definition KartState.hh:123
EGG::Vector3f m_softWallSpeed
Definition KartState.hh:114
void handleStartBoost(size_t idx)
Applies the relevant start boost duration.
Definition KartState.cc:401
void calcStartBoost()
STAGE 1 - Each frame, calculates the start boost charge.
Definition KartState.cc:352
void calcInput()
Each frame, read input and save related bit flags. Also handles start boosts.
Definition KartState.cc:66
void calcHandleStartBoost()
On countdown end, calculates and applies our start boost charge.
Definition KartState.cc:370
s16 m_wallBonkTimer
2f counter that stunts your speed after hitting a wall.
Definition KartState.hh:124
static constexpr std::array< StartBoostEntry, 6 > START_BOOST_ENTRIES
Definition KartState.cc:20
void calcCollisions()
Each frame, checks for collision and saves relevant bit flags.
Definition KartState.cc:143
f32 m_stickX
One of 15 discrete stick values from [-1.0, 1.0].
Definition KartState.hh:120
const RaceInputState & currentState() const
const RaceInputState & lastState() const
static RaceManager * Instance()
Pertains to kart-related functionality.
@ HopStart
Set if m_bDriftInput was toggled on this frame.
Definition Status.hh:20
@ RejectRoad
Collision which causes a change in the player's pos and rot.
Definition Status.hh:64
@ HalfPipeRamp
Set while colliding with zipper KCL.
Definition Status.hh:51
@ SoftWallPush
Tracks whether we are being pushed by a soft wall or HWG.
Definition Status.hh:84
@ HWG
Set when "Horizontal Wall Glitch" is active.
Definition Status.hh:86
@ SoftWallSuspension
Changes wheel physics after touching a soft wall.
Definition Status.hh:83
@ Hop
Set while we are in a drift hop. Clears when we land.
Definition Status.hh:31
@ SoftWallUnlockRotation
Set when we are in "Barrel Roll" state.
Definition Status.hh:85
@ StickLeft
Set on left stick input. Mutually exclusive to m_bStickRight.
Definition Status.hh:26
@ VehicleBodyFloorCollision
Set if the vehicle body is colliding with the floor.
Definition Status.hh:23
@ ChargeStartBoost
Like m_bAccelerate but during countdown.
Definition Status.hh:89
@ RejectRoadTrigger
e.g. DK Summit ending, and Maple Treeway side walls.
Definition Status.hh:65
@ GroundStart
Set first frame landing from airtime.
Definition Status.hh:22
@ AllWheelsCollision
Set when all wheels are touching floor collision.
Definition Status.hh:25
@ Accelerate
Accel button is pressed.
Definition Status.hh:9
@ StickRight
Set on right stick input. Mutually exclusive to m_bStickLeft.
Definition Status.hh:35
@ ActionMidZipper
Set when we enter an action while mid-air from a zipper.
Definition Status.hh:88
@ DriftInput
A "fake" button, normally set if you meet the speed requirement to hop.
Definition Status.hh:15
@ AirtimeOver20
Set after 20 frames of airtime, resets on landing.
Definition Status.hh:28
@ OverZipper
Set while mid-air from a zipper.
Definition Status.hh:52
@ AccelerateStart
Set if m_bAccelerate was toggled on this frame.
Definition Status.hh:21
@ Burnout
Set during a burnout on race start.
Definition Status.hh:60
@ WallCollisionStart
Set if we have just started colliding with a wall.
Definition Status.hh:27
@ AnyWheelCollision
Set when any wheel is touching floor collision.
Definition Status.hh:24
@ AutoDrift
True if auto transmission, false if manual.
Definition Status.hh:93
@ Wall3Collision
Set when colliding with wall KCL COL_TYPE_WALL_2.
Definition Status.hh:18
@ TouchingGround
Set when any part of the vehicle is colliding with floor KCL.
Definition Status.hh:30
@ ZipperInvisibleWall
Set when colliding with invisible wall above a zipper.
Definition Status.hh:54
@ BeforeRespawn
Set on respawn collision, cleared on position snap.
Definition Status.hh:17
@ WallCollision
Set if we are colliding with a wall.
Definition Status.hh:19
float f32
Definition Memory.hh:21
int16_t s16
Definition Memory.hh:12
uint16_t u16
Definition Memory.hh:17
A 3D float vector.
Definition Vector.hh:107
static const Vector3f zero
Definition Vector.hh:375
static const Vector3f ey
Definition Vector.hh:377
constexpr f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:206
constexpr f32 length() const
The square root of the vector's dot product.
Definition Vector.hh:211
constexpr f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.hh:278
constexpr void setZero()
Definition Vector.hh:121
Information about the current collision and its properties.
bool bWall3
Set if colliding with COL_TYPE_WALL_2.
bool bWall
Set if colliding with KCL which satisfies KCL_TYPE_WALL.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.