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 Field {
9
12public:
13 HanachanChainManager(const std::span<const f32> &linkDistances);
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
63 std::span<SphereLink> m_links;
64};
65
67 friend class ObjectHanachan;
68
69public:
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:
93 void calcTransformFromUpAndTangent(const EGG::Vector3f &pos, const EGG::Vector3f &up,
94 const EGG::Vector3f &tangent);
95};
96
98public:
99 ObjectHanachanHead(const char *name, const EGG::Vector3f &pos, const EGG::Vector3f &rot,
100 const EGG::Vector3f &scale);
101 ~ObjectHanachanHead() override;
102
104 void createCollision() override {
105 m_collision = new ObjectCollisionSphere(150.0f, collisionCenter());
106 }
107
108 void calcCollisionTransform() override;
109
110private:
111 EGG::Vector3f m_lastPos;
112};
113
115 friend class ObjectHanachan;
116
117public:
118 ObjectHanachanBody(const System::MapdataGeoObj &params, const char *mdlName);
119 ObjectHanachanBody(const char *name, const EGG::Vector3f &pos, const EGG::Vector3f &rot,
120 const EGG::Vector3f &scale, const char *mdlName);
121 ~ObjectHanachanBody() override;
122
124 [[nodiscard]] const char *getKclName() const override {
125 return m_mdlName;
126 }
127
128 void calcCollisionTransform() override;
129
130protected:
131 const char *m_mdlName;
132 bool m_lastSegment;
133 EGG::Vector3f m_lastPos;
134
135private:
136 static constexpr std::array<const char *, 4> MDL_NAMES = {
137 "hanachan_body1",
138 "hanachan_body2",
139 "hanachan_body3",
140 "hanachan_body4",
141 };
142};
143
144class ObjectHanachan final : public ObjectCollidable, public StateManager {
145public:
147 ~ObjectHanachan() override;
148
149 void init() override;
150
152 void calc() override {
153 calcRail();
154 StateManager::calc();
155 calcBody();
156 }
157
159 [[nodiscard]] u32 loadFlags() const override {
160 return 1;
161 }
162
164 void loadGraphics() override {}
165
167 void createCollision() override {}
168
169private:
170 enum class RailAlignment {
171 Aligned = -1,
172 Unknown = 0,
173 MisalignedLeft = 1,
174 MisalignedRight = 2,
175 };
176
177 void initWalk();
178
180 void initWait() {}
181
182 void calcWalk();
183 void calcWait();
184
185 void onSegmentEnd();
186 void calcRail();
187 void calcBody();
188 void initBody();
189 void initChain();
190 void clearChain();
192
194 void calcSlowMotion() {
195 constexpr f32 PERIOD = 50.0f;
196 constexpr f32 WAVELENGTH = 4000.0f;
197
198 calcLateralMotion(m_stillAngVel, PERIOD, WAVELENGTH, m_currentFrame);
199 }
200
202 void calcFastMotion(s32 frame) {
203 constexpr f32 AMPLITUDE = 25.0f;
204 constexpr f32 PERIOD = 300.0f;
205 constexpr f32 WAVELENGTH = 5500.0f;
206
207 calcLateralMotion(AMPLITUDE, PERIOD, WAVELENGTH, static_cast<s16>(frame));
208 }
209
210 void calcLateralMotion(f32 amplitude, f32 period, f32 wavelength, s16 frame);
211 [[nodiscard]] RailAlignment calcRailAlignment() const;
212
214 [[nodiscard]] bool shouldStartMoving() const {
215 return m_currentFrame > m_stillDuration;
216 }
217
219 void setMovingVel() {
220 m_railInterpolator->setCurrVel(m_movingVel);
221 }
222
223 [[nodiscard]] ObjectHanachanHead *&headPart() {
224 return reinterpret_cast<ObjectHanachanHead *&>(m_parts[0]);
225 }
226
227 [[nodiscard]] std::span<ObjectHanachanPart *> bodyParts() {
228 return std::span(m_parts.begin() + 1, m_parts.size() - 1);
229 }
230
231 std::array<ObjectHanachanPart *, 7> m_parts;
232 HanachanChainManager m_chain;
233 const f32 m_movingVel;
234 std::array<float, 7> m_partDisplacement;
235 u16 m_stillDuration;
237 bool m_still;
239 EGG::Vector3f m_right;
240 RailAlignment m_railAlignment;
241 RailAlignment m_prevRailAlignment;
242
244 static constexpr std::array<f32, 6> BODY_PART_DISTANCES = {{
245 360.0f,
246 510.0f,
247 510.0f,
248 480.0f,
249 510.0f,
250 510.0f,
251 }};
252
253 static constexpr std::array<StateManagerEntry, 2> STATE_ENTRIES = {{
254 {StateEntry<ObjectHanachan, &ObjectHanachan::initWalk, &ObjectHanachan::calcWalk>(0)},
255 {StateEntry<ObjectHanachan, &ObjectHanachan::initWait, &ObjectHanachan::calcWait>(1)},
256 }};
257};
258
259} // namespace Field
Class that interfaces with the chain links corresponding to wiggler body parts.
RailAlignment m_railAlignment
Captures when the wiggle takes sharp turns.
u16 m_leftMisalignFrame
Frame at which the wiggler became left-misaligned from the rail.
f32 m_stillAngVel
Affects body part swaying when coming to a standstill.
std::array< float, 7 > m_partDisplacement
Total distance between a given part and the head.
static constexpr std::array< f32, 6 > BODY_PART_DISTANCES
The distance between each body part link in the chain.
void calcRailAlignmentMotion()
If the wiggler has moved out of alignment of the rail, then applies a lateral adjustment to the wiggl...
Base class that represents different "states" for an object.
Pertains to collision.
A 3D float vector.
Definition Vector.hh:88