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 -= 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::UNK2)) {
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 =
125 status().onBit(eStatus::SomethingWallCollision) ? 0.01f : collide()->floorMomentRate();
126
127 collide()->applySomeFloorMoment(0.1f, rate, m_hitboxGroup, forward, move()->dir(), m_speed,
128 true, true, status().offBit(eStatus::LargeFlipHit, eStatus::WheelieRot));
129}
130
132KartSuspensionPhysics::KartSuspensionPhysics(u16 wheelIdx, TireType tireType, u16 bspWheelIdx)
133 : m_tirePhysics(nullptr), m_tireType(tireType), m_bspWheelIdx(bspWheelIdx),
134 m_wheelIdx(wheelIdx) {}
135
137KartSuspensionPhysics::~KartSuspensionPhysics() = default;
138
140void KartSuspensionPhysics::init() {
141 m_tirePhysics = tire(m_wheelIdx)->wheelPhysics();
142 m_bspWheel = &bsp().wheels[m_bspWheelIdx];
143}
144
146void KartSuspensionPhysics::reset() {
147 m_topmostPos.setZero();
148 m_maxTravelScaled = 0.0f;
149 m_bottomDir.setZero();
150}
151
153void KartSuspensionPhysics::setInitialState() {
154 EGG::Vector3f relPos = m_bspWheel->relPosition;
155 if (m_tireType == TireType::KartReflected) {
156 relPos.x = -relPos.x;
157 }
158
159 const EGG::Vector3f rotatedRelPos = dynamics()->fullRot().rotateVector(relPos) + pos();
160 const EGG::Vector3f unitRotated = dynamics()->fullRot().rotateVector(-EGG::Vector3f::ey);
161
162 m_tirePhysics->setPos(rotatedRelPos + m_bspWheel->maxTravel * unitRotated);
163 m_tirePhysics->setLastPos(rotatedRelPos + m_bspWheel->maxTravel * unitRotated);
164 m_tirePhysics->setLastPosDiff(m_tirePhysics->pos() - rotatedRelPos);
165 m_tirePhysics->setWheelEdgePos(m_tirePhysics->pos() +
166 (m_tirePhysics->effectiveRadius() * move()->totalScale() * unitRotated));
167 m_tirePhysics->hitboxGroup()->hitbox(0).setWorldPos(m_tirePhysics->pos());
168 m_tirePhysics->hitboxGroup()->hitbox(0).setLastPos(pos() + 100 * EGG::Vector3f::ey);
169 m_topmostPos = rotatedRelPos;
170}
171
173void KartSuspensionPhysics::calcCollision(f32 dt, const EGG::Vector3f &gravity,
174 const EGG::Matrix34f &mat) {
175 m_maxTravelScaled = m_bspWheel->maxTravel * sub()->someScale();
176
177 EGG::Vector3f scaledRelPos = m_bspWheel->relPosition * scale();
178 if (m_tireType == TireType::KartReflected) {
179 scaledRelPos.x = -scaledRelPos.x;
180 }
181
182 const EGG::Vector3f topmostPos = mat.ps_multVector(scaledRelPos);
183 EGG::Matrix34f mStack_60;
184 EGG::Vector3f euler_angles(m_bspWheel->xRot * DEG2RAD, 0.0f, 0.0f);
185 mStack_60.makeR(euler_angles);
186 EGG::Vector3f local_ac = mStack_60.multVector33(EGG::Vector3f(0.0f, -1.0f, 0.0f));
187 m_bottomDir = mat.multVector33(local_ac);
188
189 f32 y_down = m_tirePhysics->suspTravel() + 5.0f * sub()->someScale();
190 m_tirePhysics->setSuspTravel(std::max(0.0f, std::min(m_maxTravelScaled, y_down)));
191 m_tirePhysics->setColVel(dt * 10.0f * gravity);
192 m_tirePhysics->setPos(topmostPos + m_tirePhysics->suspTravel() * m_bottomDir);
193
194 if (status().offBit(eStatus::SkipWheelCalc)) {
195 m_tirePhysics->updateCollision(m_bottomDir, topmostPos);
196 m_topmostPos = topmostPos;
197 }
198}
199
203void KartSuspensionPhysics::calcSuspension(const EGG::Vector3f &forward,
204 const EGG::Vector3f &vehicleMovement) {
205 EGG::Vector3f lastPosDiff = m_tirePhysics->lastPosDiff();
206
207 m_tirePhysics->realign(m_bottomDir, vehicleMovement);
208
209 CollisionData &collisionData = m_tirePhysics->hitboxGroup()->collisionData();
210 if (!collisionData.bFloor) {
211 return;
212 }
213
214 EGG::Vector3f topDiff = m_tirePhysics->pos() - m_topmostPos;
215 f32 yDown = std::max(0.0f, m_bottomDir.dot(topDiff));
216 EGG::Vector3f speed = lastPosDiff - topDiff;
217 f32 travel = m_maxTravelScaled - yDown;
218 f32 speedScalar = m_bottomDir.dot(speed);
219
220 f32 springDamp =
221 -(m_bspWheel->springStiffness * travel + m_bspWheel->dampingFactor * speedScalar);
222
223 EGG::Vector3f fRot = m_bottomDir * springDamp;
224
225 if (isInRespawn()) {
226 fRot.y = std::max(-1.0f, std::min(1.0f, fRot.y));
227 }
228
229 EGG::Vector3f fLinear = fRot;
230 EGG::Vector3f rotProj = fRot;
231 rotProj.y = 0.0f;
232
233 rotProj = rotProj.proj(collisionData.floorNrm);
234 fLinear.y += rotProj.y;
235 fLinear.y = std::min(fLinear.y, param()->stats().maxNormalAcceleration);
236
237 auto &status = KartObjectProxy::status();
238
239 if (dynamics()->extVel().y > 5.0f || status.onBit(eStatus::JumpPadDisableYsusForce)) {
240 fLinear.y = 0.0f;
241 }
242
243 dynamics()->applySuspensionWrench(m_topmostPos, fLinear, fRot,
244 status.onBit(eStatus::WheelieRot));
245
246 m_tirePhysics->calcSuspension(forward);
247}
248
249} // 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:249
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:237
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:204
Information about the current collision and its properties.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.