A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectHanachan.cc
1#include "ObjectHanachan.hh"
2
3#include "game/field/ObjectDirector.hh"
4
5namespace Kinoko::Field {
6
8HanachanChainManager::HanachanChainManager(const std::span<const f32> &linkDistances) {
9 size_t count = linkDistances.size() + 1;
10
11 m_links = owning_span<Field::SphereLink>(count);
12 m_links[0].initLinkLen(linkDistances[0]);
13
14 for (size_t i = 1; i < count - 1; ++i) {
15 m_links[i].initLinkLen(linkDistances[i]);
16 m_links[i - 1].setNext(&m_links[i]);
17 m_links[i].setPrev(&m_links[i - 1]);
18 }
19
20 auto &last = m_links.back();
21 auto &secondToLast = m_links[count - 2];
22 last.initLinkLen(0.0f);
23 secondToLast.setNext(&last);
24 last.setPrev(&secondToLast);
25}
26
28HanachanChainManager::~HanachanChainManager() = default;
29
31void HanachanChainManager::calc() {
32 for (u32 i = 0; i < 2; ++i) {
33 for (auto &link : m_links) {
34 link.calc();
35 }
36
37 for (auto &link : m_links) {
38 link.calcPos();
39 }
40 }
41
42 for (size_t i = 0; i < m_links.size() - 1; ++i) {
43 EGG::Vector3f delta = m_links[i].pos() - m_links[i + 1].pos();
44 f32 len = m_links[i].linkLen();
45
46 if (delta.squaredLength() - len * len > 0.0f) {
47 calcConstraints();
48 break;
49 }
50 }
51
52 for (auto &link : m_links) {
53 link.checkCollision();
54 }
55}
56
58void ObjectHanachanPart::calcTransformFromUpAndTangent(const EGG::Vector3f &pos,
59 const EGG::Vector3f &up, const EGG::Vector3f &tangent) {
60 EGG::Matrix34f mat;
61 SetRotTangentHorizontal(mat, up, tangent);
62 m_flags.setBit(eFlags::Matrix);
63 m_transform = mat;
64 m_transform.setBase(3, pos);
65 m_pos = pos;
66}
67
69ObjectHanachanHead::ObjectHanachanHead(const char *name, const EGG::Vector3f &pos,
70 const EGG::Vector3f &rot, const EGG::Vector3f &scale)
71 : ObjectHanachanPart(name, pos, rot, scale), m_lastPos(EGG::Vector3f::zero) {}
72
74ObjectHanachanHead::~ObjectHanachanHead() = default;
75
77void ObjectHanachanHead::calcCollisionTransform() {
78 calcTransform();
79
80 EGG::Matrix34f trans = m_transform;
81 EGG::Vector3f scaledUp = trans.base(1) * 330.0f * m_scale.y;
82 EGG::Vector3f scaledForward = trans.base(2) * 100.0f * m_scale.y;
83 trans.setBase(3, m_pos + scaledUp + scaledForward);
84 EGG::Vector3f speed = m_pos - m_lastPos;
85
86 m_collision->transform(trans, m_scale, speed);
87 m_lastPos = m_pos;
88}
89
90ObjectHanachanBody::ObjectHanachanBody(const System::MapdataGeoObj &params, const char *mdlName)
91 : ObjectHanachanPart(params), m_mdlName(mdlName), m_lastSegment(false),
92 m_lastPos(EGG::Vector3f::zero) {}
93
94ObjectHanachanBody::ObjectHanachanBody(const char *name, const EGG::Vector3f &pos,
95 const EGG::Vector3f &rot, const EGG::Vector3f &scale, const char *mdlName)
96 : ObjectHanachanPart(name, pos, rot, scale), m_mdlName(mdlName), m_lastSegment(false),
97 m_lastPos(EGG::Vector3f::zero) {}
98
100ObjectHanachanBody::~ObjectHanachanBody() = default;
101
103void ObjectHanachanBody::calcCollisionTransform() {
104 if (!m_lastSegment) {
105 ObjectCollidable::calcCollisionTransform();
106 return;
107 }
108
109 EGG::Matrix34f trans = m_transform;
110 trans.setBase(3, m_pos + trans.base(2) * 80.0f * m_scale.y);
111 EGG::Vector3f posDelta = m_pos - m_lastPos;
112
113 m_collision->transform(trans, m_scale, posDelta);
114 m_lastPos = m_pos;
115}
116
118ObjectHanachan::ObjectHanachan(const System::MapdataGeoObj &params)
119 : ObjectCollidable(params), StateManager(this, STATE_ENTRIES), m_chain(BODY_PART_DISTANCES),
120 m_movingVel(static_cast<f32>(static_cast<s16>(params.setting(0)))) {
121 constexpr f32 SCALE = 3.0f;
122 constexpr EGG::Vector3f SCALE_VEC = EGG::Vector3f(SCALE, SCALE, SCALE);
123
124 auto *&head = headPart();
125 head = new ObjectHanachanHead("BossHanachanHead", EGG::Vector3f::zero, EGG::Vector3f::ez,
126 EGG::Vector3f::ez);
127 head->setScale(SCALE_VEC);
128
129 const auto &mdlNames = ObjectHanachanBody::MDL_NAMES;
130 size_t mdlNameCount = ObjectHanachanBody::MDL_NAMES.size();
131 auto parts = bodyParts();
132 for (size_t i = 0; i < parts.size(); ++i) {
133 auto *&part = parts[i];
134 part = new ObjectHanachanBody(params, mdlNames[i % mdlNameCount]);
135 part->setScale(SCALE_VEC);
136 }
137
138 head->load();
139
140 const auto &flowTable = ObjectDirector::Instance()->flowTable();
141 for (size_t i = 0; i < parts.size(); ++i) {
142 auto *&part = parts[i];
143 part->load();
144
145 const auto *collisionSet = flowTable.set(flowTable.slot(part->id()));
146 f32 radius = SCALE * static_cast<f32>(parse<s16>(collisionSet->params.sphere.radius));
147 part->resize(radius, 0.0f);
148 }
149
150 m_partDisplacement[0] = 0.0f;
151 for (size_t i = 1; i < m_partDisplacement.size(); ++i) {
152 m_partDisplacement[i] = m_partDisplacement[i - 1] + BODY_PART_DISTANCES[i - 1];
153 }
154}
155
157ObjectHanachan::~ObjectHanachan() = default;
158
160void ObjectHanachan::init() {
161 m_railInterpolator->init(0.0f, 0);
162 m_railInterpolator->setCurrVel(m_movingVel);
163
164 initBody();
165
166 m_still = false;
167 m_stillAngVel = 15.0f;
168 m_leftMisalignFrame = 0;
169 m_right = EGG::Vector3f::ez;
170 m_railAlignment = RailAlignment::Unknown;
171 m_prevRailAlignment = RailAlignment::Unknown;
172
173 reinterpret_cast<ObjectHanachanBody *>(m_parts.back())->m_lastSegment = true;
174
175 initChain();
176}
177
179void ObjectHanachan::initWalk() {
180 setMovingVel();
181 m_stillAngVel = 15.0f;
182 m_still = false;
183 m_leftMisalignFrame = 0;
184}
185
187void ObjectHanachan::calcWalk() {
188 if (m_still) {
189 m_railInterpolator->setCurrVel(0.0f);
190 m_nextStateId = 1;
191 }
192
193 m_prevRailAlignment = m_railAlignment;
194 m_railAlignment = calcRailAlignment();
195
196 clearChain();
197 calcRailAlignmentMotion();
198 m_chain.calc();
199
200 m_stillAngVel = 15.0f;
201}
202
204void ObjectHanachan::calcWait() {
205 if (shouldStartMoving()) {
206 m_nextStateId = 0;
207 }
208
209 clearChain();
210
211 if (m_stillAngVel >= 0.0f) {
212 m_stillAngVel -= 0.25f;
213 } else {
214 m_stillAngVel += 0.25f;
215 }
216
217 if (EGG::Mathf::abs(m_stillAngVel) <= 1.0f) {
218 m_stillAngVel = 0.0f;
219 }
220
221 calcSlowMotion();
222
223 m_chain.calc();
224}
225
227void ObjectHanachan::onSegmentEnd() {
228 u16 setting = m_railInterpolator->curPoint().setting[0];
229 if (setting != 0) {
230 m_still = true;
231 m_stillDuration = setting;
232 }
233}
234
236void ObjectHanachan::calcRail() {
237 m_right = m_railInterpolator->curTangentDir();
238
239 if (m_railInterpolator->calc() == RailInterpolator::Status::SegmentEnd) {
240 onSegmentEnd();
241 }
242}
243
245void ObjectHanachan::calcBody() {
246 auto *&head = headPart();
247 head->calcTransform();
248 EGG::Vector3f forward = head->m_transform.base(2);
249 EGG::Vector3f dir = Interpolate(0.1f, forward, m_railInterpolator->curTangentDir());
250 head->calcTransformFromUpAndTangent(m_chain.pos(0), m_chain.up(0), dir);
251
252 auto parts = bodyParts();
253 for (size_t i = 0; i < parts.size(); ++i) {
254 const EGG::Vector3f &pos = m_chain.pos(i + 1);
255 dir = m_chain.pos(i) - pos;
256 dir.normalise2();
257 parts[i]->calcTransformFromUpAndTangent(pos, m_chain.up(i + 1), dir);
258 }
259}
260
262void ObjectHanachan::initBody() {
263 headPart()->setPos(m_railInterpolator->curPos());
264
265 const EGG::Vector3f &curTanDir = m_railInterpolator->curTangentDir();
266 for (size_t i = 1; i < m_parts.size(); ++i) {
267 m_parts[i]->setPos(m_parts[i - 1]->pos() - curTanDir * BODY_PART_DISTANCES[i - 1]);
268 m_parts[i]->setMatrixTangentTo(EGG::Vector3f::ey, curTanDir);
269 }
270}
271
273void ObjectHanachan::initChain() {
274 m_chain.init();
275
276 for (size_t i = 0; i < m_parts.size(); ++i) {
277 m_chain.setPos(i, m_parts[i]->pos());
278 }
279}
280
282void ObjectHanachan::clearChain() {
283 m_chain.setPos(0, m_railInterpolator->curPos());
284 m_chain.setVel(0, EGG::Vector3f::zero);
285 m_chain.addSpringForce(0, EGG::Vector3f::ey * SphereLink::Gravity());
286}
287
291void ObjectHanachan::calcRailAlignmentMotion() {
292 constexpr u16 MISALIGNMENT_CORRECTION_DURATION = 80;
293
294 bool becameUnaligned = m_prevRailAlignment == RailAlignment::Aligned &&
295 m_railAlignment != RailAlignment::Aligned;
296
297 if (becameUnaligned && m_railAlignment == RailAlignment::MisalignedLeft) {
298 m_leftMisalignFrame = m_currentFrame;
299 }
300
301 if (m_leftMisalignFrame != 0 && m_currentFrame >= m_leftMisalignFrame &&
302 m_currentFrame <
303 static_cast<u32>(m_leftMisalignFrame + MISALIGNMENT_CORRECTION_DURATION)) {
304 calcFastMotion(m_currentFrame - m_leftMisalignFrame);
305 } else {
306 calcSlowMotion();
307 }
308}
309
311void ObjectHanachan::calcLateralMotion(f32 amplitude, f32 period, f32 wavelength, s16 frame) {
312 f32 velAmplitude = F_TAU * amplitude / period;
313
314 auto parts = bodyParts();
315 for (size_t i = 0; i < parts.size(); ++i) {
316 auto *&part = parts[i];
317 f32 phase =
318 F_TAU * (static_cast<f32>(frame) / period - m_partDisplacement[i + 1] / wavelength);
319 part->calcTransform();
320 EGG::Vector3f right = RotateXZByYaw(HALF_PI, part->m_transform.base(2));
321 EGG::Vector3f posOffset = right * (amplitude * EGG::Mathf::SinFIdx(RAD2FIDX * phase));
322 m_chain.setPos(i + 1, m_parts[i + 1]->pos() + posOffset);
323 m_chain.setVel(i + 1, right * (velAmplitude * EGG::Mathf::CosFIdx(RAD2FIDX * phase)));
324 }
325}
326
328ObjectHanachan::RailAlignment ObjectHanachan::calcRailAlignment() const {
329 constexpr f32 EPSILON = 0.9995f;
330
331 EGG::Vector3f curTanDir = m_railInterpolator->curTangentDir();
332 EGG::Vector2f railTan = EGG::Vector2f(curTanDir.x, curTanDir.z);
333 EGG::Vector2f right = EGG::Vector2f(m_right.x, m_right.z);
334 railTan.normalise2();
335 right.normalise2();
336
337 if (railTan.dot(right) >= EPSILON) {
338 return RailAlignment::Aligned;
339 }
340
341 return right.cross(railTan) < 0.0f ? RailAlignment::MisalignedLeft :
342 RailAlignment::MisalignedRight;
343}
344
345} // namespace Kinoko::Field
constexpr void setBase(size_t col, const Vector3f &base)
Sets one column of a matrix.
Definition Matrix.hh:230
Pertains to collision.
constexpr TBitFlag< T, E > & setBit(Es... es)
Sets the corresponding bits for the provided enum values.
Definition BitFlag.hh:64
A 3D float vector.
Definition Vector.hh:107