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 Kinoko::Field {
8
10ObjectKuribo::ObjectKuribo(const System::MapdataGeoObj &params)
11 : ObjectCollidable(params), StateManager(this, STATE_ENTRIES) {
12 ASSERT(m_mapObj);
13 m_animStep = static_cast<f32>(m_mapObj->setting(2)) / 100.0f;
14 m_speedStep = static_cast<f32>(m_mapObj->setting(1)) / 100.0f;
15
16 // Not initialized here in the base game because normally the game's heaps are zero-initialized
17 m_rot = EGG::Vector3f::zero;
18 m_floorNrm = EGG::Vector3f::zero;
19}
20
22ObjectKuribo::~ObjectKuribo() = default;
23
25void ObjectKuribo::init() {
26 calcTransform();
27 m_origin = transform().base(2);
28
29 m_railInterpolator->init(0.0f, 0);
30 m_railInterpolator->setCurrVel(0.0f);
31
32 m_currSpeed = 0.0f;
33 m_animTimer = 0.0f;
34 m_frameCount = 0;
35
36 auto *anmMgr = m_drawMdl->anmMgr();
37 anmMgr->playAnim(0.0f, m_animStep, 0);
38 m_maxAnimTimer = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
39 m_nextStateId = 1;
40}
41
43void ObjectKuribo::calc() {
44 m_animTimer = ::fmodf(static_cast<f32>(m_frameCount) * m_animStep, m_maxAnimTimer);
45
46 StateManager::calc();
47
48 ++m_frameCount;
49}
50
52void ObjectKuribo::loadAnims() {
53 std::array<const char *, 2> names = {{
54 "walk_l",
55 "walk_r",
56 }};
57
58 std::array<Render::AnmType, 2> types = {{
59 Render::AnmType::Chr,
60 Render::AnmType::Chr,
61 }};
62
63 linkAnims(names, types);
64}
65
66void ObjectKuribo::enterStateStub() {}
67
68void ObjectKuribo::calcStateStub() {}
69
73 if (m_railInterpolator->curPoint().setting[0] < m_currentFrame) {
74 m_nextStateId = 1;
75 }
76
77 checkSphereFull();
78 calcRot();
79 setMatrixTangentTo(m_rot, m_origin);
80}
81
85 calcAnim();
86}
87
89void ObjectKuribo::calcAnim() {
90 bool shouldMove;
91
92 if (m_railInterpolator->isMovementDirectionForward()) {
93 shouldMove = m_animTimer > 15.0f && m_animTimer < 25.0f;
94 } else {
95 shouldMove = m_animTimer > 45.0f && m_animTimer < 55.0f;
96 }
97
98 if (shouldMove) {
99 m_currSpeed = std::min(10.0f, m_currSpeed + m_speedStep);
100 } else {
101 m_currSpeed = std::max(0.0f, m_currSpeed - m_speedStep);
102 }
103
104 m_railInterpolator->setCurrVel(m_currSpeed);
105 const auto &curPos = m_railInterpolator->curPos();
106 setPos(EGG::Vector3f(curPos.x, pos().y, curPos.z));
107
108 if (m_railInterpolator->calc() == RailInterpolator::Status::ChangingDirection) {
109 m_nextStateId = 0;
110 m_currSpeed = 0.0f;
111 }
112
113 checkSphereFull();
114 calcRot();
115 setMatrixTangentTo(m_rot, m_origin);
116}
117
119void ObjectKuribo::calcRot() {
120 m_rot = Interpolate(0.1f, m_rot, m_floorNrm);
121
122 if (m_rot.squaredLength() > std::numeric_limits<f32>::epsilon()) {
123 m_rot.normalise2();
124 } else {
125 m_rot = EGG::Vector3f::ey;
126 }
127}
128
130void ObjectKuribo::checkSphereFull() {
131 constexpr f32 RADIUS = 50.0f;
132
133 // Apply gravity if we're not changing direction
134 if (m_currentStateId != 0) {
135 subPos(EGG::Vector3f(0.0f, 2.0f, 0.0f));
136 }
137
138 CollisionInfo colInfo;
139 EGG::Vector3f colPos = pos();
140 colPos.y += RADIUS;
141
142 bool hasCol = CollisionDirector::Instance()->checkSphereFull(RADIUS, colPos, EGG::Vector3f::inf,
143 KCL_TYPE_FLOOR, &colInfo, nullptr, 0);
144
145 if (hasCol) {
146 addPos(colInfo.tangentOff);
147
148 if (colInfo.floorDist > -std::numeric_limits<f32>::min()) {
149 m_floorNrm = colInfo.floorNrm;
150 }
151 }
152}
153
154} // namespace Kinoko::Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
void calcStateWalk()
Called when Goomba is walking along the rail.
void calcStateReroute()
Called when the Goomba is changing direction.
Base class that represents different "states" for an object.
Pertains to collision.