A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectBird.cc
1#include "ObjectBird.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/system/RaceManager.hh"
6
7namespace Kinoko::Field {
8
10ObjectBird::ObjectBird(const System::MapdataGeoObj &params) : ObjectCollidable(params) {
11 m_leader = EGG::egg_new<ObjectBirdLeader>(params, this);
12 m_leader->load();
13
14 u32 count = params.setting(1);
15 if (count == 0) {
16 count = 5;
17 }
18
19 m_followers = owning_span<ObjectBirdFollower *>(count);
20
21 for (u32 i = 0; i < count; ++i) {
22 auto *bird = EGG::egg_new<ObjectBirdFollower>(params, this, i);
23 m_followers[i] = bird;
24 bird->load();
25 }
26}
27
29ObjectBird::~ObjectBird() = default;
30
32void ObjectBird::calc() {
33 constexpr f32 MIN_SPACING = 300.0f;
34
35 for (u32 i = 0; i < m_followers.size() - 1; ++i) {
36 const EGG::Vector3f &firstPos = m_followers[i]->pos();
37
38 for (u32 j = i + 1; j < m_followers.size(); ++j) {
39 const EGG::Vector3f &secondPos = m_followers[j]->pos();
40 EGG::Vector3f posDelta = firstPos - secondPos;
41 f32 len = posDelta.length();
42
43 if (len >= MIN_SPACING) {
44 continue;
45 }
46
47 posDelta.normalise();
48 m_followers[j]->setPos(secondPos - posDelta * (MIN_SPACING - len));
49 }
50 }
51}
52
54ObjectBirdLeader::ObjectBirdLeader(const System::MapdataGeoObj &params, ObjectBird *bird)
55 : ObjectCollidable(params), m_bird(bird) {}
56
58ObjectBirdLeader::~ObjectBirdLeader() = default;
59
61void ObjectBirdLeader::init() {
62 auto *anmMgr = m_drawMdl->anmMgr();
63 anmMgr->playAnim(0.0f, 1.0f, 0);
64 f32 frameCount = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
65
66 auto &rand = System::RaceManager::Instance()->random();
67 f32 rate = rand.getF32(static_cast<f32>(frameCount));
68 anmMgr->playAnim(rate, 1.0f, 0);
69
70 m_railInterpolator->init(0.0f, 0);
71 m_railInterpolator->calc();
72 setPos(m_railInterpolator->curPos());
73 m_railInterpolator->setCurrVel(static_cast<f32>(m_mapObj->setting(0)));
74}
75
77void ObjectBirdLeader::calc() {
78 m_railInterpolator->calc();
79 setPos(m_railInterpolator->curPos());
80}
81
83void ObjectBirdLeader::loadAnims() {
84 std::array<const char *, 1> names = {{
85 "flying",
86 }};
87
88 std::array<Render::AnmType, 1> types = {{
89 Render::AnmType::Chr,
90 }};
91
92 linkAnims(names, types);
93}
94
96ObjectBirdFollower::ObjectBirdFollower(const System::MapdataGeoObj &params, ObjectBird *bird,
97 u32 idx)
98 : ObjectBirdLeader(params, bird), m_idx(idx) {}
99
101ObjectBirdFollower::~ObjectBirdFollower() = default;
102
104void ObjectBirdFollower::init() {
105 constexpr f32 POS_DELTA_RANGE = 1000.0f;
106 constexpr f32 POS_DELTA_CENTER = 500.0f;
107
108 auto *anmMgr = m_drawMdl->anmMgr();
109 anmMgr->playAnim(0.0f, 1.0f, 0);
110 f32 frameCount = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
111
112 auto &rand = System::RaceManager::Instance()->random();
113 f32 rate = rand.getF32(static_cast<f32>(frameCount));
114 anmMgr->playAnim(rate, 1.0f, 0);
115
116 m_baseSpeed = static_cast<f32>(m_mapObj->setting(0));
117 m_velocity = EGG::Vector3f::ez * m_baseSpeed;
118
119 f32 z = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
120 f32 y = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
121 f32 x = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
122 EGG::Vector3f delta = EGG::Vector3f(x, y, z);
123
124 setPos(m_bird->leader()->pos() + delta);
125}
126
128void ObjectBirdFollower::calc() {
129 calcPos();
130
131 CollisionInfo info;
132
133 if (CollisionDirector::Instance()->checkSphereFull(100.0f, pos(), EGG::Vector3f::inf,
134 KCL_TYPE_FLOOR, &info, nullptr, 0)) {
135 addPos(info.tangentOff);
136 }
137}
138
140void ObjectBirdFollower::calcPos() {
141 constexpr f32 MAX_SPEED_FACTOR = 1.2f;
142
143 EGG::Vector3f leaderPos = m_bird->leader()->pos();
144 const auto &follower = m_bird->followers();
145
146 for (u32 i = 0; i < follower.size(); ++i) {
147 if (i != m_idx) {
148 leaderPos += follower[i]->pos();
149 }
150 }
151
152 EGG::Vector3f posDelta = leaderPos * (1.0f / static_cast<f32>(follower.size())) - pos();
153 posDelta.normalise();
154 posDelta *= 0.5f;
155
156 m_velocity += posDelta;
157
158 if (m_velocity.length() > m_baseSpeed * MAX_SPEED_FACTOR) {
159 m_velocity.normalise();
160 m_velocity *= m_baseSpeed * MAX_SPEED_FACTOR;
161 }
162
163 addPos(m_velocity);
164}
165
166} // namespace Kinoko::Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
Pertains to collision.