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 = 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 = 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 m_pos = m_railInterpolator->curPos();
73 m_flags.setBit(eFlags::Position);
74 m_railInterpolator->setCurrVel(static_cast<f32>(m_mapObj->setting(0)));
75}
76
78void ObjectBirdLeader::calc() {
79 m_railInterpolator->calc();
80 m_pos = m_railInterpolator->curPos();
81 m_flags.setBit(eFlags::Position);
82}
83
85void ObjectBirdLeader::loadAnims() {
86 std::array<const char *, 1> names = {{
87 "flying",
88 }};
89
90 std::array<Render::AnmType, 1> types = {{
91 Render::AnmType::Chr,
92 }};
93
94 linkAnims(names, types);
95}
96
98ObjectBirdFollower::ObjectBirdFollower(const System::MapdataGeoObj &params, ObjectBird *bird,
99 u32 idx)
100 : ObjectBirdLeader(params, bird), m_idx(idx) {}
101
103ObjectBirdFollower::~ObjectBirdFollower() = default;
104
106void ObjectBirdFollower::init() {
107 constexpr f32 POS_DELTA_RANGE = 1000.0f;
108 constexpr f32 POS_DELTA_CENTER = 500.0f;
109
110 auto *anmMgr = m_drawMdl->anmMgr();
111 anmMgr->playAnim(0.0f, 1.0f, 0);
112 f32 frameCount = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
113
114 auto &rand = System::RaceManager::Instance()->random();
115 f32 rate = rand.getF32(static_cast<f32>(frameCount));
116 anmMgr->playAnim(rate, 1.0f, 0);
117
118 m_baseSpeed = static_cast<f32>(m_mapObj->setting(0));
119 m_velocity = EGG::Vector3f::ez * m_baseSpeed;
120
121 f32 z = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
122 f32 y = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
123 f32 x = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
124 EGG::Vector3f delta = EGG::Vector3f(x, y, z);
125
126 m_pos = m_bird->leader()->pos() + delta;
127 m_flags.setBit(eFlags::Position);
128}
129
131void ObjectBirdFollower::calc() {
132 calcPos();
133
134 CollisionInfo info;
135
136 if (CollisionDirector::Instance()->checkSphereFull(100.0f, m_pos, EGG::Vector3f::inf,
137 KCL_TYPE_FLOOR, &info, nullptr, 0)) {
138 m_pos += info.tangentOff;
139 m_flags.setBit(eFlags::Position);
140 }
141}
142
144void ObjectBirdFollower::calcPos() {
145 constexpr f32 MAX_SPEED_FACTOR = 1.2f;
146
147 EGG::Vector3f pos = m_bird->leader()->pos();
148 const auto &follower = m_bird->followers();
149
150 for (u32 i = 0; i < follower.size(); ++i) {
151 if (i != m_idx) {
152 pos += follower[i]->pos();
153 }
154 }
155
156 EGG::Vector3f posDelta = pos * (1.0f / static_cast<f32>(follower.size())) - m_pos;
157 posDelta.normalise();
158 posDelta *= 0.5f;
159
160 m_velocity += posDelta;
161
162 if (m_velocity.length() > m_baseSpeed * MAX_SPEED_FACTOR) {
163 m_velocity.normalise();
164 m_velocity *= m_baseSpeed * MAX_SPEED_FACTOR;
165 }
166
167 m_pos += m_velocity;
168 m_flags.setBit(eFlags::Position);
169}
170
171} // namespace Kinoko::Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
Pertains to collision.