A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectFlamePoleFoot.cc
1#include "ObjectFlamePoleFoot.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/system/RaceManager.hh"
6
7#include <algorithm>
8
9namespace Field {
10
12ObjectFlamePoleFoot::ObjectFlamePoleFoot(const System::MapdataGeoObj &params)
13 : ObjectKCL(params), StateManager(this, STATE_ENTRIES) {
14 m_extraCycleFrames = params.setting(0);
15 m_initDelay = params.setting(1);
16 m_poleScale = static_cast<f32>(params.setting(2));
17
18 ++FLAMEPOLE_COUNT;
19
20 if (m_poleScale == 0.0f) {
21 m_poleScale = 3.0f + static_cast<f32>(FLAMEPOLE_COUNT % 3);
22 }
23
24 m_pole = new ObjectFlamePole(params, m_pos, m_rot, m_scale);
25 m_pole->load();
26}
27
29ObjectFlamePoleFoot::~ObjectFlamePoleFoot() {
30 FLAMEPOLE_COUNT = 0;
31}
32
34void ObjectFlamePoleFoot::init() {
35 constexpr f32 NORMALIZATION = static_cast<f32>(CYCLE_FRAMES) * (7.0f - 1.0f);
36
37 m_nextStateId = 0;
38 m_cycleFrame = 0;
39 m_eruptUpDuration = static_cast<s32>(0.1f * NORMALIZATION / 7.0f);
40 m_eruptDownDuration = static_cast<s32>(0.2f * NORMALIZATION / 7.0f);
41
42 s32 state1 = static_cast<s32>(0.3f * NORMALIZATION / 7.0f);
43 s32 state2 = state1 + m_eruptUpDuration;
44 s32 state3 = state2 + static_cast<s32>(static_cast<f32>(CYCLE_FRAMES) * 1.0f / 7.0f);
45 s32 state4 = state3 + m_eruptDownDuration;
46 s32 state5 = state4 + static_cast<s32>(0.4f * NORMALIZATION / 7.0f);
47 m_stateStart = {{0, state1, state2, state3, state4, state5}};
48
49 m_eruptDownVel = (m_poleScale - 1.0f) / static_cast<f32>(state1);
50 m_initScaledHeight = ObjectFlamePole::HEIGHT * m_poleScale;
51 m_scaleDelta = (300.0f + m_initScaledHeight) / static_cast<f32>(m_eruptDownDuration);
52 m_pole->setActive(false);
53 m_pole->disableCollision();
54
55 EGG::Vector3f polePos = m_pole->pos();
56 polePos.y = m_pos.y - ObjectFlamePole::HEIGHT * m_poleScale;
57 m_pole->setPos(polePos);
58}
59
61void ObjectFlamePoleFoot::calc() {
62 if (System::RaceManager::Instance()->timer() < m_initDelay) {
63 return;
64 }
65
66 calcStates();
67
68 StateManager::calc();
69
70 f32 scale = getScaleY(0);
71 m_flags.setBit(eFlags::Scale);
72 m_scale = EGG::Vector3f(scale, scale, scale);
73
74 EGG::Vector3f polePos = m_pole->pos();
75 m_pole->setPos(
76 EGG::Vector3f(polePos.x, m_heightOffset + (m_pos.y - m_initScaledHeight), polePos.z));
77 m_pole->setScale(EGG::Vector3f(m_poleScale, m_poleScale, m_poleScale));
78}
79
81void ObjectFlamePoleFoot::calcStates() {
82 u32 frame = static_cast<s32>(System::RaceManager::Instance()->timer() - m_initDelay);
83 m_cycleFrame = frame % (m_extraCycleFrames + CYCLE_FRAMES);
84
85 // Access the array of state timers to see which state corresponds with the current frame.
86 auto it = std::ranges::upper_bound(m_stateStart.begin(), m_stateStart.end(), m_cycleFrame);
87 auto idx = it - m_stateStart.begin() - 1;
88
89 if (idx < 0) {
90 return;
91 }
92
93 u16 stateId = static_cast<u16>(idx);
94
95 if (m_currentStateId != stateId) {
96 m_nextStateId = stateId;
97 }
98}
99
100f32 ObjectFlamePoleFoot::getScaleY(u32 timeOffset) const {
101 u32 frame = System::RaceManager::Instance()->timer() - timeOffset;
102 if (frame < m_initDelay) {
103 return 1.0f;
104 }
105
106 s32 cycleFrame = frame - m_initDelay;
107 cycleFrame %= m_extraCycleFrames + CYCLE_FRAMES;
108
109 if (cycleFrame >= m_stateStart[5]) {
110 return 1.0f;
111 }
112
113 if (cycleFrame >= m_stateStart[4]) {
114 return std::max(1.0f,
115 m_poleScale - m_eruptDownVel * static_cast<f32>(m_eruptDownDuration / 2) -
116 m_eruptDownVel * static_cast<f32>(cycleFrame - m_stateStart[4]));
117 }
118
119 if (cycleFrame >= m_stateStart[3]) {
120 s32 framesSince194 = cycleFrame - m_stateStart[3];
121 s32 half17c = m_eruptDownDuration / 2;
122 if (framesSince194 > half17c) {
123 return m_poleScale - m_eruptDownVel * static_cast<f32>(framesSince194 - half17c);
124 } else {
125 return m_poleScale;
126 }
127 }
128
129 if (cycleFrame >= m_stateStart[2] || cycleFrame >= m_stateStart[1]) {
130 return m_poleScale;
131 }
132
133 if (cycleFrame >= 0) {
134 return std::min(m_poleScale, m_eruptDownVel * static_cast<f32>(cycleFrame) + 1.0f);
135 }
136
137 return 1.0f;
138}
139
141bool ObjectFlamePoleFoot::checkCollision(f32 radius, const EGG::Vector3f &pos,
142 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
143 u32 timeOffset) {
144 update(timeOffset);
145 calcScale(timeOffset);
146 f32 scale = getScaleY(timeOffset);
147
148 if (!m_objColMgr->checkSphereFullPush(radius, pos, prevPos, mask, info, maskOut)) {
149 return false;
150 }
151
152 if (2.0f < scale) {
153 CollisionDirector::Instance()->setCurrentCollisionTrickable(true);
154 }
155
156 return true;
157}
158
160bool ObjectFlamePoleFoot::checkCollisionCached(f32 radius, const EGG::Vector3f &pos,
161 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
162 u32 timeOffset) {
163 update(timeOffset);
164 calcScale(timeOffset);
165 f32 scale = getScaleY(timeOffset);
166
167 if (!m_objColMgr->checkSphereCachedFullPush(radius, pos, prevPos, mask, info, maskOut)) {
168 return false;
169 }
170
171 if (2.0f < scale) {
172 CollisionDirector::Instance()->setCurrentCollisionTrickable(true);
173 }
174
175 return true;
176}
177
179void ObjectFlamePoleFoot::enterEruptingUp() {
180 m_pole->setActive(true);
181 m_pole->enableCollision();
182 m_heightOffset = 0.0f;
183
184 f32 t1 = -1.0f;
185 f32 t2 = -1.0f;
186 f32 vel = m_initScaledHeight;
187 EGG::Mathf::FindRootsQuadratic(static_cast<f32>(m_eruptUpDuration * m_eruptUpDuration),
188 -4.0f * m_initScaledHeight * static_cast<f32>(m_eruptUpDuration),
189 4.0f * m_initScaledHeight * m_initScaledHeight, t1, t2);
190
191 if (t1 <= 0.0f) {
192 t1 = -1.0f;
193 }
194
195 if (t2 <= 0.0f) {
196 vel = t1;
197 }
198
199 m_initEruptVel = vel;
200 m_eruptAccel = vel * vel / (2.0f * m_initScaledHeight);
201}
202
204void ObjectFlamePoleFoot::calcEruptingUp() {
205 f32 frame = static_cast<f32>(m_cycleFrame - m_stateStart[1]);
206 m_heightOffset = std::min(m_initScaledHeight,
207 m_initEruptVel * frame - frame * 0.5f * m_eruptAccel * frame);
208}
209
211void ObjectFlamePoleFoot::calcEruptingStay() {
212 constexpr f32 AMPLITUDE = 50.0f;
213
214 f32 angle = 360.0f * static_cast<f32>(m_cycleFrame - m_stateStart[2]) / 30.0f;
215 m_heightOffset = m_scaledHeight + AMPLITUDE * EGG::Mathf::SinFIdx(DEG2FIDX * angle);
216}
217
218u32 ObjectFlamePoleFoot::FLAMEPOLE_COUNT = 0;
219
220} // namespace Field
Pertains to collision.
A 3D float vector.
Definition Vector.hh:88