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