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 if (!state()->isSkipWheelCalc()) {
75 f32 nextRadius = m_bspWheel->sphereRadius;
76 f32 scalar = m_effectiveRadius * scale().y - nextRadius * move()->totalScale();
77
78 EGG::Vector3f center = m_pos + scalar * bottom;
79 scalar = 0.3f * (nextRadius * move()->leanRot()) * move()->totalScale();
80 center += scalar * bodyForward();
81
82 if (state()->isInCannon()) {
83 collisionData().reset();
84 } else {
85 m_hitboxGroup->setHitboxScale(move()->totalScale());
86 if (state()->isUNK2()) {
87 m_hitboxGroup->hitbox(0).setLastPos(dynamics()->pos());
88 }
89
90 collide()->calcWheelCollision(m_wheelIdx, m_hitboxGroup, m_colVel, center, nextRadius);
91 CollisionData &colData = m_hitboxGroup->collisionData();
92
93 if (colData.bFloor || colData.bWall || colData.bWall3) {
94 m_pos += colData.tangentOff;
95 if (colData.intensity > -1) {
96 f32 sinkDepth = 3.0f * static_cast<f32>(colData.intensity);
97 m_targetEffectiveRadius = m_bspWheel->wheelRadius - sinkDepth;
98 body()->trySetTargetSinkDepth(sinkDepth);
99 }
100 }
101 }
102 m_hitboxGroup->hitbox(0).setLastPos(center);
103 }
104
105 m_topmostPos = topmostPos;
106 m_wheelEdgePos = m_pos + m_effectiveRadius * move()->totalScale() * bottom;
107 m_effectiveRadius += (m_targetEffectiveRadius - m_effectiveRadius) * 0.1f;
108 m_suspTravel = bottom.dot(m_pos - topmostPos);
109
110 if (m_suspTravel < 0.0f) {
111 m_74 = 1.0f;
112 EGG::Vector3f suspBottom = m_suspTravel * bottom;
113 sub()->updateSuspOvertravel(suspBottom);
114 } else {
115 m_74 = 0.0f;
116 }
117}
118
120KartSuspensionPhysics::KartSuspensionPhysics(u16 wheelIdx, TireType tireType, u16 bspWheelIdx)
121 : m_tirePhysics(nullptr), m_tireType(tireType), m_bspWheelIdx(bspWheelIdx),
122 m_wheelIdx(wheelIdx) {}
123
125KartSuspensionPhysics::~KartSuspensionPhysics() = default;
126
128void KartSuspensionPhysics::init() {
129 m_tirePhysics = tire(m_wheelIdx)->wheelPhysics();
130 m_bspWheel = &bsp().wheels[m_bspWheelIdx];
131}
132
134void KartSuspensionPhysics::reset() {
135 m_topmostPos.setZero();
136 m_maxTravelScaled = 0.0f;
137 m_bottomDir.setZero();
138}
139
141void KartSuspensionPhysics::setInitialState() {
142 EGG::Vector3f relPos = m_bspWheel->relPosition;
143 if (m_tireType == TireType::KartReflected) {
144 relPos.x = -relPos.x;
145 }
146
147 const EGG::Vector3f rotatedRelPos = dynamics()->fullRot().rotateVector(relPos) + pos();
148 const EGG::Vector3f unitRotated = dynamics()->fullRot().rotateVector(-EGG::Vector3f::ey);
149
150 m_tirePhysics->setPos(rotatedRelPos + m_bspWheel->maxTravel * unitRotated);
151 m_tirePhysics->setLastPos(rotatedRelPos + m_bspWheel->maxTravel * unitRotated);
152 m_tirePhysics->setLastPosDiff(m_tirePhysics->pos() - rotatedRelPos);
153 m_tirePhysics->setWheelEdgePos(m_tirePhysics->pos() +
154 (m_tirePhysics->effectiveRadius() * move()->totalScale() * unitRotated));
155 m_tirePhysics->hitboxGroup()->hitbox(0).setWorldPos(m_tirePhysics->pos());
156 m_tirePhysics->hitboxGroup()->hitbox(0).setLastPos(pos() + 100 * EGG::Vector3f::ey);
157 m_topmostPos = rotatedRelPos;
158}
159
161void KartSuspensionPhysics::calcCollision(f32 dt, const EGG::Vector3f &gravity,
162 const EGG::Matrix34f &mat) {
163 m_maxTravelScaled = m_bspWheel->maxTravel * sub()->someScale();
164
165 EGG::Vector3f scaledRelPos = m_bspWheel->relPosition * scale();
166 if (m_tireType == TireType::KartReflected) {
167 scaledRelPos.x = -scaledRelPos.x;
168 }
169
170 const EGG::Vector3f topmostPos = mat.ps_multVector(scaledRelPos);
171 EGG::Matrix34f mStack_60;
172 EGG::Vector3f euler_angles(m_bspWheel->xRot * DEG2RAD, 0.0f, 0.0f);
173 mStack_60.makeR(euler_angles);
174 EGG::Vector3f local_ac = mStack_60.multVector33(EGG::Vector3f(0.0f, -1.0f, 0.0f));
175 m_bottomDir = mat.multVector33(local_ac);
176
177 f32 y_down = m_tirePhysics->suspTravel() + sub()->someScale() * 5.0f;
178 m_tirePhysics->setSuspTravel(std::max(0.0f, std::min(m_maxTravelScaled, y_down)));
179 m_tirePhysics->setColVel(dt * 10.0f * gravity);
180 m_tirePhysics->setPos(topmostPos + m_tirePhysics->suspTravel() * m_bottomDir);
181
182 if (!state()->isSkipWheelCalc()) {
183 m_tirePhysics->updateCollision(m_bottomDir, topmostPos);
184 m_topmostPos = topmostPos;
185 }
186}
187
191void KartSuspensionPhysics::calcSuspension(const EGG::Vector3f &forward,
192 const EGG::Vector3f &vehicleMovement) {
193 EGG::Vector3f lastPosDiff = m_tirePhysics->lastPosDiff();
194
195 m_tirePhysics->realign(m_bottomDir, vehicleMovement);
196
197 CollisionGroup *hitboxGroup = m_tirePhysics->hitboxGroup();
198 CollisionData &collisionData = hitboxGroup->collisionData();
199 if (!collisionData.bFloor) {
200 return;
201 }
202
203 EGG::Vector3f topDiff = m_tirePhysics->pos() - m_topmostPos;
204 f32 yDown = std::max(0.0f, m_bottomDir.dot(topDiff));
205 EGG::Vector3f speed = lastPosDiff - topDiff;
206 f32 travel = m_maxTravelScaled - yDown;
207 f32 speedScalar = m_bottomDir.dot(speed);
208
209 f32 springDamp =
210 -(m_bspWheel->springStiffness * travel + m_bspWheel->dampingFactor * speedScalar);
211
212 EGG::Vector3f fRot = m_bottomDir * springDamp;
213
214 if (isInRespawn()) {
215 fRot.y = std::max(-1.0f, std::min(1.0f, fRot.y));
216 }
217
218 EGG::Vector3f fLinear = fRot;
219 EGG::Vector3f rotProj = fRot;
220 rotProj.y = 0.0f;
221
222 rotProj = rotProj.proj(collisionData.floorNrm);
223 fLinear.y += rotProj.y;
224 fLinear.y = std::min(fLinear.y, param()->stats().maxNormalAcceleration);
225
226 if (dynamics()->extVel().y > 5.0f || state()->isJumpPadDisableYsusForce()) {
227 fLinear.y = 0.0f;
228 }
229
230 dynamics()->applySuspensionWrench(m_topmostPos, fLinear, fRot, state()->isWheelieRot());
231
232 f32 rate = state()->isSomethingWallCollision() ? 0.01f : collide()->floorMomentRate();
233
234 collide()->applySomeFloorMoment(0.1f, rate, hitboxGroup, forward, move()->dir(),
235 m_tirePhysics->speed(), true, true, !state()->isWheelieRot());
236}
237
238} // 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:243
void makeR(const Vector3f &r)
Sets 3x3 rotation matrix from a vector of Euler angles.
Definition Matrix.cc:122
Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.
Definition Matrix.cc:232
Houses hitbox and collision info for an object (body or wheel).
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:83
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:182
Vector3f proj(const Vector3f &rhs) const
The projection of this vector onto rhs.
Definition Vector.hh:193
Information about the current collision and its properties.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.