1#include "KartCamera.hh"
3#include "game/field/CollisionDirector.hh"
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;
15 const auto *kartObj = Kart::KartObjectManager::Instance()->object(0);
16 EGG::Vector3f targetPos = kartObj->pos();
20 calcForward(FORWARD_INTERP_RATE, kartObj);
21 calcDriftOffset(kartObj);
23 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
25 calcCamera(HORIZ_POS_INTERP_RATE, VERT_POS_INTERP_RATE, FAST_VERT_POS_INTERP_RATE,
32KartCamera *KartCamera::CreateInstance() {
34 s_instance =
new KartCamera;
38void KartCamera::DestroyInstance() {
40 auto *instance = s_instance;
46KartCamera::KartCamera() : m_hopPosY(0), m_forward(EGG::Vector3f::zero), m_camParams(nullptr) {}
49KartCamera::~KartCamera() =
default;
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;
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) {
66 f32 yawMax = status.onBit(Kart::eStatus::AutoDrift) ? MAX_DRIFT_YAW_AUTOMATIC :
68 f32 pitch = 90.0f - RAD2DEG * EGG::Mathf::acos(m_forward.dot(EGG::Vector3f::ey));
70 yawMax += 0.1f * EGG::Mathf::abs(pitch);
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);
79 m_driftYaw = std::min(0.0f, m_driftYaw + yawStep);
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;
90 EGG::Vector3f forwardDir = isBackwards ? -m_forward : m_forward;
91 EGG::Vector3f pitchAxis = m_right.cross(forwardDir);
92 pitchAxis.normalise();
94 f32 driftYaw = DEG2RAD * m_driftYaw;
96 const auto &status = proxy->status();
97 if (status.onBit(Kart::eStatus::AutoDrift)) {
100 f32 bigAirPitch = std::min(BIG_AIR_PITCH_CAP, state.m_bigAirFallPitch);
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));
109 RAD2DEG * EGG::Mathf::acos(std::clamp(orbitDir.dot(EGG::Vector3f::ey), -1.0f, 1.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);
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;
125 EGG::Vector3f horizDelta = targetPos + posOffset - state.m_pos;
126 f32 vertDelta = horizDelta.y;
128 state.m_pos += horizInterpRate * horizDelta;
130 if (status.onBit(Kart::eStatus::TouchingGround) && proxy->speed() > 30.0f && pitch > 15.0f) {
131 vertInterpRate = fastVertInterpRate;
133 state.m_pos.y += vertDelta * vertInterpRate;
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();
140 state.m_targetPos = targetPos;
144void KartCamera::calcAirtimeHeight(KartCameraState &state,
145 const Kart::KartObjectProxy *proxy)
const {
146 constexpr f32 BIG_AIR_HEIGHT_CAP = 300.0f;
148 f32 targetPitch = 0.0f;
149 f32 interpRate = 0.2f;
150 const auto &status = proxy->status();
152 if (status.onBit(Kart::eStatus::AirtimeOver20)) {
153 state.m_bigAirHeight = std::min(BIG_AIR_HEIGHT_CAP, state.m_bigAirHeight + 10.0f);
155 const EGG::Vector3f &vel = proxy->velocity();
157 targetPitch = std::min(0.3f, 0.005f * -vel.y);
161 state.m_bigAirHeight = 0.0f;
164 state.m_bigAirFallPitch += interpRate * (targetPitch - state.m_bigAirFallPitch);
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;
175 m_forwardCamera.init();
176 m_backwardCamera.init();
177 m_backwardCamera.m_dist = m_camParams->dist;
178 m_forwardCamera.m_dist = m_camParams->dist;
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());
187void KartCamera::calcCollision(KartCameraState &state,
bool isBackwards)
const {
188 constexpr f32 FRONT_RADIUS = 80.0f;
189 constexpr f32 BACK_RADIUS = 140.0f;
191 f32 radius = isBackwards ? BACK_RADIUS : FRONT_RADIUS;
192 Field::CollisionInfo info;
193 Field::KCLTypeMask mask;
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;
201KartCamera *KartCamera::s_instance =
nullptr;
f32 m_hopPosY
Induces a downwards camera position offset.
KartCameraState m_forwardCamera
Forward camera state.
KartCameraState m_backwardCamera
Rear camera state.
Pertains to rendering the kart model.