A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
JugemUnit.cc
1#include "JugemUnit.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/kart/KartMove.hh"
6#include "game/kart/KartObjectManager.hh"
7
8#include "game/system/RaceManager.hh"
9
10namespace Kinoko::Field {
11
13JugemUnit::JugemUnit(const Kart::KartObject *kartObj)
14 : StateManager(this, STATE_ENTRIES), m_kartObj(kartObj), m_switchReverse(nullptr) {
15 m_move = new JugemMove(kartObj);
16 m_interp = new JugemInterp(2);
17}
18
20JugemUnit::~JugemUnit() {
21 delete m_switchReverse;
22 delete m_move;
23 delete m_interp;
24}
25
27void JugemUnit::calc() {
28 calcSwitches();
29
30 StateManager::calc();
31
32 // Perform a collision check if Lakitu is not idle
33 if (m_currentStateId != 0) {
34 setPosFromTransform(m_move->transform());
35 calcCollision();
36 }
37}
38
40void JugemUnit::enterReverse() {
41 constexpr EGG::Vector3f INIT_POS_OFFSET = EGG::Vector3f(0.0f, 2000.0f, 0.0f);
42
43 m_state = State::Descending;
44 m_interp->initKeyframes(0.0f, 1.0f, 40.0f, 3);
45 m_move->init();
46 EGG::Vector3f pos = transformLocalToWorldUpright(INIT_POS_OFFSET);
47 m_move->setPos(pos, true);
48 m_move->setForwardFromKartObjPosDelta(true);
49 m_move->setDescending(false);
50}
51
53void JugemUnit::calcReverse() {
54 constexpr EGG::Vector3f AWAY_LOCAL_POS = EGG::Vector3f(0.0f, 2000.0f, 0.0f);
55 constexpr EGG::Vector3f DESCEND_LOCAL_POS = EGG::Vector3f(0.0f, 500.0f, 0.0f);
56 constexpr EGG::Vector3f SLOW_RISE_VEL = EGG::Vector3f(0.0f, 30.0f, 0.0f);
57 constexpr EGG::Vector3f FAST_RISE_VEL = EGG::Vector3f(0.0f, 80.0f, 0.0f);
58 constexpr EGG::Vector3f STAY_LOCAL_POS = EGG::Vector3f(0.0f, 250.0f, 350.0f);
59
60 constexpr f32 INTERP_RATE_START = 0.0f;
61 constexpr f32 INTERP_RATE_END = 1.0f;
62 constexpr f32 AWAY_INTERP_RATE_DURATION = 40.0f;
63 constexpr f32 STAY_INTERP_RATE_DURATION = 70.0f;
64
65 EGG::Vector3f local_40 = m_kartObj->pos() - m_move->transPos();
66
67 switch (m_state) {
68 case State::Away: {
69 bool isDoneInterpolating = m_interp->calc(1.0f);
70 EGG::Vector3f localPos = Interpolate(m_interp->rate(), AWAY_LOCAL_POS, DESCEND_LOCAL_POS);
71 m_move->setAwayOrDescending(true);
72 m_move->setAnchorPos(transformLocalToWorldUpright(localPos));
73 m_move->setForwardFromKartObjMainRot(true);
74
75 if (isDoneInterpolating) {
76 m_move->setDescending(true);
77 m_interp->initKeyframes(INTERP_RATE_START, INTERP_RATE_END, AWAY_INTERP_RATE_DURATION,
78 3);
79 m_state = State::Descending;
80 }
81 } break;
82 case State::Descending: {
83 bool isDoneInterpolating = m_interp->calc(1.0f);
84 EGG::Vector3f localPos = Interpolate(m_interp->rate(), DESCEND_LOCAL_POS, STAY_LOCAL_POS);
85 m_move->setAwayOrDescending(true);
86 m_move->setAnchorPos(transformLocalToWorldUpright(localPos));
87 m_move->setForwardFromKartObjMainRot(true);
88
89 if (isDoneInterpolating) {
90 m_state = State::Stay;
91 }
92 } break;
93 case State::Stay: {
94 m_move->setAwayOrDescending(false);
95 m_move->setAnchorPos(transformLocalToWorldUpright(STAY_LOCAL_POS));
96 m_move->setForwardFromKartObjPosDelta(false);
97
98 if (!m_switchReverse->isOn() || local_40.length() > 2000.0f) {
99 m_interp->initKeyframes(INTERP_RATE_START, INTERP_RATE_END, STAY_INTERP_RATE_DURATION,
100 3);
101 m_move->setDescending(false);
102 m_ascendTimer = 0;
103 m_state = State::Ascending;
104 }
105 } break;
106 case State::Ascending: {
107 bool isDoneInterpolating = m_interp->calc(1.0f);
108
109 m_move->setRiseVel(++m_ascendTimer < 10 ? SLOW_RISE_VEL : FAST_RISE_VEL);
110 m_move->setRising(true);
111
112 if (isDoneInterpolating) {
113 m_nextStateId = 0;
114 }
115 } break;
116 }
117
118 m_move->calc();
119}
120
122EGG::Vector3f JugemUnit::transformLocalToWorldUpright(const EGG::Vector3f &v) const {
123 const EGG::Vector3f &vel1Dir = m_kartObj->move()->vel1Dir();
124 const EGG::Quatf &mainRot = m_kartObj->mainRot();
125
126 EGG::Vector3f vStack88 = mainRot.rotateVector(EGG::Vector3f::ez);
127 const EGG::Vector3f &pos = m_kartObj->pos();
128 EGG::Vector3f up = EGG::Vector3f::ey;
129 EGG::Vector3f local_a0 = vel1Dir + vStack88;
130 local_a0.normalise2();
131 EGG::Vector3f right = up.cross(local_a0);
132 right.normalise2();
133
134 if (right.squaredLength() <= std::numeric_limits<f32>::epsilon()) {
135 right = EGG::Vector3f::ex;
136 }
137
138 EGG::Vector3f forward = right.cross(up);
139 forward.normalise2();
140
141 EGG::Matrix34f mat;
142 mat.setBase(0, right);
143 mat.setBase(1, up);
144 mat.setBase(2, forward);
145 mat.setBase(3, pos);
146
147 return mat.ps_multVector(v);
148}
149
151void JugemUnit::calcCollision() {
152 constexpr f32 RADIUS = 150.0f;
153
154 CollisionInfoPartial colInfo;
155 KCLTypeMask maskOut;
156
157 // We ignore the result of the collision check. This check is simply here so that any
158 // resulting collisions can cause updates to nearby objects.
159 std::ignore = CollisionDirector::Instance()->checkSpherePartialPush(RADIUS, m_pos,
160 EGG::Vector3f::inf, KCL_TYPE_FLOOR, &colInfo, &maskOut, 0);
161}
162
163} // namespace Kinoko::Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
Pertains to collision.