3#include "game/kart/KartAction.hh"
4#include "game/kart/KartBody.hh"
5#include "game/kart/KartCollide.hh"
6#include "game/kart/KartMove.hh"
7#include "game/kart/KartObject.hh"
8#include "game/kart/KartState.hh"
9#include "game/kart/KartSuspensionPhysics.hh"
11#include "game/field/BoxColManager.hh"
12#include "game/field/CollisionDirector.hh"
14#include "game/system/RaceManager.hh"
16#include <egg/math/Math.hh>
20KartSub::KartSub() =
default;
31void KartSub::createSubsystems(
bool isBike) {
32 m_move = isBike ?
new KartMoveBike :
new KartMove;
33 m_action =
new KartAction;
34 m_move->createSubsystems();
35 m_state =
new KartState;
36 m_collide =
new KartCollide;
42 pointers.collide = m_collide;
43 pointers.state = m_state;
44 pointers.move = m_move;
45 pointers.action = m_action;
53 move()->setTurnParams();
59void KartSub::initAABB(KartAccessor &accessor, KartObject *
object) {
60 f32 radius = 25.0f + collide()->boundingRadius();
61 f32 hardSpeedLimit = move()->hardSpeedLimit();
63 accessor.boxColUnit = Field::BoxColManager::Instance()->insertDriver(radius, hardSpeedLimit,
64 &pos(),
true,
object);
68void KartSub::initPhysicsValues() {
70 collide()->resetHitboxes();
74void KartSub::resetPhysics() {
77 collide()->resetHitboxes();
79 for (
u16 wheelIdx = 0; wheelIdx < suspCount(); ++wheelIdx) {
80 suspensionPhysics(wheelIdx)->reset();
82 for (
u16 tireIdx = 0; tireIdx < tireCount(); ++tireIdx) {
83 tirePhysics(tireIdx)->reset();
85 m_move->setKartSpeedLimit();
91 m_maxSuspOvertravel.setZero();
92 m_minSuspOvertravel.setZero();
101 if (state()->isCannonStart()) {
102 physics()->hitboxGroup()->reset();
103 for (
size_t i = 0; i < tireCount(); ++i) {
104 tirePhysics(i)->hitboxGroup()->reset();
106 move()->enterCannon();
111 if (state()->isTriggerRespawn()) {
115 move()->setTurnParams();
116 move()->calcRespawnStart();
119 physics()->setPos(dynamics()->pos());
120 physics()->setVelocity(dynamics()->velocity());
121 dynamics()->setGravity(-1.3f);
122 dynamics()->setAngVel0YFactor(0.9f);
128 if (state()->isSkipWheelCalc()) {
129 for (
size_t tireIdx = 0; tireIdx < tireCount(); ++tireIdx) {
130 tirePhysics(tireIdx)->setLastPos(pos());
137 dynamics()->setTop(move()->up());
140 const auto *raceManager = System::RaceManager::Instance();
141 if (!raceManager->isStageReached(System::RaceManager::Stage::Race)) {
142 dynamics()->setIntVel(EGG::Vector3f::zero);
146 killExtVel = killExtVel.
rej(move()->smoothedUp());
152 dynamics()->setExtVel(killExtVel);
155 f32 maxSpeed = move()->hardSpeedLimit();
156 physics()->
calc(
DT, maxSpeed, scale(), !state()->isTouchingGround());
158 move()->calcRejectRoad();
160 if (!state()->isInCannon()) {
162 collisionGroup()->setHitboxScale(move()->totalScale());
172 constexpr s16 SIDE_COLLISION_TIME = 5;
176 m_movingObjCollisionCount = 0;
177 m_floorCollisionCount = 0;
179 m_maxSuspOvertravel.setZero();
180 m_minSuspOvertravel.setZero();
184 flags.
setBit(Field::eBoxColFlag::Drivable, Field::eBoxColFlag::Object);
185 boxColUnit()->search(flags);
187 collide()->calcObjectCollision();
188 dynamics()->setPos(pos() + collide()->tangentOff());
190 if (state()->isSomethingWallCollision()) {
191 const EGG::Vector3f &softWallSpeed = state()->softWallSpeed();
192 f32 speedFactor = 5.0f;
195 if (state()->isHWG()) {
197 effectiveSpeed = softWallSpeed;
199 effectiveSpeed = softWallSpeed.
perpInPlane(move()->smoothedUp(),
true);
200 f32 speedDotUp = softWallSpeed.
dot(move()->smoothedUp());
201 if (speedDotUp < 0.0f) {
202 speedFactor += -speedDotUp * 10.0f;
206 effectiveSpeed *= speedFactor * scale().y;
207 setPos(pos() + effectiveSpeed);
208 collide()->setMovement(collide()->movement() + effectiveSpeed);
211 auto &colData = collisionData();
215 if (colData.bWallAtLeftCloser || colData.bWallAtRightCloser) {
216 f32 sign = colData.bWallAtRightCloser ? 1.0f : -1.0f;
222 colPerpBounceDir.y = 0.0f;
223 setPos(pos() + colPerpBounceDir);
224 collide()->setMovement(collide()->movement() + colPerpBounceDir);
229 body()->calcSinkDepth();
231 Field::CollisionDirector::Instance()->checkCourseColNarrScLocal(250.0f, pos(),
234 if (!state()->isInCannon()) {
235 if (!state()->isZipperStick()) {
237 body()->calcTargetSinkDepth();
239 if (colData.bWall || colData.bWall3) {
240 collide()->setMovement(collide()->movement() + colData.movement);
246 collide()->calcFloorEffect();
247 collide()->calcFloorMomentRate();
249 if (colData.bFloor) {
251 addFloor(colData,
false);
256 m_someScale = scale().y;
259 f32 speedFactor = 1.0f;
260 f32 handlingFactor = 0.0f;
261 for (
u16 i = 0; i < suspCount(); ++i) {
263 suspensionPhysics(i)->calcCollision(
DT, gravity, wheelMatrix);
265 const CollisionData &colData = tirePhysics(i)->hitboxGroup()->collisionData();
267 speedFactor = std::min(speedFactor, colData.speedFactor);
270 handlingFactor += colData.rotFactor;
271 addFloor(colData,
false);
275 if (!state()->isSkipWheelCalc()) {
276 EGG::Vector3f vehicleCompensation = m_maxSuspOvertravel + m_minSuspOvertravel;
277 dynamics()->setPos(dynamics()->pos() + vehicleCompensation);
279 if (!collisionData().bFloor) {
285 for (
u16 wheelIdx = 0; wheelIdx < tireCount(); ++wheelIdx) {
286 const WheelPhysics *wheelPhysics = tirePhysics(wheelIdx);
287 if (wheelPhysics->_74() == 0.0f) {
291 const CollisionData &colData = wheelPhysics->hitboxGroup()->collisionData();
292 relPos += colData.relPos;
294 floorNrm += colData.floorNrm;
299 f32 scalar = (1.0f /
static_cast<f32
>(count));
302 collide()->setFloorColInfo(collisionData(), relPos * scalar, vel * scalar,
309 for (
u16 wheelIdx = 0; wheelIdx < suspCount(); ++wheelIdx) {
310 suspensionPhysics(wheelIdx)->
calcSuspension(forward, vehicleCompensation);
313 move()->calcHopPhysics();
316 move()->setKCLWheelSpeedFactor(speedFactor);
317 move()->setKCLWheelRotFactor(handlingFactor);
319 move()->setFloorCollisionCount(m_floorCollisionCount);
325 collide()->resetHitboxes();
331void KartSub::resizeAABB(f32 radiusScale) {
332 f32 radius = radiusScale * collisionGroup()->boundingRadius();
333 boxColUnit()->resize(radius + 25.0f, move()->hardSpeedLimit());
337void KartSub::addFloor(
const CollisionData &colData,
bool) {
338 ++m_floorCollisionCount;
340 if (colData.bHasRoadVel) {
341 ++m_movingObjCollisionCount;
342 m_objVel += colData.roadVelocity;
347void KartSub::updateSuspOvertravel(
const EGG::Vector3f &suspOvertravel) {
348 m_maxSuspOvertravel = m_maxSuspOvertravel.
minimize(suspOvertravel);
349 m_minSuspOvertravel = m_minSuspOvertravel.
maximize(suspOvertravel);
353void KartSub::tryEndHWG() {
354 if (state()->isSoftWallDrift()) {
355 if (EGG::Mathf::abs(move()->speed()) > 15.0f || state()->isAirtimeOver20() ||
356 state()->isAllWheelsCollision()) {
357 state()->setSoftWallDrift(
false);
358 }
else if (state()->isTouchingGround()) {
359 if (EGG::Mathf::abs(componentXAxis().dot(EGG::Vector3f::ey)) > 0.8f) {
360 state()->setSoftWallDrift(
false);
365 if (state()->isHWG() && !state()->isSomethingWallCollision()) {
366 if (!state()->isWallCollision() || state()->isAllWheelsCollision()) {
367 state()->setHWG(
false);
371 if (!state()->isInAction()) {
372 dynamics()->setForceUpright(!state()->isSoftWallDrift());
377void KartSub::calcMovingObj() {
378 if (m_movingObjCollisionCount == 0) {
379 f32 scalar = state()->airtime() < 20 ? 1.0f : 0.9f;
380 physics()->composeDecayingMovingObjVel(0.7f, scalar, m_floorCollisionCount != 0);
382 m_objVel *= 1.0f /
static_cast<f32
>(m_floorCollisionCount);
383 physics()->composeMovingObjVel(m_objVel, 0.2f);
#define KCL_TYPE_VEHICLE_INTERACTABLE
0xEFFFBDFF
virtual EGG::Matrix34f wheelMatrix(u16)
Computes a matrix to represent wheel rotation. For Karts, this is wheel-agnostic.
void calcHitboxes()
On each frame, calculates the positions for each hitbox.
void calc()
Each frame, calculates the kart's movement.
void updatePose()
Constructs a transformation matrix from rotation and position.
void calc(f32 dt, f32 maxSpeed, const EGG::Vector3f &scale, bool air)
Computes trick rotation and calls to KartDynamics::calc().
void calc()
Every frame, resets the input state and saves collision-related bit flags.
void calcInput()
Each frame, read input and save related bit flags. Also handles start boosts.
void resetEjection()
Resets certain bitfields pertaining to ejections (reject road, half pipe zippers, etc....
void calcPass0()
The first phase of physics computations on each frame.
static constexpr f32 DT
Delta time.
void copyPointers(KartAccessor &pointers)
Called during static construction of KartObject to synchronize the pointers.
f32 m_colPerpendicularity
Dot product between floor and colliding wall normals.
void calcPass1()
The second phase of physics computations on each frame.Handles the second-half of physics calculation...
s16 m_sideCollisionTimer
Number of frames to apply movement from wall collision.
void calcSuspension(const EGG::Vector3f &forward, const EGG::Vector3f &vehicleMovement)
Calculates linear force and rotation from the kart's suspension.
Manages wheel physics and collision checks.
Pertains to kart-related functionality.
Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
constexpr TBitFlag< T, E > & setBit(Es... es)
Sets the corresponding bits for the provided enum values.
f32 normalise()
Normalizes the vector and returns the original length.
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Vector3f perpInPlane(const EGG::Vector3f &rhs, bool normalise) const
Calculates the orthogonal vector, based on the plane defined by this vector and rhs.
Vector3f rej(const Vector3f &rhs) const
The rejection of this vector onto rhs.
Vector3f maximize(const Vector3f &rhs) const
Returns a vector whose elements are the max of the elements of both vectors.
Vector3f minimize(const Vector3f &rhs) const
Returns a vector whose elements are the min of the elements of both vectors.
Information about the current collision and its properties.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.
Shared between classes who inherit KartObjectProxy so they can access one another.