A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectKoopaBall.cc
1#include "ObjectKoopaBall.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/kart/KartCollide.hh"
6
7namespace Kinoko::Field {
8
10ObjectKoopaBall::ObjectKoopaBall(const System::MapdataGeoObj &params)
11 : ObjectCollidable(params), m_vel(EGG::Vector3f::zero) {}
12
14ObjectKoopaBall::~ObjectKoopaBall() {
15 EGG::egg_delete(m_bombCoreDrawMdl);
16}
17
19void ObjectKoopaBall::init() {
20 constexpr u32 START_COOLDOWN = 221;
21
22 m_state = State::Intangible;
23 m_cooldownTimer = START_COOLDOWN;
24
25 m_railInterpolator->init(0.0f, 0);
26 m_railInterpolator->setCurrVel(INITIAL_VELOCITY);
27 m_railInterpolator->calc();
28
29 m_initPosY = m_railInterpolator->curPos().y;
30 setPos(EGG::Vector3f(pos().x, m_initPosY, pos().z));
31
32 EGG::Vector3f curTanDirNorm = m_railInterpolator->curTangentDir();
33 curTanDirNorm.normalise();
34 setMatrixFromOrthonormalBasisAndPos(curTanDirNorm);
35 calcTransform();
36
37 m_angleRad = 0.0f;
38 m_angSpeed = INITIAL_ANGULAR_SPEED;
39 m_vel.y = INITIAL_Y_VEL;
40
41 m_bombCoreDrawMdl = EGG::egg_new<Render::DrawMdl>();
42
43 auto *resMgr = System::ResourceManager::Instance();
44 const void *file = resMgr->getFile("bombCore.brres", nullptr, System::ArchiveId::Core);
45 ASSERT(file);
46 Abstract::g3d::ResFile resFile = Abstract::g3d::ResFile(file);
47
48 m_bombCoreDrawMdl->linkAnims(0, &resFile, "bombCore", Render::AnmType::Chr);
49 auto *anmMgr = m_bombCoreDrawMdl->anmMgr();
50 anmMgr->playAnim(0.0f, 1.0f, 0);
51 m_animFramecount = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
52 m_explodeTimer = -1;
53
54 EGG::Matrix34f mat;
55 mat.makeR(rot());
56
57 resize(RADIUS_AABB, 0.0f);
58}
59
61void ObjectKoopaBall::calc() {
62 switch (m_state) {
63 case State::Tangible:
64 calcTangible();
65 break;
66 case State::Intangible:
67 calcIntangible();
68 break;
69 case State::Exploding:
70 calcExploding();
71 break;
72 default:
73 break;
74 }
75
76 --m_cooldownTimer;
77
78 EGG::Vector3f railVel = m_railInterpolator->curTangentDir() * m_railInterpolator->getCurrVel();
79 m_vel.x = railVel.x;
80 m_vel.z = railVel.z;
81}
82
84Kart::Reaction ObjectKoopaBall::onCollision(Kart::KartObject * /*kartObj*/,
85 Kart::Reaction reactionOnKart, Kart::Reaction /*reactionOnObj*/,
86 EGG::Vector3f & /*hitDepth*/) {
87 return m_explodeTimer > 0 ? Kart::Reaction::ExplosionLoseItem : reactionOnKart;
88}
89
91void ObjectKoopaBall::calcTangible() {
92 constexpr f32 END_VELOCITY = 60.0f;
93 constexpr f32 GRAVITY = 2.0f;
94
95 auto railStatus = m_railInterpolator->calc();
96
97 switch (railStatus) {
98 case RailInterpolator::Status::SegmentEnd:
99 m_vel.y = END_VELOCITY;
100 m_railInterpolator->setCurrVel(INITIAL_VELOCITY / INITIAL_ANGULAR_SPEED);
101 break;
102 case RailInterpolator::Status::ChangingDirection: {
103 m_state = State::Exploding;
104 m_curScale = SCALE_INITIAL;
105 setScale(SCALE_INITIAL);
106 m_explodeTimer = m_animFramecount;
107 } break;
108 default:
109 break;
110 }
111
112 m_vel.y = m_vel.y - GRAVITY;
113 const auto &railPos = m_railInterpolator->curPos();
114 setPos(EGG::Vector3f(railPos.x, m_vel.y + pos().y, railPos.z));
115
116 checkSphereFull();
117
118 m_angleRad += -m_angSpeed * DEG2RAD;
119
120 EGG::Matrix34f mat = EGG::Matrix34f::ident;
121 mat.makeR(EGG::Vector3f(m_angleRad, 0.0f, 0.0f));
122 mat = transform().multiplyTo(mat);
123 mat.setBase(3, pos());
124 setTransform(mat);
125}
126
128void ObjectKoopaBall::calcExploding() {
129 constexpr s32 EXPLODE_COLLISION_DURATION = 20;
130 constexpr s32 EXPLOSION_EXPAND_FRAME = 30;
131 constexpr f32 INIT_FACTOR = 1.01f;
132 constexpr EGG::Vector3f INIT_SCALE = EGG::Vector3f(INIT_FACTOR, INIT_FACTOR, INIT_FACTOR);
133
134 if (m_explodeTimer > EXPLOSION_EXPAND_FRAME) {
135 m_curScale += SCALE_DELTA;
136 setScale(m_curScale);
137 }
138
139 if (m_explodeTimer == EXPLODE_COLLISION_DURATION) {
140 disableCollision();
141 }
142
143 if (--m_explodeTimer == 0) {
144 m_curScale = INIT_FACTOR;
145 setScale(INIT_SCALE);
146 m_railInterpolator->init(0.0f, 0);
147 const auto &railPos = m_railInterpolator->curPos();
148 setPos(EGG::Vector3f(railPos.x, m_initPosY, railPos.z));
149 enableCollision();
150 m_state = State::Intangible;
151 }
152}
153
155void ObjectKoopaBall::calcIntangible() {
156 constexpr s32 COOLDOWN_FRAMES = 210;
157
158 if (m_cooldownTimer >= 0) {
159 return;
160 }
161
162 m_state = State::Tangible;
163 m_railInterpolator->setCurrVel(INITIAL_VELOCITY);
164 m_angSpeed = INITIAL_ANGULAR_SPEED;
165 m_vel.y = INITIAL_Y_VEL;
166 m_cooldownTimer = COOLDOWN_FRAMES;
167}
168
170void ObjectKoopaBall::checkSphereFull() {
171 constexpr EGG::Vector3f POS_OFFSET = EGG::Vector3f(0.0f, -900.0f, 0.0f);
172 constexpr f32 RADIUS = 100.0f;
173 constexpr f32 BOUNCE_FACTOR = -0.4f;
174 constexpr f32 MIN_ANG_SPEED = 10.0f;
175
176 CollisionInfo info;
177 EGG::Vector3f colPos = pos() + POS_OFFSET;
178
179 if (CollisionDirector::Instance()->checkSphereFull(RADIUS, colPos, EGG::Vector3f::inf,
180 KCL_TYPE_FLOOR, &info, nullptr, 0)) {
181 m_vel.y *= BOUNCE_FACTOR;
182 m_angSpeed = std::max(MIN_ANG_SPEED, m_angSpeed);
183 addPos(info.tangentOff);
184 }
185}
186
187} // namespace Kinoko::Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
Pertains to collision.