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#include "game/field/ObjectDrivableDirector.hh"
5
6namespace Kinoko::Render {
7
14 constexpr f32 HOP_POS_INTERP_RATE = 0.8f;
15 constexpr f32 FORWARD_INTERP_RATE = 0.35f;
16 constexpr f32 HORIZ_POS_INTERP_RATE = 0.05f;
17 constexpr f32 VERT_POS_INTERP_RATE = 0.03f;
18 constexpr f32 FAST_VERT_POS_INTERP_RATE = 0.1f;
19
20 if (!Field::ObjectDrivableDirector::Instance()->hasCalcObjects()) {
21 return;
22 }
23
24 const auto *kartObj = Kart::KartObjectManager::Instance()->object(0);
25 EGG::Vector3f targetPos = kartObj->pos();
26 m_hopPosY += HOP_POS_INTERP_RATE * (kartObj->move()->hopPosY() - m_hopPosY);
27 targetPos.y -= m_hopPosY;
28
29 calcForward(FORWARD_INTERP_RATE, kartObj);
30 calcDriftOffset(kartObj);
31
32 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
33 m_forwardCamera, false, kartObj, targetPos);
34 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
35 m_backwardCamera, true, kartObj, targetPos);
36
37 calcCollision(m_forwardCamera, false);
38 calcCollision(m_backwardCamera, true);
39}
40
41KartCamera *KartCamera::CreateInstance() {
42 ASSERT(!s_instance);
43 s_instance = EGG::egg_new<KartCamera>();
44 return s_instance;
45}
46
47void KartCamera::DestroyInstance() {
48 ASSERT(s_instance);
49 auto *instance = s_instance;
50 s_instance = nullptr;
51 EGG::egg_delete(instance);
52}
53
55KartCamera::KartCamera() : m_hopPosY(0), m_forward(EGG::Vector3f::zero), m_camParams(nullptr) {}
56
58KartCamera::~KartCamera() = default;
59
61void KartCamera::calcDriftOffset(const Kart::KartObjectProxy *proxy) {
62 constexpr f32 MAX_DRIFT_YAW_AUTOMATIC = 10.0f;
63 constexpr f32 MAX_DRIFT_YAW_MANUAL = 15.0f;
64 constexpr f32 YAW_STEP_AUTOMATIC = 0.5f;
65 constexpr f32 YAW_STEP_MANUAL = 1.0f;
66
67 const auto &status = proxy->status();
69 f32 yaw = static_cast<f32>(proxy->hopStickX()) * -0.5f;
70 if (proxy->vehicleType() == Kart::KartParam::Stats::DriftType::Inside_Drift_Bike) {
71 yaw *= -1.0f;
72 }
73 m_driftYaw += yaw;
74
75 f32 yawMax = status.onBit(Kart::eStatus::AutoDrift) ? MAX_DRIFT_YAW_AUTOMATIC :
76 MAX_DRIFT_YAW_MANUAL;
77 f32 pitch = 90.0f - RAD2DEG * EGG::Mathf::acos(m_forward.dot(EGG::Vector3f::ey));
78 if (pitch < 0.0f) {
79 yawMax += 0.1f * EGG::Mathf::abs(pitch);
80 }
81
82 m_driftYaw = std::clamp(m_driftYaw, -yawMax, yawMax);
83 } else if (m_driftYaw != 0.0f) {
84 f32 yawStep = status.onBit(Kart::eStatus::AutoDrift) ? YAW_STEP_AUTOMATIC : YAW_STEP_MANUAL;
85 if (m_driftYaw > 0.0f) {
86 m_driftYaw = std::max(0.0f, m_driftYaw - yawStep);
87 } else {
88 m_driftYaw = std::min(0.0f, m_driftYaw + yawStep);
89 }
90 }
91}
92
94void KartCamera::calcCamera(f32 horizInterpRate, f32 vertInterpRate, f32 fastVertInterpRate,
95 KartCameraState &state, bool isBackwards, const Kart::KartObjectProxy *proxy,
96 const EGG::Vector3f &targetPos) const {
97 constexpr f32 BIG_AIR_PITCH_CAP = 89.0f * DEG2RAD;
98
99 EGG::Vector3f forwardDir = isBackwards ? -m_forward : m_forward;
100 EGG::Vector3f pitchAxis = m_right.cross(forwardDir);
101 pitchAxis.normalise();
102
103 f32 driftYaw = DEG2RAD * m_driftYaw;
104
105 const auto &status = proxy->status();
106 if (status.onBit(Kart::eStatus::AutoDrift)) {
107 driftYaw *= -1.0f;
108 }
109 f32 bigAirPitch = std::min(BIG_AIR_PITCH_CAP, state.m_bigAirFallPitch);
110
111 EGG::Matrix34f bigAirPitchMat;
112 EGG::Matrix34f yawRotMat;
113 yawRotMat.setAxisRotation(driftYaw, m_right);
114 bigAirPitchMat.setAxisRotation(bigAirPitch, pitchAxis);
115 EGG::Vector3f orbitDir = yawRotMat.ps_multVector(bigAirPitchMat.ps_multVector(forwardDir));
116
117 f32 pitch = 90.0f -
118 RAD2DEG * EGG::Mathf::acos(std::clamp(orbitDir.dot(EGG::Vector3f::ey), -1.0f, 1.0f));
119
120 // If camera is looking downwards
121 if (pitch > 0.0f) {
122 EGG::Matrix34f downPitchMat;
123 f32 fVar16 = status.onBit(Kart::eStatus::TouchingGround) ? 0.1f : 0.6f;
124 state.m_1c = state.m_1c + 0.2f * (fVar16 - state.m_1c);
125 downPitchMat.setAxisRotation(DEG2RAD * pitch * state.m_1c, pitchAxis);
126 orbitDir = downPitchMat.ps_multVector(orbitDir);
127 }
128 orbitDir *= -1.0f;
129 calcAirtimeHeight(state, proxy);
130 state.m_pos += targetPos - state.m_targetPos;
131 EGG::Vector3f posOffset = state.m_dist * orbitDir;
132 posOffset.y += m_camParams->posY - proxy->cameraDistY() + state.m_bigAirHeight;
133
134 EGG::Vector3f horizDelta = targetPos + posOffset - state.m_pos;
135 f32 vertDelta = horizDelta.y;
136 horizDelta.y = 0.0f;
137 state.m_pos += horizInterpRate * horizDelta;
138
139 if (status.onBit(Kart::eStatus::TouchingGround) && proxy->speed() > 30.0f && pitch > 15.0f) {
140 vertInterpRate = fastVertInterpRate;
141 }
142 state.m_pos.y += vertDelta * vertInterpRate;
143
144 EGG::Vector3f targetDelta = state.m_pos - targetPos;
145 if (targetDelta.ps_length() != 0.0f) {
146 state.m_pos = targetPos + state.m_dist * targetDelta.ps_normalize();
147 }
148
149 state.m_targetPos = targetPos;
150}
151
153void KartCamera::calcAirtimeHeight(KartCameraState &state,
154 const Kart::KartObjectProxy *proxy) const {
155 constexpr f32 BIG_AIR_HEIGHT_CAP = 300.0f;
156
157 f32 targetPitch = 0.0f;
158 f32 interpRate = 0.2f;
159 const auto &status = proxy->status();
160
161 if (status.onBit(Kart::eStatus::AirtimeOver20)) {
162 state.m_bigAirHeight = std::min(BIG_AIR_HEIGHT_CAP, state.m_bigAirHeight + 10.0f);
163
164 const EGG::Vector3f &vel = proxy->velocity();
165 if (vel.y < 0.0f) {
166 targetPitch = std::min(0.3f, 0.005f * -vel.y);
167 }
168 interpRate = 0.03f;
169 } else {
170 state.m_bigAirHeight = 0.0f;
171 }
172
173 state.m_bigAirFallPitch += interpRate * (targetPitch - state.m_bigAirFallPitch);
174}
175
177void KartCamera::initPos() {
178 constexpr f32 FORWARD_INTERP_RATE = 1.0f;
179 constexpr f32 HORIZ_POS_INTERP_RATE = 1.0f;
180 constexpr f32 VERT_POS_INTERP_RATE = 1.0f;
181 constexpr f32 FAST_VERT_POS_INTERP_RATE = 1.0f;
182
183 m_driftYaw = 0.0f;
184 m_forwardCamera.init();
185 m_backwardCamera.init();
186 m_backwardCamera.m_dist = m_camParams->dist;
187 m_forwardCamera.m_dist = m_camParams->dist;
188
189 const auto *kartObj = Kart::KartObjectManager::Instance()->object(0);
190 calcForward(FORWARD_INTERP_RATE, kartObj);
191 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
192 m_forwardCamera, false, kartObj, kartObj->pos());
193}
194
196void KartCamera::calcCollision(KartCameraState &state, bool isBackwards) const {
197 constexpr f32 FRONT_RADIUS = 80.0f;
198 constexpr f32 BACK_RADIUS = 140.0f;
199
200 f32 radius = isBackwards ? BACK_RADIUS : FRONT_RADIUS;
201 Field::CollisionInfo info;
202 Field::KCLTypeMask mask;
203
204 // Kinoko-specific performance optimization: Skip course KCL and only query drivable objects
205 info.reset();
206 Field::CollisionDirector::Instance()->resetCollisionEntries(&mask);
207
208 if (!Field::ObjectDrivableDirector::Instance()->checkSphereFullPush(radius, state.m_pos,
209 state.m_prevPos, KCL_TYPE_CAMERA_COLLIDABLE, &info, &mask, 0)) {
210 state.m_prevPos = state.m_pos;
211 }
212}
213
214KartCamera *KartCamera::s_instance = nullptr;
215
216} // namespace Kinoko::Render
Tracks the current state of the front and backwards player cameras.
Definition KartCamera.hh:9
Manager class for the forward and backwards cameras.
Definition KartCamera.hh:43
const Kart::KartParam::KartCameraParam * m_camParams
Definition KartCamera.hh:98
f32 m_hopPosY
Induces a downwards camera position offset.
Definition KartCamera.hh:88
f32 m_driftYaw
Rotation induced when drifting.
Definition KartCamera.hh:87
KartCameraState m_forwardCamera
Forward camera state.
KartCameraState m_backwardCamera
Rear camera state.
@ Hop
Set while we are in a drift hop. Clears when we land.
Definition Status.hh:31
@ AirtimeOver20
Set after 20 frames of airtime, resets on landing.
Definition Status.hh:28
@ DriftManual
Currently in a drift w/ manual.
Definition Status.hh:16
@ AutoDrift
True if auto transmission, false if manual.
Definition Status.hh:93
@ TouchingGround
Set when any part of the vehicle is colliding with floor KCL.
Definition Status.hh:30
Pertains to rendering the kart model.
A 3D float vector.
Definition Vector.hh:107