A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectHanachan.hh
1#pragma once
2
3#include "game/field/ObjectCollisionSphere.hh"
4#include "game/field/SphereLink.hh"
5#include "game/field/StateManager.hh"
6#include "game/field/obj/ObjectCollidable.hh"
7
8namespace Kinoko::Field {
9
11class HanachanChainManager {
12public:
13 HanachanChainManager(const std::span<const f32> &linkDistances);
14 ~HanachanChainManager();
15
17 void init() {
18 for (auto &link : m_links) {
19 link.init();
20 }
21 }
22
23 void calc();
24
26 void setPos(size_t idx, const EGG::Vector3f &pos) {
27 ASSERT(idx < m_links.size());
28 m_links[idx].setPos(pos);
29 }
30
32 void setVel(size_t idx, const EGG::Vector3f &v) {
33 ASSERT(idx < m_links.size());
34 m_links[idx].setVel(v);
35 }
36
38 [[nodiscard]] const EGG::Vector3f &pos(size_t idx) const {
39 ASSERT(idx < m_links.size());
40 return m_links[idx].pos();
41 }
42
44 [[nodiscard]] const EGG::Vector3f &up(size_t idx) const {
45 ASSERT(idx < m_links.size());
46 return m_links[idx].up();
47 }
48
50 void addSpringForce(size_t idx, const EGG::Vector3f &v) {
51 ASSERT(idx < m_links.size());
52 m_links[idx].addSpringForce(v);
53 }
54
55private:
57 void calcConstraints() {
58 for (size_t i = 1; i < m_links.size(); ++i) {
59 m_links[i].calcConstraints(1.0f);
60 }
61 }
62
64};
65
66class ObjectHanachanPart : public ObjectCollidable {
67 friend class ObjectHanachan;
68
69public:
70 ObjectHanachanPart(const System::MapdataGeoObj &params) : ObjectCollidable(params) {}
71
72 ObjectHanachanPart(const char *name, const EGG::Vector3f &pos, const EGG::Vector3f &rot,
73 const EGG::Vector3f &scale)
74 : ObjectCollidable(name, pos, rot, scale) {}
75
77 ~ObjectHanachanPart() = default;
78
80 [[nodiscard]] u32 loadFlags() const override {
81 return 1;
82 }
83
85 [[nodiscard]] const char *getKclName() const override {
86 return "hanachan";
87 }
88
90 void loadRail() override {}
91
92private:
94 void calcTransformFromUpAndTangent(const EGG::Vector3f &pos, const EGG::Vector3f &up,
95 const EGG::Vector3f &tangent) {
97 SetRotTangentHorizontal(mat, up, tangent);
98 mat.setBase(3, pos);
99 setTransform(mat);
100 }
101};
102
103class ObjectHanachanHead final : public ObjectHanachanPart {
104public:
105 ObjectHanachanHead(const char *name, const EGG::Vector3f &pos, const EGG::Vector3f &rot,
106 const EGG::Vector3f &scale);
107 ~ObjectHanachanHead() override;
108
110 void createCollision() override {
111 m_collision = EGG::egg_new<ObjectCollisionSphere>(150.0f, collisionCenter());
112 }
113
114 void calcCollisionTransform() override;
115
116private:
117 EGG::Vector3f m_lastPos;
118};
119
120class ObjectHanachanBody final : public ObjectHanachanPart {
121 friend class ObjectHanachan;
122
123public:
124 ObjectHanachanBody(const System::MapdataGeoObj &params, const char *mdlName);
125 ObjectHanachanBody(const char *name, const EGG::Vector3f &pos, const EGG::Vector3f &rot,
126 const EGG::Vector3f &scale, const char *mdlName);
127 ~ObjectHanachanBody() override;
128
130 [[nodiscard]] const char *getKclName() const override {
131 return m_mdlName;
132 }
133
134 void calcCollisionTransform() override;
135
136protected:
137 const char *m_mdlName;
138 bool m_lastSegment;
139 EGG::Vector3f m_lastPos;
140
141private:
142 static constexpr std::array<const char *, 4> MDL_NAMES = {
143 "hanachan_body1",
144 "hanachan_body2",
145 "hanachan_body3",
146 "hanachan_body4",
147 };
148};
149
150class ObjectHanachan final : public ObjectCollidable, public StateManager {
151public:
152 ObjectHanachan(const System::MapdataGeoObj &params);
153 ~ObjectHanachan() override;
154
155 void init() override;
156
158 void calc() override {
159 calcRail();
160 StateManager::calc();
161 calcBody();
162 }
163
165 [[nodiscard]] u32 loadFlags() const override {
166 return 1;
167 }
168
170 void loadGraphics() override {}
171
173 void createCollision() override {}
174
175private:
176 enum class RailAlignment {
177 Aligned = -1,
178 Unknown = 0,
179 MisalignedLeft = 1,
180 MisalignedRight = 2,
181 };
182
183 void initWalk();
184
186 void initWait() {}
187
188 void calcWalk();
189 void calcWait();
190
191 void onSegmentEnd();
192 void calcRail();
193 void calcBody();
194 void initBody();
195 void initChain();
196 void clearChain();
198
200 void calcSlowMotion() {
201 constexpr f32 PERIOD = 50.0f;
202 constexpr f32 WAVELENGTH = 4000.0f;
203
204 calcLateralMotion(m_stillAngVel, PERIOD, WAVELENGTH, m_currentFrame);
205 }
206
208 void calcFastMotion(s32 frame) {
209 constexpr f32 AMPLITUDE = 25.0f;
210 constexpr f32 PERIOD = 300.0f;
211 constexpr f32 WAVELENGTH = 5500.0f;
212
213 calcLateralMotion(AMPLITUDE, PERIOD, WAVELENGTH, static_cast<s16>(frame));
214 }
215
216 void calcLateralMotion(f32 amplitude, f32 period, f32 wavelength, s16 frame);
217 [[nodiscard]] RailAlignment calcRailAlignment() const;
218
220 [[nodiscard]] bool shouldStartMoving() const {
221 return m_currentFrame > m_stillDuration;
222 }
223
225 void setMovingVel() {
226 m_railInterpolator->setCurrVel(m_movingVel);
227 }
228
229 [[nodiscard]] ObjectHanachanHead *&headPart() {
230 return reinterpret_cast<ObjectHanachanHead *&>(m_parts[0]);
231 }
232
233 [[nodiscard]] std::span<ObjectHanachanPart *> bodyParts() {
234 return std::span(m_parts.begin() + 1, m_parts.size() - 1);
235 }
236
237 std::array<ObjectHanachanPart *, 7> m_parts;
238 HanachanChainManager m_chain;
239 const f32 m_movingVel;
240 std::array<float, 7> m_partDisplacement;
241 u16 m_stillDuration;
243 bool m_still;
245 EGG::Vector3f m_right;
246 RailAlignment m_railAlignment;
247 RailAlignment m_prevRailAlignment;
248
250 static constexpr std::array<f32, 6> BODY_PART_DISTANCES = {{
251 360.0f,
252 510.0f,
253 510.0f,
254 480.0f,
255 510.0f,
256 510.0f,
257 }};
258
259 static constexpr std::array<StateManagerEntry, 2> STATE_ENTRIES = {{
260 {StateEntry<ObjectHanachan, &ObjectHanachan::initWalk, &ObjectHanachan::calcWalk>(0)},
261 {StateEntry<ObjectHanachan, &ObjectHanachan::initWait, &ObjectHanachan::calcWait>(1)},
262 }};
263};
264
265} // namespace Kinoko::Field
A 3 x 4 matrix.
Definition Matrix.hh:10
constexpr void setBase(size_t col, const Vector3f &base)
Sets one column of a matrix.
Definition Matrix.hh:230
Class that interfaces with the chain links corresponding to wiggler body parts.
f32 m_stillAngVel
Affects body part swaying when coming to a standstill.
u16 m_leftMisalignFrame
Frame at which the wiggler became left-misaligned from the rail.
void calcRailAlignmentMotion()
If the wiggler has moved out of alignment of the rail, then applies a lateral adjustment to the wiggl...
std::array< float, 7 > m_partDisplacement
Total distance between a given part and the head.
RailAlignment m_railAlignment
Captures when the wiggle takes sharp turns.
static constexpr std::array< f32, 6 > BODY_PART_DISTANCES
The distance between each body part link in the chain.
A contiguous storage container that manages the lifecycle of a buffer of a given size.
Definition Types.hh:31
Pertains to collision.
A 3D float vector.
Definition Vector.hh:107