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
11namespace Field {
12
14void ObjectDirector::init() {
15 for (auto *&obj : m_objects) {
16 obj->init();
17 obj->calcModel();
18 }
19
20 ObjectDrivableDirector::Instance()->init();
21}
22
24void ObjectDirector::calc() {
25 for (auto *&obj : m_calcObjects) {
26 obj->calc();
27 }
28
29 for (auto *&obj : m_calcObjects) {
30 obj->calcModel();
31 }
32
33 ObjectDrivableDirector::Instance()->calc();
34}
35
37void ObjectDirector::addObject(ObjectCollidable *obj) {
38 u32 loadFlags = obj->loadFlags();
39
40 if (loadFlags & 1) {
41 m_calcObjects.push_back(obj);
42 }
43
44 const auto *set = m_flowTable.set(m_flowTable.slot(obj->id()));
45
46 // In the base game, it's possible an object here will access slot -1 (e.g. Moonview Highway
47 // cars). We add a nullptr check here to prevent this.
48 if (set && set->mode != 0) {
49 if (obj->collision()) {
50 m_collisionObjects.push_back(obj);
51 }
52 }
53
54 m_objects.push_back(obj);
55}
56
57void ObjectDirector::addObjectNoImpl(ObjectNoImpl *obj) {
58 m_objects.push_back(obj);
59}
60
62size_t ObjectDirector::checkKartObjectCollision(Kart::KartObject *kartObj,
63 ObjectCollisionConvexHull *convexHull) {
64 size_t count = 0;
65
66 while (ObjectCollidable *obj = BoxColManager::Instance()->getNextObject()) {
67 auto *objCollision = obj->collision();
68 if (!objCollision) {
69 continue;
70 }
71
72 obj->calcCollisionTransform();
73 if (!obj->checkCollision(convexHull, m_hitDepths[count])) {
74 continue;
75 }
76
77 // We have a collision, process it
78 // Assume that we are not in a star, mega, or bullet
79 Kart::Reaction reactionOnKart = m_hitTableKart.reaction(m_hitTableKart.slot(obj->id()));
80 Kart::Reaction reactionOnObj =
81 m_hitTableKartObject.reaction(m_hitTableKartObject.slot(obj->id()));
82
83 // The object might change the reaction states
84 obj->processKartReactions(kartObj, reactionOnKart, reactionOnObj);
85
86 Kart::Reaction reaction =
87 obj->onCollision(kartObj, reactionOnKart, reactionOnObj, m_hitDepths[count]);
88 m_reactions[count] = reaction;
89
90 if (reaction == Kart::Reaction::WallAllSpeed || reaction == Kart::Reaction::WallSpark) {
91 obj->onWallCollision(kartObj, m_hitDepths[count]);
92 } else {
93 obj->onObjectCollision(kartObj);
94 }
95
96 m_collidingObjects[count] = obj;
97 if (m_hitDepths[count].y < 0.0f) {
98 m_hitDepths[count].y = 0.0f;
99 }
100
101 ++count;
102 }
103
104 return count;
105}
106
108ObjectDirector *ObjectDirector::CreateInstance() {
109 ASSERT(!s_instance);
110 s_instance = new ObjectDirector;
111
112 ObjectDrivableDirector::CreateInstance();
113
114 s_instance->createObjects();
115
116 return s_instance;
117}
118
120void ObjectDirector::DestroyInstance() {
121 ASSERT(s_instance);
122 auto *instance = s_instance;
123 s_instance = nullptr;
124 delete instance;
125
126 ObjectDrivableDirector::DestroyInstance();
127}
128
130ObjectDirector::ObjectDirector()
131 : m_flowTable("ObjFlow.bin"), m_hitTableKart("GeoHitTableKart.bin"),
132 m_hitTableKartObject("GeoHitTableKartObj.bin") {}
133
135ObjectDirector::~ObjectDirector() {
136 if (s_instance) {
137 s_instance = nullptr;
138 WARN("ObjectDirector instance not explicitly handled!");
139 }
140
141 for (auto *&obj : m_objects) {
142 delete obj;
143 }
144}
145
147void ObjectDirector::createObjects() {
148 const auto *courseMap = System::CourseMap::Instance();
149 size_t objectCount = courseMap->getGeoObjCount();
150
151 // It's possible for the KMP to specify settings for objects that aren't tracked here
152 // MAX_UNIT_COUNT is the upper bound for tracked object count, so we reserve the minimum
153 size_t maxCount = std::min(objectCount, MAX_UNIT_COUNT);
154 m_objects.reserve(maxCount);
155 m_calcObjects.reserve(maxCount);
156 m_collisionObjects.reserve(maxCount);
157
158 for (size_t i = 0; i < objectCount; ++i) {
159 const auto *pObj = courseMap->getGeoObj(i);
160 ASSERT(pObj);
161
162 // Assume one player - if the presence flag isn't set, don't construct it
163 if (!(pObj->presenceFlag() & 1)) {
164 continue;
165 }
166
167 // Prevent construction of objects with disabled or no collision
168 if (IsObjectBlacklisted(pObj->id())) {
169 continue;
170 }
171
172 ObjectBase *object = createObject(*pObj);
173 object->load();
174 }
175}
176
178ObjectBase *ObjectDirector::createObject(const System::MapdataGeoObj &params) {
179 ObjectId id = static_cast<ObjectId>(params.id());
180 switch (id) {
181 case ObjectId::WLWallGC:
182 return new ObjectWLWallGC(params);
183 case ObjectId::Boble:
184 return new ObjectBoble(params);
185 case ObjectId::DokanSFC:
186 return new ObjectDokan(params);
187 case ObjectId::OilSFC:
188 return new ObjectOilSFC(params);
189 case ObjectId::ParasolR:
190 return new ObjectParasolR(params);
191 case ObjectId::Kuribo:
192 return new ObjectKuribo(params);
193 case ObjectId::WLFirebarGC:
194 return new ObjectFirebar(params);
195 case ObjectId::WLFireRingGC:
196 return new ObjectFireRing(params);
197 case ObjectId::PuchiPakkun:
198 return new ObjectPuchiPakkun(params);
199 case ObjectId::KinokoUd:
200 return new ObjectKinokoUd(params);
201 case ObjectId::KinokoBend:
202 return new ObjectKinokoBend(params);
203 case ObjectId::KinokoNm:
204 return new ObjectKinokoNm(params);
205 case ObjectId::Aurora:
206 return new ObjectAurora(params);
207 // Non-specified objects are stock collidable objects by default
208 // However, we need to specify an impl, so we don't use default
209 case ObjectId::DummyPole:
210 case ObjectId::CastleTree1c:
211 case ObjectId::PalmTree:
212 case ObjectId::DKtreeA64c:
213 case ObjectId::TownTreeDsc:
214 return new ObjectCollidable(params);
215 case ObjectId::WLDokanGC:
216 case ObjectId::Mdush:
217 return new ObjectKCL(params);
218 default:
219 return new ObjectNoImpl(params);
220 }
221}
222
223ObjectDirector *ObjectDirector::s_instance = nullptr;
224
225} // 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.