A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectAmi.cc
1#include "ObjectAmi.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/system/RaceManager.hh"
6
7#include <egg/math/Math.hh>
8
9namespace Field {
10
12ObjectAmi::ObjectAmi(const System::MapdataGeoObj &params) : ObjectDrivable(params) {}
13
15ObjectAmi::~ObjectAmi() = default;
16
18bool ObjectAmi::checkPointPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
19 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
20 return checkSpherePartialImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
21}
22
24bool ObjectAmi::checkPointPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
25 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
26 return checkSpherePartialPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
27}
28
30bool ObjectAmi::checkPointFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags,
31 CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
32 return checkSphereFullImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
33}
34
36bool ObjectAmi::checkPointFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
37 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
38 return checkSphereFullPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
39}
40
42bool ObjectAmi::checkSpherePartial(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
43 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
44 return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
45}
46
48bool ObjectAmi::checkSpherePartialPush(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
49 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
50 return checkSpherePartialPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
51}
52
54bool ObjectAmi::checkSphereFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
55 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
56 return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
57}
58
60bool ObjectAmi::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
61 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
62 return checkSphereFullPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
63}
64
66bool ObjectAmi::checkPointCachedPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
67 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
68 return checkSpherePartialImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
69}
70
72bool ObjectAmi::checkPointCachedPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
73 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) {
74 return checkSpherePartialPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
75}
76
78bool ObjectAmi::checkPointCachedFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
79 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
80 return checkSphereFullImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
81}
82
84bool ObjectAmi::checkPointCachedFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1,
85 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) {
86 return checkSphereFullPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0);
87}
88
90bool ObjectAmi::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &v0,
91 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
92 KCLTypeMask *pFlagsOut, u32 timeOffset) {
93 return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
94}
95
97bool ObjectAmi::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &v0,
98 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
99 KCLTypeMask *pFlagsOut, u32 timeOffset) {
100 return checkSpherePartialPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
101}
102
104bool ObjectAmi::checkSphereCachedFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
105 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
106 return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
107}
108
110bool ObjectAmi::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &v0,
111 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
112 u32 timeOffset) {
113 return checkSphereFullPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset);
114}
115
117bool ObjectAmi::checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
118 KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
119 return checkSphereImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, false);
120}
121
123bool ObjectAmi::checkSpherePartialPushImpl(f32 radius, const EGG::Vector3f &v0,
124 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo,
125 KCLTypeMask *pFlagsOut, u32 timeOffset) {
126 return checkSphereImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, true);
127}
128
130bool ObjectAmi::checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1,
131 KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) {
132 return checkSphereImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, false);
133}
134
136bool ObjectAmi::checkSphereFullPushImpl(f32 radius, const EGG::Vector3f &v0,
137 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
138 u32 timeOffset) {
139 return checkSphereImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, true);
140}
141
147template <typename T>
148 requires std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>
149bool ObjectAmi::checkSphereImpl(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f & /*v1*/,
150 KCLTypeMask flags, T *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset, bool push) {
151 // We check flags first to avoid unnecessary position posDelta computation.
152 if (!(flags & KCL_TYPE_FLOOR)) {
153 return false;
154 }
155
156 EGG::Vector3f posDelta = v0 - m_pos;
157 posDelta.z *= -1.0f;
158
159 if (posDelta.z < 0.0f || posDelta.z > DIMS.z || EGG::Mathf::abs(posDelta.x) > DIMS.x) {
160 return false;
161 }
162
163 u32 t = timeOffset + System::RaceManager::Instance()->timer();
164 EGG::Vector3f bbox;
165 EGG::Vector3f fnrm;
166 f32 dist;
167
168 if (!checkCollision(radius, posDelta, t, bbox, fnrm, dist)) {
169 return false;
170 }
171
172 if (pInfo) {
173 pInfo->bbox.min = pInfo->bbox.min.minimize(bbox);
174 pInfo->bbox.max = pInfo->bbox.max.maximize(bbox);
175
176 if constexpr (std::is_same_v<T, CollisionInfo>) {
177 pInfo->updateFloor(dist, fnrm);
178 }
179 }
180
181 if (pFlagsOut) {
182 if (push) {
183 auto *colDirector = CollisionDirector::Instance();
184 colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_ROTATING_ROAD),
186 colDirector->setCurrentCollisionVariant(0);
187 colDirector->setCurrentCollisionTrickable(true);
188 } else {
190 }
191
192 if (posDelta.z > DIMS.z) {
193 *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP);
194 }
195 }
196
197 return true;
198}
199
201bool ObjectAmi::checkCollision(f32 radius, const EGG::Vector3f &posDelta, u32 time,
202 EGG::Vector3f &bbox, EGG::Vector3f &fnrm, f32 &dist) {
203 constexpr EGG::Vector3f FLOOR_NORMAL = EGG::Vector3f(0.0f, 1.5f, -0.5f);
204 constexpr f32 Z_SLOPE = 910.0f;
205
206 f32 zPhase = F_PI * (2.0f * posDelta.z) / DIMS.z;
207 f32 depth = radius - (posDelta.y - (SpatialSin(zPhase) * TemporalSin(time) - Z_SLOPE * zPhase));
208
209 // Not colliding if net is falling below the hitbox's radius or above by more than 600 units.
210 if (depth <= 0.0f || depth >= 600.0f) {
211 return false;
212 }
213
214 if (depth >= 300.0f) {
215 depth *= 0.2f;
216 }
217
218 fnrm = FLOOR_NORMAL;
219 fnrm.normalise();
220 bbox = fnrm * depth;
221 dist = depth;
222
223 return true;
224}
225
230f32 ObjectAmi::SpatialSin(f32 phase) {
231 return 550.0f * EGG::Mathf::SinFIdx(RAD2FIDX * (phase * 0.5f));
232}
233
236f32 ObjectAmi::TemporalSin(u32 t) {
237 return EGG::Mathf::SinFIdx(RAD2FIDX * (F_PI * static_cast<f32>(t) / 35.0f));
238}
239
240} // namespace Field
@ COL_TYPE_BOOST_RAMP
Trickable. Variant affects boost duration.
@ COL_TYPE_ROTATING_ROAD
Chain Chomp Roulette.
#define KCL_TYPE_BIT(x)
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
Pertains to collision.
A 3D float vector.
Definition Vector.hh:87