A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectKuribo.cc
1#include "ObjectKuribo.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include <cmath>
6
7namespace Field {
8
10ObjectKuribo::ObjectKuribo(const System::MapdataGeoObj &params)
11 : ObjectCollidable(params), StateManager(this) {
12 m_animStep = static_cast<f32>(m_mapObj->setting(2)) / 100.0f;
13 m_speedStep = static_cast<f32>(m_mapObj->setting(1)) / 100.0f;
14}
15
17ObjectKuribo::~ObjectKuribo() = default;
18
20void ObjectKuribo::init() {
21 calcTransform();
22 m_origin = m_transform.base(2);
23
24 m_railInterpolator->init(0.0f, 0);
25 m_railInterpolator->setCurrVel(0.0f);
26
27 m_currSpeed = 0.0f;
28 m_animTimer = 0.0f;
29 m_frameCount = 0;
30
31 auto *anmMgr = m_drawMdl->anmMgr();
32 anmMgr->playAnim(0.0f, m_animStep, 0);
33 m_maxAnimTimer = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
34 m_nextStateId = 1;
35}
36
38void ObjectKuribo::calc() {
39 m_animTimer = ::fmodf(static_cast<f32>(m_frameCount) * m_animStep, m_maxAnimTimer);
40
41 if (m_nextStateId >= 0) {
42 m_currentStateId = m_nextStateId;
43 m_nextStateId = -1;
44 m_currentFrame = 0;
45
46 auto enterFunc = m_entries[m_entryIds[m_currentStateId]].onEnter;
47 (this->*enterFunc)();
48 } else {
49 ++m_currentFrame;
50 }
51
52 auto calcFunc = m_entries[m_entryIds[m_currentStateId]].onCalc;
53 (this->*calcFunc)();
54
55 ++m_frameCount;
56}
57
59void ObjectKuribo::loadAnims() {
60 std::array<const char *, 2> names = {{
61 "walk_l",
62 "walk_r",
63 }};
64
65 std::array<Render::AnmType, 2> types = {{
66 Render::AnmType::Chr,
67 Render::AnmType::Chr,
68 }};
69
70 linkAnims(names, types);
71}
72
73void ObjectKuribo::enterStateStub() {}
74
75void ObjectKuribo::calcStateStub() {}
76
79void ObjectKuribo::calcStateReroute() {
80 if (m_railInterpolator->curPoint().setting[0] < m_currentFrame) {
81 m_nextStateId = 1;
82 }
83
84 checkSphereFull();
85 calcRot();
86 setMatrixTangentTo(m_rot, m_origin);
87}
88
91void ObjectKuribo::calcStateWalk() {
92 calcAnim();
93}
94
96void ObjectKuribo::calcAnim() {
97 bool shouldMove;
98
99 if (m_railInterpolator->isMovementDirectionForward()) {
100 shouldMove = m_animTimer > 15.0f && m_animTimer < 25.0f;
101 } else {
102 shouldMove = m_animTimer > 45.0f && m_animTimer < 55.0f;
103 }
104
105 if (shouldMove) {
106 m_currSpeed = std::min(10.0f, m_currSpeed + m_speedStep);
107 } else {
108 m_currSpeed = std::max(0.0f, m_currSpeed - m_speedStep);
109 }
110
111 m_railInterpolator->setCurrVel(m_currSpeed);
112 m_flags |= 1;
113 const auto &curPos = m_railInterpolator->curPos();
114 m_pos.x = curPos.x;
115 m_pos.z = curPos.z;
116
117 if (m_railInterpolator->calc() == RailInterpolator::Status::ChangingDirection) {
118 m_nextStateId = 0;
119 m_currSpeed = 0.0f;
120 }
121
122 checkSphereFull();
123 calcRot();
124 setMatrixTangentTo(m_rot, m_origin);
125}
126
128void ObjectKuribo::calcRot() {
129 m_rot = interpolate(0.1f, m_rot, m_floorNrm);
130
131 if (m_rot.squaredLength() > std::numeric_limits<f32>::epsilon()) {
132 m_rot.normalise2();
133 } else {
134 m_rot = EGG::Vector3f::ey;
135 }
136}
137
139void ObjectKuribo::checkSphereFull() {
140 constexpr f32 RADIUS = 50.0f;
141
142 // Apply gravity if we're not changing direction
143 if (m_currentStateId != 0) {
144 m_flags |= 1;
145 m_pos.y -= 2.0f;
146 }
147
148 CollisionInfo colInfo;
149 EGG::Vector3f pos = m_pos;
150 pos.y += RADIUS;
151
152 bool hasCol = CollisionDirector::Instance()->checkSphereFull(RADIUS, pos, EGG::Vector3f::inf,
153 KCL_TYPE_FLOOR, &colInfo, nullptr, 0);
154
155 if (hasCol) {
156 m_pos += colInfo.tangentOff;
157 m_flags |= 1;
158
159 if (colInfo.floorDist > -std::numeric_limits<f32>::min()) {
160 m_floorNrm = colInfo.floorNrm;
161 }
162 }
163}
164
166EGG::Vector3f ObjectKuribo::interpolate(f32 scale, const EGG::Vector3f &v0,
167 const EGG::Vector3f &v1) const {
168 return v0 + (v1 - v0) * scale;
169}
170
171const std::array<StateManagerEntry<ObjectKuribo>, 4> StateManager<ObjectKuribo>::STATE_ENTRIES = {{
172 {0, &ObjectKuribo::enterStateStub, &ObjectKuribo::calcStateReroute},
173 {1, &ObjectKuribo::enterStateStub, &ObjectKuribo::calcStateWalk},
174 {2, &ObjectKuribo::enterStateStub, &ObjectKuribo::calcStateStub},
175 {3, &ObjectKuribo::enterStateStub, &ObjectKuribo::calcStateStub},
176}};
177
178StateManager<ObjectKuribo>::StateManager(ObjectKuribo *obj) {
179 constexpr size_t ENTRY_COUNT = 4;
180
181 m_obj = obj;
182 m_entries = std::span{STATE_ENTRIES};
183 m_entryIds = std::span(new u16[ENTRY_COUNT], ENTRY_COUNT);
184
185 // The base game initializes all entries to 0xffff, possibly to avoid an uninitialized value
186 for (auto &id : m_entryIds) {
187 id = 0xffff;
188 }
189
190 for (size_t i = 0; i < m_entryIds.size(); ++i) {
191 m_entryIds[STATE_ENTRIES[i].id] = i;
192 }
193}
194
195StateManager<ObjectKuribo>::~StateManager() {
196 delete[] m_entryIds.data();
197}
198
199} // namespace Field
#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:83