A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectVolcanoPiece.cc
1#include "game/field/obj/ObjectVolcanoPiece.hh"
2
3#include "game/system/RaceManager.hh"
4
5namespace Field {
6
8ObjectVolcanoPiece::ObjectVolcanoPiece(const System::MapdataGeoObj &params)
9 : ObjectKCL(params), m_initialPos(m_pos), m_initialRot(m_rot),
10 m_restDuration(params.setting(1) * 60),
11 m_shakeDuration(m_restDuration + params.setting(2) * 60),
12 m_quakeDuration(m_shakeDuration + params.setting(7) + 1), m_colMgrB(nullptr),
13 m_colMgrC(nullptr) {
14 snprintf(m_modelName, sizeof(m_modelName), "VolcanoPiece%hd",
15 static_cast<s16>(params.setting(0)));
16}
17
19ObjectVolcanoPiece::~ObjectVolcanoPiece() {
20 delete m_colMgrB;
21 delete m_colMgrC;
22}
23
25void ObjectVolcanoPiece::calc() {
26 u32 timer = System::RaceManager::Instance()->timer();
27 if (calcState(timer) == State::Fall && FALL_DURATION - 1 == calcT(timer)) {
28 update(0);
29 }
30
31 m_flags.setBit(eFlags::Matrix);
32 EGG::Vector3f movingObjVel;
33 m_transform = calcShakeAndFall(&movingObjVel, 0);
34 m_pos = m_transform.base(3);
35 setMovingObjVel(movingObjVel);
36}
37
39void ObjectVolcanoPiece::createCollision() {
40 ObjectKCL::createCollision();
41
42 char filepath[128];
43 snprintf(filepath, sizeof(filepath), "%sb.kcl", getKclName());
44 auto *file = System::ResourceManager::Instance()->getFile(filepath, nullptr,
45 System::ArchiveId::Course);
46
47 if (file) {
48 m_colMgrB = new ObjColMgr(file);
49 }
50
51 snprintf(filepath, sizeof(filepath), "%sc.kcl", getKclName());
52 file = System::ResourceManager::Instance()->getFile(filepath, nullptr,
53 System::ArchiveId::Course);
54
55 if (file) {
56 m_colMgrC = new ObjColMgr(file);
57 }
58
59 EGG::Matrix34f rtMat;
60 EGG::Matrix34f invMat;
61 rtMat.makeRT(m_initialRot, m_initialPos);
62 rtMat.ps_inverse(invMat);
63
64 m_objColMgr->setMtx(rtMat);
65 m_objColMgr->setInvMtx(invMat);
66 m_objColMgr->setScale(m_scale.y);
67
68 if (m_colMgrB) {
69 m_colMgrB->setMtx(rtMat);
70 m_colMgrB->setInvMtx(invMat);
71 m_colMgrB->setScale(m_scale.y);
72 }
73
74 if (m_colMgrC) {
75 m_colMgrC->setMtx(rtMat);
76 m_colMgrC->setInvMtx(invMat);
77 m_colMgrC->setScale(m_scale.y);
78 }
79}
80
81template <typename T, typename U>
82 requires(std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>) &&
83 (std::is_same_v<U, ObjectVolcanoPiece::CheckPointPartialFunc> ||
84 std::is_same_v<U, ObjectVolcanoPiece::CheckPointFullFunc>)
85bool ObjectVolcanoPiece::checkPointImpl(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
86 KCLTypeMask flags, T *pInfo, KCLTypeMask *pFlagsOut, U checkFunc) {
87 State state = calcState(System::RaceManager::Instance()->timer());
88 bool hasCol = (m_objColMgr->*checkFunc)(v0, v1, flags, pInfo, pFlagsOut);
89
90 if (state == State::Rest || hasCol) {
91 return hasCol;
92 }
93
94 hasCol = m_colMgrB && (m_colMgrB->*checkFunc)(v0, v1, flags, pInfo, pFlagsOut);
95 hasCol = hasCol || (m_colMgrC && (m_colMgrC->*checkFunc)(v0, v1, flags, pInfo, pFlagsOut));
96
97 return hasCol;
98}
99
100template <typename T, typename U>
101 requires(std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>) &&
102 (std::is_same_v<U, ObjectVolcanoPiece::CheckSpherePartialFunc> ||
103 std::is_same_v<U, ObjectVolcanoPiece::CheckSphereFullFunc>)
104bool ObjectVolcanoPiece::checkSphereImpl(f32 radius, const EGG::Vector3f &v0,
105 const EGG::Vector3f &v1, KCLTypeMask flags, T *pInfo, KCLTypeMask *pFlagsOut,
106 u32 timeOffset, U checkFunc) {
107 update(timeOffset);
108 State state = calcState(System::RaceManager::Instance()->timer());
109 bool hasCol = (m_objColMgr->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut);
110
111 if (state == State::Rest || hasCol) {
112 return hasCol;
113 }
114
115 hasCol = m_colMgrB && (m_colMgrB->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut);
116 hasCol = hasCol ||
117 (m_colMgrC && (m_colMgrC->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut));
118
119 return hasCol;
120}
121
122bool ObjectVolcanoPiece::checkCollisionImpl(f32 radius, const EGG::Vector3f &v0,
123 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
124 u32 timeOffset, CheckSphereFullFunc checkFunc) {
125 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
126 State state = calcState(t);
127 update(timeOffset);
128
129 if (state == State::Rest) {
130 return (m_objColMgr->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut);
131 }
132
133 if (state == State::Gone) {
134 return m_colMgrC && (m_colMgrC->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut);
135 }
136
137 bool hasCol = (m_objColMgr->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut);
138 hasCol = hasCol ||
139 (m_colMgrB && (m_colMgrB->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut));
140 hasCol = hasCol ||
141 (m_colMgrC && (m_colMgrC->*checkFunc)(radius, v0, v1, flags, pInfo, pFlagsOut));
142
143 return hasCol;
144}
145
147void ObjectVolcanoPiece::narrScLocal(f32 radius, const EGG::Vector3f &pos, KCLTypeMask mask,
148 u32 /*timeOffset*/) {
149 State state = calcState(System::RaceManager::Instance()->timer());
150 m_objColMgr->narrScLocal(radius, pos, mask);
151
152 if (state == State::Rest) {
153 return;
154 }
155
156 if (m_colMgrB) {
157 m_colMgrB->narrScLocal(radius, pos, mask);
158 }
159
160 if (m_colMgrC) {
161 m_colMgrC->narrScLocal(radius, pos, mask);
162 }
163}
164
166void ObjectVolcanoPiece::update(u32 timeOffset) {
167 State state = calcState(System::RaceManager::Instance()->timer() - timeOffset);
168 if (state == State::Rest || state == State::Gone) {
169 return;
170 }
171
172 EGG::Vector3f movingObjVel;
173 const EGG::Matrix34f &rtMat = calcShakeAndFall(&movingObjVel, timeOffset);
174 EGG::Matrix34f invMat;
175 rtMat.ps_inverse(invMat);
176
177 m_objColMgr->setMtx(rtMat);
178 m_objColMgr->setInvMtx(invMat);
179
180 if (m_colMgrB) {
181 m_colMgrB->setMtx(rtMat);
182 m_colMgrB->setInvMtx(invMat);
183 }
184
185 setMovingObjVel(movingObjVel);
186}
187
189void ObjectVolcanoPiece::calcScale(u32 timeOffset) {
190 State state = calcState(System::RaceManager::Instance()->timer() - timeOffset);
191
192 if (state == State::Rest || state == State::Gone) {
193 return;
194 }
195
196 f32 scale = getScaleY(timeOffset);
197 m_objColMgr->setScale(scale);
198
199 if (m_colMgrB) {
200 m_colMgrB->setScale(scale);
201 }
202}
203
205void ObjectVolcanoPiece::setMovingObjVel(const EGG::Vector3f &v) {
206 m_objColMgr->setMovingObjVel(v);
207
208 if (m_colMgrB) {
209 m_colMgrB->setMovingObjVel(v);
210 }
211}
212
214const EGG::Matrix34f &ObjectVolcanoPiece::calcShakeAndFall(EGG::Vector3f *vel, u32 timeOffset) {
215 constexpr f32 FALL_SPEED = 10.0f;
216 constexpr s32 SHAKE_STEPS = 8;
217 constexpr s32 SHAKE_STEPS_HALF = SHAKE_STEPS / 2;
218 constexpr f32 SHAKE_STEP_AMPLITUDE = 5.0f;
219
220 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
221 State state = calcState(t);
222
223 EGG::Vector3f pos = m_initialPos;
224
225 switch (state) {
226 case State::Shake: {
227 s32 step = static_cast<s32>(calcT(t)) % SHAKE_STEPS + 1;
228
229 if (step > SHAKE_STEPS_HALF) {
230 step = SHAKE_STEPS_HALF - step;
231 }
232 pos.y += SHAKE_STEP_AMPLITUDE * static_cast<f32>(step);
233 } break;
234 case State::Fall:
235 pos.y -= FALL_SPEED * static_cast<f32>(calcT(t));
236 break;
237 case State::Gone:
238 pos.y -= FALL_SPEED * static_cast<f32>(FALL_DURATION);
239 break;
240 default:
241 break;
242 }
243
244 if (vel) {
245 EGG::Vector3f prevPos = m_initialPos;
246 State prevState = calcState(t - 1);
247
248 switch (prevState) {
249 case State::Shake: {
250 s32 step = static_cast<s32>(calcT(t - 1)) % SHAKE_STEPS + 1;
251
252 if (step > SHAKE_STEPS_HALF) {
253 step = SHAKE_STEPS_HALF - step;
254 }
255 prevPos.y += SHAKE_STEP_AMPLITUDE * static_cast<f32>(step);
256 } break;
257 case State::Fall:
258 prevPos.y -= FALL_SPEED * static_cast<f32>(calcT(t - 1));
259 break;
260 case State::Gone:
261 prevPos.y -= FALL_SPEED * static_cast<f32>(FALL_DURATION);
262 break;
263 default:
264 break;
265 }
266
267 *vel = EGG::Vector3f(0.0f, pos.y - prevPos.y, 0.0f);
268 }
269
270 m_rtMat.makeRT(m_rot, pos);
271 return m_rtMat;
272}
273
275ObjectVolcanoPiece::State ObjectVolcanoPiece::calcState(u32 frame) const {
276 if (frame < m_restDuration) {
277 return State::Rest;
278 }
279
280 if (frame < m_shakeDuration) {
281 return State::Shake;
282 }
283
284 if (frame < m_quakeDuration) {
285 return State::Quake;
286 }
287
288 if (frame < m_quakeDuration + FALL_DURATION) {
289 return State::Fall;
290 }
291
292 return State::Gone;
293}
294
296f32 ObjectVolcanoPiece::calcT(u32 frame) const {
297 if (frame < m_restDuration) {
298 return static_cast<f32>(frame);
299 }
300
301 if (frame < m_shakeDuration) {
302 return static_cast<f32>(frame - m_restDuration);
303 }
304
305 if (frame < m_quakeDuration) {
306 return static_cast<f32>(frame - m_shakeDuration);
307 }
308
309 if (frame < m_quakeDuration + FALL_DURATION) {
310 return static_cast<f32>(frame - m_quakeDuration);
311 }
312
313 return static_cast<f32>(frame - m_quakeDuration - FALL_DURATION);
314}
315
316} // namespace Field
A 3 x 4 matrix.
Definition Matrix.hh:8
void makeRT(const Vector3f &r, const Vector3f &t)
Sets rotation-translation matrix.
Definition Matrix.cc:71
bool ps_inverse(Matrix34f &out) const
Definition Matrix.cc:311
Pertains to collision.
A 3D float vector.
Definition Vector.hh:88