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 Kart {
13
15WheelPhysics::WheelPhysics(u16 wheelIdx, u16 bspWheelIdx)
16 : m_wheelIdx(wheelIdx), m_bspWheelIdx(bspWheelIdx), m_bspWheel(nullptr) {}
17
19WheelPhysics::~WheelPhysics() {
20 delete m_hitboxGroup;
21}
22
24void WheelPhysics::init() {
25 m_hitboxGroup = 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 -= collisionData().movement;
65 m_speed -= collide()->movement();
66 m_hitboxGroup->collisionData().vel += m_speed;
67 m_lastPos = m_pos;
68 m_lastPosDiff = m_pos - topmostPos;
69}
70
72void WheelPhysics::updateCollision(const EGG::Vector3f &bottom, const EGG::Vector3f &topmostPos) {
73 m_targetEffectiveRadius = m_bspWheel->wheelRadius;
74 auto &status = KartObjectProxy::status();
75
76 if (status.offBit(eStatus::SkipWheelCalc)) {
77 f32 nextRadius = m_bspWheel->sphereRadius;
78 f32 scalar = m_effectiveRadius * scale().y - nextRadius * move()->totalScale();
79
80 EGG::Vector3f center = m_pos + scalar * bottom;
81 scalar = 0.3f * (nextRadius * move()->leanRot()) * move()->totalScale();
82 center += scalar * bodyForward();
83
84 if (status.onBit(eStatus::HalfpipeMidair, eStatus::InCannon)) {
85 m_hitboxGroup->collisionData().reset();
86 } else {
87 m_hitboxGroup->setHitboxScale(move()->totalScale());
88 if (status.onBit(eStatus::UNK2)) {
89 m_hitboxGroup->hitbox(0).setLastPos(dynamics()->pos());
90 }
91
92 collide()->calcWheelCollision(m_wheelIdx, m_hitboxGroup, m_colVel, center, nextRadius);
93 CollisionData &colData = m_hitboxGroup->collisionData();
94
95 if (colData.bFloor || colData.bWall || colData.bWall3) {
96 m_pos += colData.tangentOff;
97 if (colData.intensity > -1) {
98 f32 sinkDepth = 3.0f * static_cast<f32>(colData.intensity);
99 m_targetEffectiveRadius = m_bspWheel->wheelRadius - sinkDepth;
100 body()->trySetTargetSinkDepth(sinkDepth);
101 }
102 }
103 }
104 m_hitboxGroup->hitbox(0).setLastPos(center);
105 }
106
107 m_topmostPos = topmostPos;
108 m_wheelEdgePos = m_pos + m_effectiveRadius * move()->totalScale() * bottom;
109 m_effectiveRadius += (m_targetEffectiveRadius - m_effectiveRadius) * 0.1f;
110 m_suspTravel = bottom.dot(m_pos - topmostPos);
111
112 if (m_suspTravel < 0.0f) {
113 m_74 = 1.0f;
114 EGG::Vector3f suspBottom = m_suspTravel * bottom;
115 sub()->updateSuspOvertravel(suspBottom);
116 } else {
117 m_74 = 0.0f;
118 }
119}
120
122void WheelPhysics::calcSuspension(const EGG::Vector3f &forward) {
123 f32 rate =
124 status().onBit(eStatus::SomethingWallCollision) ? 0.01f : collide()->floorMomentRate();
125
126 collide()->applySomeFloorMoment(0.1f, rate, m_hitboxGroup, forward, move()->dir(), 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
202void KartSuspensionPhysics::calcSuspension(const EGG::Vector3f &forward,
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 Kart
A 3 x 4 matrix.
Definition Matrix.hh:8
Vector3f multVector33(const Vector3f &vec) const
Multiplies a 3x3 matrix by a vector.
Definition Matrix.cc:236
void makeR(const Vector3f &r)
Sets 3x3 rotation matrix from a vector of Euler angles.
Definition Matrix.cc:98
Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.
Definition Matrix.cc:224
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:88
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:187
Vector3f proj(const Vector3f &rhs) const
The projection of this vector onto rhs.
Definition Vector.hh:198
Information about the current collision and its properties.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.