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 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 = std::span<ObjectBirdFollower *>(new ObjectBirdFollower *[count], 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() {
30 delete[] m_followers.data();
31}
32
34void ObjectBird::calc() {
35 constexpr f32 MIN_SPACING = 300.0f;
36
37 for (u32 i = 0; i < m_followers.size() - 1; ++i) {
38 const EGG::Vector3f &firstPos = m_followers[i]->pos();
39
40 for (u32 j = i + 1; j < m_followers.size(); ++j) {
41 const EGG::Vector3f &secondPos = m_followers[j]->pos();
42 EGG::Vector3f posDelta = firstPos - secondPos;
43 f32 len = posDelta.length();
44
45 if (len >= MIN_SPACING) {
46 continue;
47 }
48
49 posDelta.normalise();
50 m_followers[j]->setPos(secondPos - posDelta * (MIN_SPACING - len));
51 }
52 }
53}
54
56ObjectBirdLeader::ObjectBirdLeader(const System::MapdataGeoObj &params, ObjectBird *bird)
57 : ObjectCollidable(params), m_bird(bird) {}
58
60ObjectBirdLeader::~ObjectBirdLeader() = default;
61
63void ObjectBirdLeader::init() {
64 auto *anmMgr = m_drawMdl->anmMgr();
65 anmMgr->playAnim(0.0f, 1.0f, 0);
66 f32 frameCount = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
67
68 auto &rand = System::RaceManager::Instance()->random();
69 f32 rate = rand.getF32(static_cast<f32>(frameCount));
70 anmMgr->playAnim(rate, 1.0f, 0);
71
72 m_railInterpolator->init(0.0f, 0);
73 m_railInterpolator->calc();
74 m_pos = m_railInterpolator->curPos();
75 m_flags.setBit(eFlags::Position);
76 m_railInterpolator->setCurrVel(static_cast<f32>(m_mapObj->setting(0)));
77}
78
80void ObjectBirdLeader::calc() {
81 m_railInterpolator->calc();
82 m_pos = m_railInterpolator->curPos();
83 m_flags.setBit(eFlags::Position);
84}
85
87void ObjectBirdLeader::loadAnims() {
88 std::array<const char *, 1> names = {{
89 "flying",
90 }};
91
92 std::array<Render::AnmType, 1> types = {{
93 Render::AnmType::Chr,
94 }};
95
96 linkAnims(names, types);
97}
98
100ObjectBirdFollower::ObjectBirdFollower(const System::MapdataGeoObj &params, ObjectBird *bird,
101 u32 idx)
102 : ObjectBirdLeader(params, bird), m_idx(idx) {}
103
105ObjectBirdFollower::~ObjectBirdFollower() = default;
106
108void ObjectBirdFollower::init() {
109 constexpr f32 POS_DELTA_RANGE = 1000.0f;
110 constexpr f32 POS_DELTA_CENTER = 500.0f;
111
112 auto *anmMgr = m_drawMdl->anmMgr();
113 anmMgr->playAnim(0.0f, 1.0f, 0);
114 f32 frameCount = anmMgr->activeAnim(Render::AnmType::Chr)->frameCount();
115
116 auto &rand = System::RaceManager::Instance()->random();
117 f32 rate = rand.getF32(static_cast<f32>(frameCount));
118 anmMgr->playAnim(rate, 1.0f, 0);
119
120 m_baseSpeed = static_cast<f32>(m_mapObj->setting(0));
121 m_velocity = EGG::Vector3f::ez * m_baseSpeed;
122
123 f32 z = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
124 f32 y = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
125 f32 x = rand.getF32(POS_DELTA_RANGE) - POS_DELTA_CENTER;
126 EGG::Vector3f delta = EGG::Vector3f(x, y, z);
127
128 m_pos = m_bird->leader()->pos() + delta;
129 m_flags.setBit(eFlags::Position);
130}
131
133void ObjectBirdFollower::calc() {
134 calcPos();
135
136 CollisionInfo info;
137
138 if (CollisionDirector::Instance()->checkSphereFull(100.0f, m_pos, EGG::Vector3f::inf,
139 KCL_TYPE_FLOOR, &info, nullptr, 0)) {
140 m_pos += info.tangentOff;
141 m_flags.setBit(eFlags::Position);
142 }
143}
144
146void ObjectBirdFollower::calcPos() {
147 constexpr f32 MAX_SPEED_FACTOR = 1.2f;
148
149 EGG::Vector3f pos = m_bird->leader()->pos();
150 const auto &follower = m_bird->followers();
151
152 for (u32 i = 0; i < follower.size(); ++i) {
153 if (i != m_idx) {
154 pos += follower[i]->pos();
155 }
156 }
157
158 EGG::Vector3f posDelta = pos * (1.0f / static_cast<f32>(follower.size())) - m_pos;
159 posDelta.normalise();
160 posDelta *= 0.5f;
161
162 m_velocity += posDelta;
163
164 if (m_velocity.length() > m_baseSpeed * MAX_SPEED_FACTOR) {
165 m_velocity.normalise();
166 m_velocity *= m_baseSpeed * MAX_SPEED_FACTOR;
167 }
168
169 m_pos += m_velocity;
170 m_flags.setBit(eFlags::Position);
171}
172
173} // namespace Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
Pertains to collision.
A 3D float vector.
Definition Vector.hh:87
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:44
f32 length() const
The square root of the vector's dot product.
Definition Vector.hh:191