A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartSuspensionPhysics.cc
1#include "KartSuspensionPhysics.hh"
2
3#include "game/kart/KartBody.hh"
4#include "game/kart/KartCollide.hh"
5#include "game/kart/KartDynamics.hh"
6#include "game/kart/KartState.hh"
7#include "game/kart/KartSub.hh"
8#include "game/kart/KartTire.hh"
9
10#include <egg/math/Math.hh>
11
12namespace Kinoko::Kart {
13
15WheelPhysics::WheelPhysics(u16 wheelIdx, u16 bspWheelIdx)
16 : m_wheelIdx(wheelIdx), m_bspWheelIdx(bspWheelIdx), m_bspWheel(nullptr) {}
17
19WheelPhysics::~WheelPhysics() {
20 EGG::egg_delete(m_hitboxGroup);
21}
22
24void WheelPhysics::init() {
25 m_hitboxGroup = EGG::egg_new<CollisionGroup>();
26 m_hitboxGroup->createSingleHitbox(10.0f, EGG::Vector3f::zero);
27}
28
30void WheelPhysics::initBsp() {
31 m_bspWheel = &bsp().wheels[m_bspWheelIdx];
32}
33
35void WheelPhysics::reset() {
36 m_pos.setZero();
37 m_lastPos.setZero();
38 m_lastPosDiff.setZero();
39 m_suspTravel = 0.0f;
40 m_colVel.setZero();
41 m_speed.setZero();
42 m_wheelEdgePos.setZero();
43 m_effectiveRadius = 0.0f;
44 m_targetEffectiveRadius = 0.0f;
45 m_74 = 0.0f;
46 m_topmostPos.setZero();
47
48 if (m_bspWheel) {
49 m_suspTravel = m_bspWheel->maxTravel;
50 m_effectiveRadius = m_bspWheel->wheelRadius;
51 }
52}
53
55void WheelPhysics::realign(const EGG::Vector3f &bottom, const EGG::Vector3f &vehicleMovement) {
56 const EGG::Vector3f topmostPos = m_topmostPos + vehicleMovement;
57 f32 scaledMaxTravel = m_bspWheel->maxTravel * sub()->someScale();
58 f32 suspTravel = bottom.dot(m_pos - topmostPos);
59 m_suspTravel = std::max(0.0f, std::min(scaledMaxTravel, suspTravel));
60 m_pos = topmostPos + m_suspTravel * bottom;
61 m_speed = m_pos - m_lastPos;
62 m_speed -= dynamics()->intVel();
63 m_speed -= dynamics()->movingObjVel();
64 m_speed -= dynamics()->movingRoadVel();
65 m_speed -= collisionData().movement;
66 m_speed -= collide()->movement();
67 m_hitboxGroup->collisionData().vel += m_speed;
68 m_lastPos = m_pos;
69 m_lastPosDiff = m_pos - topmostPos;
70}
71
73void WheelPhysics::updateCollision(const EGG::Vector3f &bottom, const EGG::Vector3f &topmostPos) {
74 m_targetEffectiveRadius = m_bspWheel->wheelRadius;
75 auto &status = KartObjectProxy::status();
76
77 if (status.offBit(eStatus::SkipWheelCalc)) {
78 f32 nextRadius = m_bspWheel->sphereRadius;
79 f32 scalar = m_effectiveRadius * scale().y - nextRadius * move()->totalScale();
80
81 EGG::Vector3f center = m_pos + scalar * bottom;
82 scalar = 0.3f * (nextRadius * move()->leanRot()) * move()->totalScale();
83 center += scalar * bodyForward();
84
85 if (status.onBit(eStatus::HalfpipeMidair, eStatus::InCannon)) {
86 m_hitboxGroup->collisionData().reset();
87 } else {
88 m_hitboxGroup->setHitboxScale(move()->totalScale());
89 if (status.onBit(eStatus::SoftWallSuspension)) {
90 m_hitboxGroup->hitbox(0).setLastPos(dynamics()->pos());
91 }
92
93 collide()->calcWheelCollision(m_wheelIdx, m_hitboxGroup, m_colVel, center, nextRadius);
94 CollisionData &colData = m_hitboxGroup->collisionData();
95
96 if (colData.bFloor || colData.bWall || colData.bWall3) {
97 m_pos += colData.tangentOff;
98 if (colData.intensity > -1) {
99 f32 sinkDepth = 3.0f * static_cast<f32>(colData.intensity);
100 m_targetEffectiveRadius = m_bspWheel->wheelRadius - sinkDepth;
101 body()->trySetTargetSinkDepth(sinkDepth);
102 }
103 }
104 }
105 m_hitboxGroup->hitbox(0).setLastPos(center);
106 }
107
108 m_topmostPos = topmostPos;
109 m_wheelEdgePos = m_pos + m_effectiveRadius * move()->totalScale() * bottom;
110 m_effectiveRadius += (m_targetEffectiveRadius - m_effectiveRadius) * 0.1f;
111 m_suspTravel = bottom.dot(m_pos - topmostPos);
112
113 if (m_suspTravel < 0.0f) {
114 m_74 = 1.0f;
115 EGG::Vector3f suspBottom = m_suspTravel * bottom;
116 sub()->updateSuspOvertravel(suspBottom);
117 } else {
118 m_74 = 0.0f;
119 }
120}
121
123void WheelPhysics::calcSuspension(const EGG::Vector3f &forward) {
124 f32 rate = status().onBit(eStatus::SoftWallPush) ? 0.01f : collide()->floorMomentRate();
125
126 collide()->applySomeFloorMoment(0.1f, rate, m_hitboxGroup, forward, move()->dir(), m_speed,
127 true, true, status().offBit(eStatus::LargeFlipHit, eStatus::WheelieRot));
128}
129
131KartSuspensionPhysics::KartSuspensionPhysics(u16 wheelIdx, TireType tireType, u16 bspWheelIdx)
132 : m_tirePhysics(nullptr), m_tireType(tireType), m_bspWheelIdx(bspWheelIdx),
133 m_wheelIdx(wheelIdx) {}
134
136KartSuspensionPhysics::~KartSuspensionPhysics() = default;
137
139void KartSuspensionPhysics::init() {
140 m_tirePhysics = tire(m_wheelIdx)->wheelPhysics();
141 m_bspWheel = &bsp().wheels[m_bspWheelIdx];
142}
143
145void KartSuspensionPhysics::reset() {
146 m_topmostPos.setZero();
147 m_maxTravelScaled = 0.0f;
148 m_bottomDir.setZero();
149}
150
152void KartSuspensionPhysics::setInitialState() {
153 EGG::Vector3f relPos = m_bspWheel->relPosition;
154 if (m_tireType == TireType::KartReflected) {
155 relPos.x = -relPos.x;
156 }
157
158 const EGG::Vector3f rotatedRelPos = dynamics()->fullRot().rotateVector(relPos) + pos();
159 const EGG::Vector3f unitRotated = dynamics()->fullRot().rotateVector(-EGG::Vector3f::ey);
160
161 m_tirePhysics->setPos(rotatedRelPos + m_bspWheel->maxTravel * unitRotated);
162 m_tirePhysics->setLastPos(rotatedRelPos + m_bspWheel->maxTravel * unitRotated);
163 m_tirePhysics->setLastPosDiff(m_tirePhysics->pos() - rotatedRelPos);
164 m_tirePhysics->setWheelEdgePos(m_tirePhysics->pos() +
165 (m_tirePhysics->effectiveRadius() * move()->totalScale() * unitRotated));
166 m_tirePhysics->hitboxGroup()->hitbox(0).setWorldPos(m_tirePhysics->pos());
167 m_tirePhysics->hitboxGroup()->hitbox(0).setLastPos(pos() + 100 * EGG::Vector3f::ey);
168 m_topmostPos = rotatedRelPos;
169}
170
172void KartSuspensionPhysics::calcCollision(f32 dt, const EGG::Vector3f &gravity,
173 const EGG::Matrix34f &mat) {
174 m_maxTravelScaled = m_bspWheel->maxTravel * sub()->someScale();
175
176 EGG::Vector3f scaledRelPos = m_bspWheel->relPosition * scale();
177 if (m_tireType == TireType::KartReflected) {
178 scaledRelPos.x = -scaledRelPos.x;
179 }
180
181 const EGG::Vector3f topmostPos = mat.ps_multVector(scaledRelPos);
182 EGG::Matrix34f mStack_60;
183 EGG::Vector3f euler_angles(m_bspWheel->xRot * DEG2RAD, 0.0f, 0.0f);
184 mStack_60.makeR(euler_angles);
185 EGG::Vector3f local_ac = mStack_60.multVector33(EGG::Vector3f(0.0f, -1.0f, 0.0f));
186 m_bottomDir = mat.multVector33(local_ac);
187
188 f32 y_down = m_tirePhysics->suspTravel() + 5.0f * sub()->someScale();
189 m_tirePhysics->setSuspTravel(std::max(0.0f, std::min(m_maxTravelScaled, y_down)));
190 m_tirePhysics->setColVel(dt * 10.0f * gravity);
191 m_tirePhysics->setPos(topmostPos + m_tirePhysics->suspTravel() * m_bottomDir);
192
193 if (status().offBit(eStatus::SkipWheelCalc)) {
194 m_tirePhysics->updateCollision(m_bottomDir, topmostPos);
195 m_topmostPos = topmostPos;
196 }
197}
198
203 const EGG::Vector3f &vehicleMovement) {
204 EGG::Vector3f lastPosDiff = m_tirePhysics->lastPosDiff();
205
206 m_tirePhysics->realign(m_bottomDir, vehicleMovement);
207
208 CollisionData &collisionData = m_tirePhysics->hitboxGroup()->collisionData();
209 if (!collisionData.bFloor) {
210 return;
211 }
212
213 EGG::Vector3f topDiff = m_tirePhysics->pos() - m_topmostPos;
214 f32 yDown = std::max(0.0f, m_bottomDir.dot(topDiff));
215 EGG::Vector3f speed = lastPosDiff - topDiff;
216 f32 travel = m_maxTravelScaled - yDown;
217 f32 speedScalar = m_bottomDir.dot(speed);
218
219 f32 springDamp =
220 -(m_bspWheel->springStiffness * travel + m_bspWheel->dampingFactor * speedScalar);
221
222 EGG::Vector3f fRot = m_bottomDir * springDamp;
223
224 if (isInRespawn()) {
225 fRot.y = std::max(-1.0f, std::min(1.0f, fRot.y));
226 }
227
228 EGG::Vector3f fLinear = fRot;
229 EGG::Vector3f rotProj = fRot;
230 rotProj.y = 0.0f;
231
232 rotProj = rotProj.proj(collisionData.floorNrm);
233 fLinear.y += rotProj.y;
234 fLinear.y = std::min(fLinear.y, param()->stats().maxNormalAcceleration);
235
236 auto &status = KartObjectProxy::status();
237
238 if (dynamics()->extVel().y > 5.0f || status.onBit(eStatus::JumpPadDisableYsusForce)) {
239 fLinear.y = 0.0f;
240 }
241
242 dynamics()->applySuspensionWrench(m_topmostPos, fLinear, fRot,
243 status.onBit(eStatus::WheelieRot));
244
245 m_tirePhysics->calcSuspension(forward);
246}
247
248} // namespace Kinoko::Kart
void calcSuspension(const EGG::Vector3f &forward, const EGG::Vector3f &vehicleMovement)
Calculates linear force and rotation from the kart's suspension.
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:107
constexpr Vector3f proj(const Vector3f &rhs) const
The projection of this vector onto rhs.
Definition Vector.hh:223
Information about the current collision and its properties.