A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectDirector.cc
1#include "ObjectDirector.hh"
2
3#include "game/field/BoxColManager.hh"
4#include "game/field/ObjectDrivableDirector.hh"
5#include "game/field/obj/ObjectRegistry.hh"
6
7#include "game/kart/KartObject.hh"
8
9#include "game/system/CourseMap.hh"
10#include "game/system/RaceConfig.hh"
11
12namespace Field {
13
15void ObjectDirector::init() {
16 for (auto *&obj : m_objects) {
17 obj->init();
18 obj->calcModel();
19 }
20
21 ObjectDrivableDirector::Instance()->init();
22}
23
25void ObjectDirector::calc() {
26 for (auto *&obj : m_calcObjects) {
27 obj->calc();
28 }
29
30 for (auto *&obj : m_calcObjects) {
31 obj->calcModel();
32 }
33
34 ObjectDrivableDirector::Instance()->calc();
35}
36
38void ObjectDirector::addObject(ObjectCollidable *obj) {
39 u32 loadFlags = obj->loadFlags();
40
41 if (loadFlags & 1) {
42 m_calcObjects.push_back(obj);
43 }
44
45 const auto *set = m_flowTable.set(m_flowTable.slot(obj->id()));
46
47 // In the base game, it's possible an object here will access slot -1 (e.g. Moonview Highway
48 // cars). We add a nullptr check here to prevent this.
49 if (set && set->mode != 0) {
50 if (obj->collision()) {
51 m_collisionObjects.push_back(obj);
52 }
53 }
54
55 m_objects.push_back(obj);
56}
57
58void ObjectDirector::addObjectNoImpl(ObjectNoImpl *obj) {
59 m_objects.push_back(obj);
60}
61
63void ObjectDirector::addManagedObject(ObjectCollidable *obj) {
64 m_managedObjects.push_back(obj);
65}
66
68size_t ObjectDirector::checkKartObjectCollision(Kart::KartObject *kartObj,
69 ObjectCollisionConvexHull *convexHull) {
70 size_t count = 0;
71
72 while (ObjectCollidable *obj = BoxColManager::Instance()->getNextObject()) {
73 auto *objCollision = obj->collision();
74 if (!objCollision) {
75 continue;
76 }
77
78 obj->calcCollisionTransform();
79 if (!obj->checkCollision(convexHull, m_hitDepths[count])) {
80 continue;
81 }
82
83 // We have a collision, process it
84 // Assume that we are not in a star, mega, or bullet
85 Kart::Reaction reactionOnKart = m_hitTableKart.reaction(m_hitTableKart.slot(obj->id()));
86 Kart::Reaction reactionOnObj =
87 m_hitTableKartObject.reaction(m_hitTableKartObject.slot(obj->id()));
88
89 // The object might change the reaction states
90 obj->processKartReactions(kartObj, reactionOnKart, reactionOnObj);
91
92 Kart::Reaction reaction =
93 obj->onCollision(kartObj, reactionOnKart, reactionOnObj, m_hitDepths[count]);
94 m_reactions[count] = reaction;
95
96 if (reaction == Kart::Reaction::WallAllSpeed || reaction == Kart::Reaction::WallSpark) {
97 obj->onWallCollision(kartObj, m_hitDepths[count]);
98 } else {
99 obj->onObjectCollision(kartObj);
100 }
101
102 m_collidingObjects[count] = obj;
103 if (m_hitDepths[count].y < 0.0f) {
104 m_hitDepths[count].y = 0.0f;
105 }
106
107 ++count;
108 }
109
110 return count;
111}
112
114f32 ObjectDirector::distAboveRisingWater(f32 offset) const {
115 ASSERT(m_psea);
116 return offset - m_psea->pos().y;
117}
118
120f32 ObjectDirector::risingWaterKillPlaneHeight() const {
121 ASSERT(m_psea);
122 return m_psea->pos().y - 260.0f;
123}
124
126ObjectDirector *ObjectDirector::CreateInstance() {
127 ASSERT(!s_instance);
128 s_instance = new ObjectDirector;
129
130 ObjectDrivableDirector::CreateInstance();
131
132 s_instance->createObjects();
133
134 return s_instance;
135}
136
138void ObjectDirector::DestroyInstance() {
139 ASSERT(s_instance);
140 auto *instance = s_instance;
141 s_instance = nullptr;
142 delete instance;
143
144 ObjectDrivableDirector::DestroyInstance();
145}
146
148ObjectDirector::ObjectDirector()
149 : m_flowTable("ObjFlow.bin"), m_hitTableKart("GeoHitTableKart.bin"),
150 m_hitTableKartObject("GeoHitTableKartObj.bin"), m_psea(nullptr) {}
151
153ObjectDirector::~ObjectDirector() {
154 if (s_instance) {
155 s_instance = nullptr;
156 WARN("ObjectDirector instance not explicitly handled!");
157 }
158
159 for (auto *&obj : m_objects) {
160 delete obj;
161 }
162}
163
165void ObjectDirector::createObjects() {
166 const auto *courseMap = System::CourseMap::Instance();
167 size_t objectCount = courseMap->getGeoObjCount();
168
169 // It's possible for the KMP to specify settings for objects that aren't tracked here
170 // MAX_UNIT_COUNT is the upper bound for tracked object count, so we reserve the minimum
171 size_t maxCount = std::min(objectCount, MAX_UNIT_COUNT);
172 m_objects.reserve(maxCount);
173 m_calcObjects.reserve(maxCount);
174 m_collisionObjects.reserve(maxCount);
175
176 auto *objDrivableDir = ObjectDrivableDirector::Instance();
177 const auto &raceScenario = System::RaceConfig::Instance()->raceScenario();
178 bool rGV2 = raceScenario.course == Course::SNES_Ghost_Valley_2;
179 bool sun = false;
180
181 for (size_t i = 0; i < objectCount; ++i) {
182 const auto *pObj = courseMap->getGeoObj(i);
183 ASSERT(pObj);
184
185 // Assume one player - if the presence flag isn't set, don't construct it
186 if (!(pObj->presenceFlag() & 1)) {
187 continue;
188 }
189
190 // Prevent construction of objects with disabled or no collision
191 if (IsObjectBlacklisted(pObj->id())) {
192 continue;
193 }
194
195 // rGV2's blocks are created outside of the factory function
196 if (rGV2) {
197 switch (static_cast<ObjectId>(pObj->id())) {
198 case ObjectId::ObakeBlockSFCc:
199 case ObjectId::ObakeBlock2SFCc:
200 case ObjectId::ObakeBlock3SFCc: {
201 // Create the manager if this is the first block.
202 auto *obakeManager = objDrivableDir->obakeManager();
203 if (!obakeManager) {
204 objDrivableDir->createObakeManager(*pObj);
205 } else {
206 obakeManager->addBlock(*pObj);
207 }
208 } break;
209 default:
210 break;
211 }
212 }
213
214 ObjectBase *object = createObject(*pObj);
215 object->load();
216
217 if (object->id() == ObjectId::SunDS) {
218 sun = true;
219 }
220 }
221
222 if (raceScenario.course == Course::Moonview_Highway) {
223 auto *highwayMgr = new ObjectHighwayManager;
224 highwayMgr->load();
225 }
226
227 if (sun) {
228 auto *sunMgr = new ObjectSunManager;
229 sunMgr->load();
230 }
231
232 if (raceScenario.course == Course::GBA_Shy_Guy_Beach) {
233 auto *shipMgr = new ObjectHeyhoShipManager;
234 shipMgr->load();
235 }
236}
237
239ObjectBase *ObjectDirector::createObject(const System::MapdataGeoObj &params) {
240 ObjectId id = static_cast<ObjectId>(params.id());
241 switch (id) {
242 case ObjectId::Psea:
243 return new ObjectPsea(params);
244 case ObjectId::Woodbox:
245 return new ObjectWoodbox(params);
246 case ObjectId::WLWallGC:
247 return new ObjectWLWallGC(params);
248 case ObjectId::CarA1:
249 case ObjectId::CarA2:
250 case ObjectId::CarA3:
251 return new ObjectCarA(params);
252 case ObjectId::Basabasa:
253 return new ObjectBasabasa(params);
254 case ObjectId::HeyhoShipGBA:
255 return new ObjectHeyhoShip(params);
256 case ObjectId::KartTruck:
257 case ObjectId::CarBody:
258 return new ObjectCarTGE(params);
259 case ObjectId::KoopaBall:
260 return new ObjectKoopaBall(params);
261 case ObjectId::W_Woodbox:
262 return new ObjectWoodboxW(params);
263 case ObjectId::SunDS:
264 return new ObjectSunDS(params);
265 case ObjectId::ItemboxLine:
266 return new ObjectItemboxLine(params);
267 case ObjectId::VolcanoBall:
268 return new ObjectVolcanoBallLauncher(params);
269 case ObjectId::PenguinS:
270 return new ObjectPenguinS(params);
271 case ObjectId::PenguinM:
272 return new ObjectPenguin(params);
273 case ObjectId::Dossunc:
274 return new ObjectDossunc(params);
275 case ObjectId::Boble:
276 return new ObjectBoble(params);
277 case ObjectId::Seagull:
278 return new ObjectBird(params);
279 case ObjectId::HeyhoBallGBA:
280 return new ObjectHeyhoBall(params);
281 case ObjectId::DokanSFC:
282 return new ObjectDokan(params);
283 case ObjectId::Pylon:
284 return new ObjectPylon(params);
285 case ObjectId::OilSFC:
286 return new ObjectOilSFC(params);
287 case ObjectId::ParasolR:
288 return new ObjectParasolR(params);
289 case ObjectId::KoopaFigure64:
290 return new ObjectKoopaFigure64(params);
291 case ObjectId::Kuribo:
292 return new ObjectKuribo(params);
293 case ObjectId::Choropu:
294 case ObjectId::Choropu2:
295 return new ObjectChoropu(params);
296 case ObjectId::Cow:
297 return new ObjectCowHerd(params);
298 case ObjectId::PakkunF:
299 return new ObjectPakkunF(params);
300 case ObjectId::WLFirebarGC:
301 case ObjectId::KoopaFirebar:
302 return new ObjectFirebar(params);
303 case ObjectId::DKRockGC:
304 return new ObjectRock(params);
305 case ObjectId::Sanbo:
306 return new ObjectSanbo(params);
307 case ObjectId::TruckWagon:
308 return new ObjectTruckWagon(params);
309 case ObjectId::Heyho:
310 return new ObjectHeyho(params);
311 case ObjectId::Press:
312 return new ObjectPress(params);
313 case ObjectId::WLFireRingGC:
314 return new ObjectFireRing(params);
315 case ObjectId::FireSnake:
316 return new ObjectFireSnake(params);
317 case ObjectId::FireSnakeV:
318 return new ObjectFireSnakeV(params);
319 case ObjectId::PuchiPakkun:
320 return new ObjectPuchiPakkun(params);
321 case ObjectId::KinokoUd:
322 return new ObjectKinokoUd(params);
323 case ObjectId::KinokoBend:
324 return new ObjectKinokoBend(params);
325 case ObjectId::VolcanoRock:
326 return new ObjectVolcanoRock(params);
327 case ObjectId::BulldozerL:
328 case ObjectId::BulldozerR:
329 return new ObjectBulldozer(params);
330 case ObjectId::KinokoNm:
331 return new ObjectKinokoNm(params);
332 case ObjectId::Crane:
333 return new ObjectCrane(params);
334 case ObjectId::VolcanoPiece:
335 return new ObjectVolcanoPiece(params);
336 case ObjectId::FlamePole:
337 return new ObjectFlamePoleFoot(params);
338 case ObjectId::TwistedWay:
339 return new ObjectTwistedWay(params);
340 case ObjectId::TownBridge:
341 return new ObjectTownBridge(params);
342 case ObjectId::DKShip64:
343 return new ObjectShip64(params);
344 case ObjectId::Turibashi:
345 return new ObjectTuribashi(params);
346 case ObjectId::Aurora:
347 return new ObjectAurora(params);
348 case ObjectId::DCPillar:
349 return new ObjectPillar(params);
350 case ObjectId::Sandcone:
351 return new ObjectSandcone(params);
352 case ObjectId::FlamePoleV:
353 case ObjectId::FlamePoleVBig:
354 return new ObjectFlamePoleV(params);
355 case ObjectId::Ami:
356 return new ObjectAmi(params);
357 case ObjectId::BeltEasy:
358 return new ObjectBeltEasy(params);
359 case ObjectId::BeltCrossing:
360 return new ObjectBeltCrossing(params);
361 case ObjectId::BeltCurveA:
362 return new ObjectBeltCurveA(params);
363 case ObjectId::Escalator:
364 return new ObjectEscalator(params);
365 case ObjectId::EscalatorGroup:
366 return new ObjectEscalatorGroup(params);
367
368 // Non-specified objects are stock collidable objects by default
369 // However, we need to specify an impl, so we don't use default
370 case ObjectId::DummyPole:
371 case ObjectId::CastleTree1c:
372 case ObjectId::PeachTreeGCc:
373 case ObjectId::MarioGo64c:
374 case ObjectId::KinokoT1:
375 case ObjectId::PalmTree:
376 case ObjectId::Parasol:
377 case ObjectId::HeyhoTreeGBAc:
378 case ObjectId::GardenTreeDSc:
379 case ObjectId::DKtreeA64c:
380 case ObjectId::DKTreeB64c:
381 case ObjectId::TownTreeDsc:
382 case ObjectId::PakkunDokan:
383 return new ObjectCollidable(params);
384 case ObjectId::WLDokanGC:
385 case ObjectId::Mdush:
386 return new ObjectKCL(params);
387 default:
388 return new ObjectNoImpl(params);
389 }
390}
391
392ObjectDirector *ObjectDirector::s_instance = nullptr;
393
394} // namespace Field
std::vector< ObjectBase * > m_objects
All objects live here.
std::vector< ObjectBase * > m_collisionObjects
Objects having collision live here too.
std::array< ObjectCollidable *, MAX_UNIT_COUNT > m_collidingObjects
Objects we are currently colliding with.
std::vector< ObjectBase * > m_calcObjects
Objects needing calc() live here too.
The highest level abstraction for a kart.
Definition KartObject.hh:11
Pertains to collision.
ObjectDokan ObjectPuchiPakkun
This is just to help with readability. The rMR piranhas are really just pipes.