A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectAurora.cc
1#include "ObjectAurora.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/system/RaceManager.hh"
6
7namespace Kinoko::Field {
8
10ObjectAurora::ObjectAurora(const System::MapdataGeoObj &params) : ObjectDrivable(params) {}
11
13ObjectAurora::~ObjectAurora() = default;
14
16void ObjectAurora::init() {}
17
22
24void ObjectAurora::createCollision() {}
25
27void ObjectAurora::calcCollisionTransform() {}
28
30f32 ObjectAurora::getCollisionRadius() const {
31 return COLLISION_SIZE.z + 100.0f;
32}
33
35bool ObjectAurora::checkPointPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
36 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
37 return checkSpherePartialImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
38}
39
41bool ObjectAurora::checkPointPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
42 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
43 return checkSpherePartialPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
44}
45
47bool ObjectAurora::checkPointFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
48 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
49 return checkSphereFullImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
50}
51
53bool ObjectAurora::checkPointFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
54 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
55 return checkSphereFullPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
56}
57
59bool ObjectAurora::checkSpherePartial(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
60 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
61 return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
62}
63
65bool ObjectAurora::checkSpherePartialPush(f32 radius, const EGG::Vector3f &v0,
66 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
67 KCLTypeMask *pFlagsOut, u32 timeOffset) {
68 return checkSpherePartialPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
69}
70
72bool ObjectAurora::checkSphereFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
73 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
74 return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
75}
76
78bool ObjectAurora::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
79 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
80 return checkSphereFullPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
81}
82
84bool ObjectAurora::checkPointCachedPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
85 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
86 return checkSpherePartialImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
87}
88
90bool ObjectAurora::checkPointCachedPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
91 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
92 return checkSpherePartialPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
93}
94
96bool ObjectAurora::checkPointCachedFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
97 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
98 return checkSphereFullImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
99}
100
102bool ObjectAurora::checkPointCachedFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
103 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
104 return checkSphereFullPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
105}
106
108bool ObjectAurora::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &v0,
109 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
110 KCLTypeMask *pFlagsOut, u32 timeOffset) {
111 return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
112}
113
115bool ObjectAurora::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &v0,
116 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
117 KCLTypeMask *pFlagsOut, u32 timeOffset) {
118 return checkSpherePartialPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
119}
120
122bool ObjectAurora::checkSphereCachedFull(f32 radius, const EGG::Vector3f &v0,
123 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
124 u32 timeOffset) {
125 return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
126}
127
129bool ObjectAurora::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &v0,
130 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
131 u32 timeOffset) {
132 return checkSphereFullPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
133}
134
136bool ObjectAurora::checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0,
137 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
138 KCLTypeMask *pFlagsOut, u32 timeOffset) {
139 return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, false);
140}
141
143bool ObjectAurora::checkSpherePartialPushImpl(f32 radius, const EGG::Vector3f &v0,
144 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
145 KCLTypeMask *pFlagsOut, u32 timeOffset) {
146 return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, true);
147}
148
150bool ObjectAurora::checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
151 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
152 return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, false);
153}
154
156bool ObjectAurora::checkSphereFullPushImpl(f32 radius, const EGG::Vector3f &v0,
157 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
158 u32 timeOffset) {
159 return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, true);
160}
161
165bool ObjectAurora::checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0,
166 const EGG::Vector3f & /*v1*/, KCLTypeMask flags, CollisionInfoPartial *pInfo,
167 KCLTypeMask *pFlagsOut, u32 timeOffset, bool push) {
168 EGG::Vector3f vel = v0 - pos();
169
170 if (vel.z < 0.0f || vel.z > COLLISION_SIZE.z || EGG::Mathf::abs(vel.x) > COLLISION_SIZE.x) {
171 return false;
172 }
173
174 if (!(flags & KCL_TYPE_FLOOR)) {
175 return false;
176 }
177
178 u32 t = timeOffset + System::RaceManager::Instance()->timer();
179 EGG::Vector3f bbox;
180 EGG::Vector3f fnrm;
181 f32 dist;
182
183 if (!calcCollision(radius, vel, t, bbox, fnrm, dist)) {
184 return false;
185 }
186
187 if (pInfo) {
188 pInfo->updateBBox(bbox);
189 }
190
191 if (pFlagsOut) {
192 auto *colDirector = CollisionDirector::Instance();
193
194 if (push) {
195 colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_ROAD2),
197 colDirector->setCurrentCollisionVariant(7);
198 colDirector->setCurrentCollisionTrickable(true);
199 } else {
200 *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_ROAD2);
201 }
202
203 if (vel.z > COLLISION_SIZE.z - 600.0f * 4.0f) {
204 if (push) {
205 colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP),
207 } else {
209 }
210 }
211 }
212
213 return true;
214}
215
219bool ObjectAurora::checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0,
220 const EGG::Vector3f & /*v1*/, KCLTypeMask flags, CollisionInfo *pInfo,
221 KCLTypeMask *pFlagsOut, u32 timeOffset, bool push) {
222 EGG::Vector3f vel = v0 - pos();
223
224 if (vel.z < 0.0f || vel.z > COLLISION_SIZE.z || EGG::Mathf::abs(vel.x) > COLLISION_SIZE.x) {
225 return false;
226 }
227
228 if (!(flags & KCL_TYPE_FLOOR)) {
229 return false;
230 }
231
232 u32 t = timeOffset + System::RaceManager::Instance()->timer();
233 EGG::Vector3f bbox;
234 EGG::Vector3f fnrm;
235 f32 dist;
236
237 if (!calcCollision(radius, vel, t, bbox, fnrm, dist)) {
238 return false;
239 }
240
241 if (pInfo) {
242 pInfo->updateBBox(bbox);
243
244 pInfo->updateFloor(dist, fnrm);
245 }
246
247 if (pFlagsOut) {
248 auto *colDirector = CollisionDirector::Instance();
249
250 if (push) {
251 colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_ROAD2),
253 colDirector->setCurrentCollisionVariant(7);
254 colDirector->setCurrentCollisionTrickable(true);
255 } else {
256 *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_ROAD2);
257 }
258
259 if (vel.z > COLLISION_SIZE.z - 600.0f * 4.0f) {
260 if (push) {
261 colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP),
263 } else {
265 }
266 }
267 }
268
269 return true;
270}
271
278bool ObjectAurora::calcCollision(f32 radius, const EGG::Vector3f &vel, u32 time, EGG::Vector3f &v0,
279 EGG::Vector3f &fnrm, f32 &dist) {
280 constexpr f32 INITIAL_FREQUENCY = 1.0f;
281 constexpr f32 MAX_FREQUENCY = 4.0f;
282 constexpr f32 PHASE_SHIFT_SECONDS = 30.0f;
283 constexpr f32 COLLISION_DISTANCE_THRESHOLD = 600.0f;
284 constexpr f32 UPWARP_THRESHOLD = 300.0f;
285 constexpr f32 UPWARP_DIST_SCALAR = 0.2f;
286
287 f32 minsNormalized = (static_cast<f32>(time) / 60.0f - PHASE_SHIFT_SECONDS) / 60.0f;
288 f32 frequency = std::min(INITIAL_FREQUENCY + minsNormalized * minsNormalized, MAX_FREQUENCY);
289 f32 velPeriod = (F_PI * (2.0f * vel.z)) / COLLISION_SIZE.z;
290
291 f32 result = EGG::Mathf::SinFIdx(
292 RAD2FIDX * (velPeriod * frequency + (F_PI * static_cast<f32>(time) / 50.0f)));
293 result = radius - (vel.y - velPeriod * 80.0f * result);
294
295 // We're not colliding if we're 600 units away or if the road is now behind us.
296 if (result <= 0.0f || result >= COLLISION_DISTANCE_THRESHOLD) {
297 return false;
298 }
299
300 // Responsible for the sudden upwards snap that can occur when falling off.
301 if (result > UPWARP_THRESHOLD) {
302 result *= UPWARP_DIST_SCALAR;
303 }
304
305 fnrm = EGG::Vector3f::ey;
306 v0 = fnrm * result;
307 dist = result;
308
309 return true;
310}
311
312} // namespace Kinoko::Field
@ COL_TYPE_BOOST_RAMP
Trickable. Variant affects boost duration.
@ COL_TYPE_ROAD2
COL_TYPE_ROAD but with more variants.
#define KCL_TYPE_BIT(x)
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
bool calcCollision(f32 radius, const EGG::Vector3f &vel, u32 time, EGG::Vector3f &v0, EGG::Vector3f &fnrm, f32 &dist)
Calculates the sin-like collision of the wavy road.
LoadFlags loadFlags() const override
Returns a bitmask indicating which lifecycle hooks should be called for the object.
EGG::TBitFlag< u8, eLoadFlags > LoadFlags
A bitfield of eLoadFlags that represents the update requirements of the object.
Definition ObjectBase.hh:36
@ Calc
The state of the object should be recalculated every frame.
Definition ObjectBase.hh:30
Pertains to collision.
A 3D float vector.
Definition Vector.hh:107