1#include "ObjectFireSnake.hh"
3#include "game/field/CollisionDirector.hh"
4#include "game/field/ObjectDirector.hh"
6#include "game/system/RaceManager.hh"
12 : ObjectCollidable(params) {}
15ObjectFireSnakeKid::~ObjectFireSnakeKid() =
default;
19 : ObjectProjectile(params), StateManager(this), m_maxAge(static_cast<s16>(params.setting(1))),
20 m_initialPos(params.pos()) {
21 if (ObjectDirector::Instance()->managedObjects().size() > 0) {
22 registerManagedObject();
25 for (
u32 i = 0; i < 2; ++i) {
26 auto *&kid = m_kids[i];
27 kid =
new ObjectFireSnakeKid(params);
29 f32 scale = (0.75f - 0.25f *
static_cast<f32
>(i)) * m_scale.y;
33 m_prevTransforms.fill(EGG::Matrix34f::ident);
37ObjectFireSnake::~ObjectFireSnake() =
default;
40void ObjectFireSnake::init() {
47 m_initRot = m_transform.base(0);
48 m_bounceDir = m_transform.base(0);
52void ObjectFireSnake::calc() {
55 if (isCollisionEnabled()) {
56 if (++m_age >= m_maxAge && m_currentStateId == 3) {
68 m_xzSunDist = m_initialPos - m_sunPos;
70 m_xzSunDist.normalise2();
74 f32 dist = xzDist.
length();
76 m_fallAxis = RotateXZByYaw(F_PI / 2.0f, m_xzSunDist);
77 m_xzSpeed = dist * EGG::Mathf::sqrt(GRAVITY * 0.5f / (m_sunPos.y - m_initialPos.y));
78 m_fallDuration =
static_cast<u16>(dist / m_xzSpeed);
82void ObjectFireSnake::onLaunch() {
87void ObjectFireSnake::enterDespawned() {
89 unregisterCollision();
92 m_visualPos = m_sunPos;
94 m_flags.setBit(eFlags::Position);
98void ObjectFireSnake::enterFalling() {
105void ObjectFireSnake::enterHighBounce() {
106 m_visualPos = m_initialPos;
107 m_pos = m_initialPos;
108 m_flags.setBit(eFlags::Position);
110 f32 rand = System::RaceManager::Instance()->random().getF32();
111 m_bounceDir = rand >= 0.5f ? m_initRot : -m_initRot;
117void ObjectFireSnake::enterRest() {
118 constexpr f32 XZ_RANGE = 1000.0f * 1000.0f;
121 if (m_visualPos.sqDistance(m_initialPos) >= XZ_RANGE) {
122 m_bounceDir = m_initialPos - m_visualPos;
123 m_bounceDir.normalise2();
126 auto &rand = System::RaceManager::Instance()->random();
127 f32 angle = rand.getF32(90.0f) - 45.0f;
129 if (rand.getF32() >= 0.5f) {
133 m_bounceDir = RotateXZByYaw(angle * DEG2RAD, m_initRot);
138void ObjectFireSnake::calcFalling() {
140 fallVel.y = -GRAVITY *
static_cast<f32
>(m_currentFrame);
141 f32 fallVelY = fallVel.y;
142 f32 posY = m_visualPos.y + fallVel.y;
144 if (posY <= m_initialPos.y) {
146 m_pos = m_visualPos * 0.5f + m_initialPos * 0.5f;
147 m_flags.setBit(eFlags::Position);
149 fallVel.x = m_xzSpeed;
150 m_visualPos.y = posY;
151 m_visualPos.x += m_xzSunDist.x * fallVel.x;
152 m_visualPos.z += m_xzSunDist.z * fallVel.x;
153 fallVel.normalise2();
155 f32 angle = fallVel.x;
156 EGG::Vector3f up = RotateAxisAngle(EGG::Mathf::acos(angle), m_fallAxis, EGG::Vector3f::ey);
157 auto axis =
EGG::Vector3f(m_xzSunDist.x * m_xzSpeed, -fallVelY, m_xzSunDist.z * m_xzSpeed);
159 auto spiral = RotateAxisAngle(50.0f *
static_cast<f32
>(m_currentFrame) * DEG2RAD, axis, up);
161 f32 scaledDuration = 0.9f *
static_cast<f32
>(m_fallDuration);
162 f32 phase = m_currentFrame -
static_cast<u16>(scaledDuration);
163 f32 spiralRadius = phase < 0 ? 200.0f : 200.0f - (200.0f / scaledDuration) * phase;
165 m_pos = m_visualPos + spiral * spiralRadius;
166 m_flags.setBit(eFlags::Position);
171void ObjectFireSnake::calcHighBounce() {
172 constexpr f32 INITIAL_VELOCITY = 1.6f * 60.0f;
174 calcBounce(INITIAL_VELOCITY);
178void ObjectFireSnake::calcRest() {
179 if (m_currentFrame >= 30) {
185 EGG::Vector3f tangent = Interpolate(0.3f, m_transform.base(2), m_bounceDir);
186 tangent.normalise2();
188 setMatrixTangentTo(EGG::Vector3f::ey, tangent);
192void ObjectFireSnake::calcBounce() {
193 constexpr f32 INITIAL_VELOCITY = 60.0f;
195 calcBounce(INITIAL_VELOCITY);
199void ObjectFireSnake::calcChildren() {
201 for (
size_t i = m_prevTransforms.size() - 1; i > 0; --i) {
202 m_prevTransforms[i] = m_prevTransforms[i - 1];
206 m_prevTransforms[0] = m_transform;
207 m_prevTransforms[0].setBase(3, m_pos);
210 for (
auto *&kid : m_kids) {
211 if (m_currentStateId == 1 && idx == m_currentFrame) {
212 if (!kid->getUnit()) {
215 }
else if (m_currentStateId == 0 && m_currentFrame == 0) {
216 if (kid->getUnit()) {
217 kid->unregisterCollision();
221 if (m_currentStateId == 1 && m_currentFrame < idx) {
223 kid->setTransform(m_transform);
225 kid->setTransform(m_prevTransforms[idx]);
233void ObjectFireSnake::calcBounce(f32 initialVel) {
235 constexpr u32 BOUNCE_COL_CHECK_DELAY = 10;
236 constexpr f32 RADIUS = 130.0f;
237 constexpr f32 BOUNCE_SPEED = 20.0f;
239 m_visualPos.x += m_bounceDir.x * BOUNCE_SPEED;
240 m_visualPos.z += m_bounceDir.z * BOUNCE_SPEED;
241 m_visualPos.y += initialVel - GRAVITY *
static_cast<f32
>(m_currentFrame);
245 if (m_currentFrame > BOUNCE_COL_CHECK_DELAY) {
246 bool hasCol = CollisionDirector::Instance()->checkSphereFull(RADIUS, m_visualPos,
247 EGG::Vector3f::inf, KCL_TYPE_64EBDFFF, &info,
nullptr, 0);
250 m_visualPos += info.tangentOff;
256 m_flags.setBit(eFlags::Position);
f32 length() const
The square root of the vector's dot product.