A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartCamera.cc
1#include "KartCamera.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5namespace Kinoko::Render {
6
8void KartCamera::calc() {
9 constexpr f32 HOP_POS_INTERP_RATE = 0.8f;
10 constexpr f32 FORWARD_INTERP_RATE = 0.35f;
11 constexpr f32 HORIZ_POS_INTERP_RATE = 0.05f;
12 constexpr f32 VERT_POS_INTERP_RATE = 0.03f;
13 constexpr f32 FAST_VERT_POS_INTERP_RATE = 0.1f;
14
15 const auto *kartObj = Kart::KartObjectManager::Instance()->object(0);
16 EGG::Vector3f targetPos = kartObj->pos();
17 m_hopPosY += HOP_POS_INTERP_RATE * (kartObj->move()->hopPosY() - m_hopPosY);
18 targetPos.y -= m_hopPosY;
19
20 calcForward(FORWARD_INTERP_RATE, kartObj);
21 calcDriftOffset(kartObj);
22
23 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
24 m_forwardCamera, false, kartObj, targetPos);
25 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
26 m_backwardCamera, true, kartObj, targetPos);
27
28 calcCollision(m_forwardCamera, false);
29 calcCollision(m_backwardCamera, true);
30}
31
32KartCamera *KartCamera::CreateInstance() {
33 ASSERT(!s_instance);
34 s_instance = new KartCamera;
35 return s_instance;
36}
37
38void KartCamera::DestroyInstance() {
39 ASSERT(s_instance);
40 auto *instance = s_instance;
41 s_instance = nullptr;
42 delete instance;
43}
44
46KartCamera::KartCamera() : m_hopPosY(0), m_forward(EGG::Vector3f::zero), m_camParams(nullptr) {}
47
49KartCamera::~KartCamera() = default;
50
52void KartCamera::calcDriftOffset(const Kart::KartObjectProxy *proxy) {
53 constexpr f32 MAX_DRIFT_YAW_AUTOMATIC = 10.0f;
54 constexpr f32 MAX_DRIFT_YAW_MANUAL = 15.0f;
55 constexpr f32 YAW_STEP_AUTOMATIC = 0.5f;
56 constexpr f32 YAW_STEP_MANUAL = 1.0f;
57
58 const auto &status = proxy->status();
59 if (status.onBit(Kart::eStatus::DriftManual, Kart::eStatus::Hop)) {
60 f32 yaw = static_cast<f32>(proxy->hopStickX()) * -0.5f;
61 if (proxy->vehicleType() == Kart::KartParam::Stats::DriftType::Inside_Drift_Bike) {
62 yaw *= -1.0f;
63 }
64 m_driftYaw += yaw;
65
66 f32 yawMax = status.onBit(Kart::eStatus::AutoDrift) ? MAX_DRIFT_YAW_AUTOMATIC :
67 MAX_DRIFT_YAW_MANUAL;
68 f32 pitch = 90.0f - RAD2DEG * EGG::Mathf::acos(m_forward.dot(EGG::Vector3f::ey));
69 if (pitch < 0.0f) {
70 yawMax += 0.1f * EGG::Mathf::abs(pitch);
71 }
72
73 m_driftYaw = std::clamp(m_driftYaw, -yawMax, yawMax);
74 } else if (m_driftYaw != 0.0f) {
75 f32 yawStep = status.onBit(Kart::eStatus::AutoDrift) ? YAW_STEP_AUTOMATIC : YAW_STEP_MANUAL;
76 if (m_driftYaw > 0.0f) {
77 m_driftYaw = std::max(0.0f, m_driftYaw - yawStep);
78 } else {
79 m_driftYaw = std::min(0.0f, m_driftYaw + yawStep);
80 }
81 }
82}
83
85void KartCamera::calcCamera(f32 horizInterpRate, f32 vertInterpRate, f32 fastVertInterpRate,
86 KartCameraState &state, bool isBackwards, const Kart::KartObjectProxy *proxy,
87 const EGG::Vector3f &targetPos) const {
88 constexpr f32 BIG_AIR_PITCH_CAP = 89.0f * DEG2RAD;
89
90 EGG::Vector3f forwardDir = isBackwards ? -m_forward : m_forward;
91 EGG::Vector3f pitchAxis = m_right.cross(forwardDir);
92 pitchAxis.normalise();
93
94 f32 driftYaw = DEG2RAD * m_driftYaw;
95
96 const auto &status = proxy->status();
97 if (status.onBit(Kart::eStatus::AutoDrift)) {
98 driftYaw *= -1.0f;
99 }
100 f32 bigAirPitch = std::min(BIG_AIR_PITCH_CAP, state.m_bigAirFallPitch);
101
102 EGG::Matrix34f bigAirPitchMat;
103 EGG::Matrix34f yawRotMat;
104 yawRotMat.setAxisRotation(driftYaw, m_right);
105 bigAirPitchMat.setAxisRotation(bigAirPitch, pitchAxis);
106 EGG::Vector3f orbitDir = yawRotMat.ps_multVector(bigAirPitchMat.ps_multVector(forwardDir));
107
108 f32 pitch = 90.0f -
109 RAD2DEG * EGG::Mathf::acos(std::clamp(orbitDir.dot(EGG::Vector3f::ey), -1.0f, 1.0f));
110
111 // If camera is looking downwards
112 if (pitch > 0.0f) {
113 EGG::Matrix34f downPitchMat;
114 f32 fVar16 = status.onBit(Kart::eStatus::TouchingGround) ? 0.1f : 0.6f;
115 state.m_1c = state.m_1c + 0.2f * (fVar16 - state.m_1c);
116 downPitchMat.setAxisRotation(DEG2RAD * pitch * state.m_1c, pitchAxis);
117 orbitDir = downPitchMat.ps_multVector(orbitDir);
118 }
119 orbitDir *= -1.0f;
120 calcAirtimeHeight(state, proxy);
121 state.m_pos += targetPos - state.m_targetPos;
122 EGG::Vector3f posOffset = state.m_dist * orbitDir;
123 posOffset.y += m_camParams->posY - proxy->cameraDistY() + state.m_bigAirHeight;
124
125 EGG::Vector3f horizDelta = targetPos + posOffset - state.m_pos;
126 f32 vertDelta = horizDelta.y;
127 horizDelta.y = 0.0f;
128 state.m_pos += horizInterpRate * horizDelta;
129
130 if (status.onBit(Kart::eStatus::TouchingGround) && proxy->speed() > 30.0f && pitch > 15.0f) {
131 vertInterpRate = fastVertInterpRate;
132 }
133 state.m_pos.y += vertDelta * vertInterpRate;
134
135 EGG::Vector3f targetDelta = state.m_pos - targetPos;
136 if (targetDelta.ps_length() != 0.0f) {
137 state.m_pos = targetPos + state.m_dist * targetDelta.ps_normalize();
138 }
139
140 state.m_targetPos = targetPos;
141}
142
144void KartCamera::calcAirtimeHeight(KartCameraState &state,
145 const Kart::KartObjectProxy *proxy) const {
146 constexpr f32 BIG_AIR_HEIGHT_CAP = 300.0f;
147
148 f32 targetPitch = 0.0f;
149 f32 interpRate = 0.2f;
150 const auto &status = proxy->status();
151
152 if (status.onBit(Kart::eStatus::AirtimeOver20)) {
153 state.m_bigAirHeight = std::min(BIG_AIR_HEIGHT_CAP, state.m_bigAirHeight + 10.0f);
154
155 const EGG::Vector3f &vel = proxy->velocity();
156 if (vel.y < 0.0f) {
157 targetPitch = std::min(0.3f, 0.005f * -vel.y);
158 }
159 interpRate = 0.03f;
160 } else {
161 state.m_bigAirHeight = 0.0f;
162 }
163
164 state.m_bigAirFallPitch += interpRate * (targetPitch - state.m_bigAirFallPitch);
165}
166
168void KartCamera::initPos() {
169 constexpr f32 FORWARD_INTERP_RATE = 1.0f;
170 constexpr f32 HORIZ_POS_INTERP_RATE = 1.0f;
171 constexpr f32 VERT_POS_INTERP_RATE = 1.0f;
172 constexpr f32 FAST_VERT_POS_INTERP_RATE = 1.0f;
173
174 m_driftYaw = 0.0f;
175 m_forwardCamera.init();
176 m_backwardCamera.init();
177 m_backwardCamera.m_dist = m_camParams->dist;
178 m_forwardCamera.m_dist = m_camParams->dist;
179
180 const auto *kartObj = Kart::KartObjectManager::Instance()->object(0);
181 calcForward(FORWARD_INTERP_RATE, kartObj);
182 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
183 m_forwardCamera, false, kartObj, kartObj->pos());
184}
185
187void KartCamera::calcCollision(KartCameraState &state, bool isBackwards) const {
188 constexpr f32 FRONT_RADIUS = 80.0f;
189 constexpr f32 BACK_RADIUS = 140.0f;
190
191 f32 radius = isBackwards ? BACK_RADIUS : FRONT_RADIUS;
192 Field::CollisionInfo info;
193 Field::KCLTypeMask mask;
194
195 if (!Field::CollisionDirector::Instance()->checkSphereFullPush(radius, state.m_pos,
196 state.m_prevPos, KCL_TYPE_CAMERA_COLLIDABLE, &info, &mask, 0)) {
197 state.m_prevPos = state.m_pos;
198 }
199}
200
201KartCamera *KartCamera::s_instance = nullptr;
202
203} // namespace Kinoko::Render
f32 m_hopPosY
Induces a downwards camera position offset.
Definition KartCamera.hh:88
KartCameraState m_forwardCamera
Forward camera state.
KartCameraState m_backwardCamera
Rear camera state.
Pertains to rendering the kart model.