-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOrganism.cpp
265 lines (217 loc) · 11 KB
/
Organism.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#include <exception>
#include "Organism.h"
#include "Food.h"
#include "MathHelpers.h"
#include "Utilities.h"
#include "SharedContext.h"
#include "MathHelpers.h"
#include "Engine.h"
#include "Scenario_Basic.h"
#include "PreprocessorDirectves.h"
static const float S_TIME_ZERO{ 0.f };
static const std::string S_DEFAULT_TEXTURE{ "Texture_organism" };
static const float S_TEXT_OFFSET_FACTOR{ 1.1f };
static const sf::Color S_DEFAULT_COLOR{ 255,255,255,255 };
static const float S_DEFAULT_SIZE{ 1.f };
static const float S_DEFAULT_DESTRUCTION_DELAY{ 10.f };
static const sf::Color S_DEATH_COLOR{70,60,50};
////////////////////////////////////////////////////////////
Organism::Organism(
SharedContext& t_context,
const std::string& t_name,
const sf::Vector2f& t_position,
const float& t_rotation,
const float& t_age) :
Actor_Base(t_context, t_position, t_rotation, S_DEFAULT_COLOR, S_DEFAULT_TEXTURE, sf::IntRect(), true, true),
m_name{ t_name },
m_age{ t_age },
m_ai{ std::make_unique<Ai_Organism>(t_context) },
m_destructionDelay{ S_DEFAULT_DESTRUCTION_DELAY },
m_scenario{ &t_context.m_engine->getScenario() }
{
m_actorType = ActorType::Organism;
m_text.setCharacterSize(10U);
setTextString(m_name);
setColorRGB(m_color); //Also write the HSL color
}
////////////////////////////////////////////////////////////
OrganismPtr Organism::makeDefaultClone(SharedContext& t_context, const std::string& t_name, const sf::Vector2f& t_position, const float& t_rotation, const float& t_age) {
auto o{ std::make_unique<Organism>(t_context, t_name, t_position, t_rotation, t_age) };
for (const auto& it : Trait_Base::getVitalTraits()) {
o->m_traits.addTrait(std::move(Trait_Base::cloneDefaultTrait(it)));
}
o->m_traits.onOrganismConstruction(o.get(), 0.f); // Update all the traits
return std::move(o);
}
////////////////////////////////////////////////////////////
OrganismPtr Organism::makeDefaultOffspring(SharedContext& t_context, const std::string& t_name, const sf::Vector2f& t_position, const float& t_rotation, const float& t_age) {
auto o{ std::make_unique<Organism>(t_context, t_name, t_position, t_rotation, t_age) };
for (const auto& it : Trait_Base::getVitalTraits()) {
o->m_traits.addTrait(std::move(Trait_Base::reproduceDefaultTrait(t_context, it)));
}
o->m_traits.onOrganismConstruction(o.get(), 0.f); // Update all the traits
return std::move(o);
}
////////////////////////////////////////////////////////////
const HSL& Organism::getColorHSL()const { return m_hslColor; }
////////////////////////////////////////////////////////////
void Organism::setColorHSL(const float& t_h, const float& t_s, const float& t_l) {
m_hslColor.Hue = t_h;
m_hslColor.Saturation = t_h;
m_hslColor.Luminance = t_l;
m_color = m_hslColor.TurnToRGB();
}
////////////////////////////////////////////////////////////
const sf::Color& Organism::getColorRGB()const { return m_color; }
////////////////////////////////////////////////////////////
void Organism::setColorRGB(const sf::Color& t_color) {
m_color = t_color;
m_hslColor = HSL::TurnToHSL(t_color);
}
////////////////////////////////////////////////////////////
const float& Organism::getMovementSpeed()const { return m_trait_movementSpeed; }
////////////////////////////////////////////////////////////
void Organism::setMovementSpeed(const float& t_movementSpeed) { m_trait_movementSpeed = t_movementSpeed; }
////////////////////////////////////////////////////////////
const float& Organism::getRotationSpeed()const { return m_trait_turningSpeed; }
////////////////////////////////////////////////////////////
void Organism::setRotationSpeed(const float& t_rotationSpeed) { m_trait_turningSpeed = t_rotationSpeed; }
////////////////////////////////////////////////////////////
const float& Organism::getAge()const { return m_age; }
////////////////////////////////////////////////////////////
void Organism::setAge(const float& t_age) { m_age = t_age; }
////////////////////////////////////////////////////////////
const float& Organism::getSize()const { return m_trait_size; }
////////////////////////////////////////////////////////////
void Organism::setSize(const float& t_size) { m_trait_size = t_size; }
////////////////////////////////////////////////////////////
const std::string& Organism::getName()const { return m_name; }
////////////////////////////////////////////////////////////
void Organism::setName(const std::string& t_name) { m_name = t_name; }
////////////////////////////////////////////////////////////
void Organism::setEnergy(const float& t_energy) { m_energy = t_energy; }
////////////////////////////////////////////////////////////
void Organism::addEnergy(const float& t_energy) { m_energy += t_energy; if (m_energy >= m_trait_maxEnergy) { m_energy = m_trait_maxEnergy; } }
////////////////////////////////////////////////////////////
const float& Organism::getEnergy()const { return m_energy; }
////////////////////////////////////////////////////////////
const float& Organism::getMass()const { return m_mass; }
////////////////////////////////////////////////////////////
const float Organism::getRestingMetabolicRate()const { return m_trait_restingMetabolicRate * m_mass; }
////////////////////////////////////////////////////////////
float Organism::getEnergyPct()const { return m_energy / m_trait_maxEnergy; }
////////////////////////////////////////////////////////////
void Organism::setEnergyPct(const float& t_pct) {
m_energy = m_trait_maxEnergy * t_pct;
if (m_energy > m_trait_maxEnergy) { m_energy = m_trait_maxEnergy; }
else if (m_energy < 0.f) { m_energy = 0.f; }
}
////////////////////////////////////////////////////////////
void Organism::addEnergyPct(const float& t_pct) {
m_energy += m_trait_maxEnergy * t_pct;
if (m_energy > m_trait_maxEnergy) { m_energy = m_trait_maxEnergy; }
else if (m_energy < 0.f) { m_energy = 0.f; }
}
////////////////////////////////////////////////////////////
void Organism::move(const float& t_dx, const float& t_dy) {
float energyExpediture{ std::sqrtf(t_dx * t_dx + t_dy * t_dy) * m_mass };
m_energy -= energyExpediture; // Movement costs energy: diplacement * mass
m_scenario->addEnergy(energyExpediture); // Return heat energy to environment
Actor_Base::move(t_dx, t_dy);
}
////////////////////////////////////////////////////////////
void Organism::rotate(const float& t_deg) {
float energyExpediture{ std::fabs(mat::toRadians(t_deg)) * m_mass };
m_energy -= energyExpediture;
m_scenario->addEnergy(energyExpediture); // Return heat energy to environment
Actor_Base::rotate(t_deg);
}
////////////////////////////////////////////////////////////
void Organism::update(const float& t_elapsed) {
// Update the organism's age
m_age += t_elapsed;
// Decrease the organism's energy based on its metabolic rate
float energyExpediture{ m_trait_restingMetabolicRate * t_elapsed };
m_energy -= energyExpediture;
m_scenario->addEnergy(energyExpediture); // Return heat energy to environment
if ((m_age >= m_trait_lifespan || m_energy <= 0.f) && !m_isDead) { die(); }
if (m_isDead) {
if (m_destructionDelay <= 0.f) { m_destroy = true; }
m_destructionDelay -= t_elapsed;
return;
}// Dead organisms do not move, they just wait to decompose.
// Update all the traits' effects
m_traits.update(this, t_elapsed);
// Update the organim's ai
m_ai->update(this, t_elapsed);
#if defined(_DEBUG) && IS_DISPLAY_ORGNAISMS_DEBUG_TEXT == 1
setTextString(m_name +
"\nEnergy: " + std::to_string(static_cast<unsigned>(m_energy >= 0.f ? m_energy : 0.f)) + " / " + std::to_string(static_cast<unsigned>(m_trait_maxEnergy)) +
"\nAge : " + std::to_string(static_cast<unsigned>(m_age)) + " / " + std::to_string(static_cast<unsigned>(m_trait_lifespan)) +
"\nSize : " + std::to_string(m_trait_size) +
"\nMass : " + std::to_string(m_mass) +
"\nRMR : " + std::to_string(m_rmr) +
"\nMovSp : " + std::to_string(m_trait_movementSpeed) +
"\nRotSp : " + std::to_string(m_trait_turningSpeed) +
"\nDigEff: " + std::to_string(m_trait_digestiveEfficiency));
#endif // defined(_DEBUG) && IS_DISPLAY_ORGNAISMS_DEBUG_TEXT == 1
// Lower level update (position, rotation ...)
Actor_Base::update(t_elapsed);
// Update the collider component
updateCollider();
}
////////////////////////////////////////////////////////////
ActorPtr Organism::clone() {
auto o{ std::make_unique<Organism>(m_context, m_name, m_position, m_rotation, m_age) };
o->m_traits = std::move(*m_traits.clone().release()); // Pass unique ptr to regular member
o->m_traits.onOrganismConstruction(o.get(), 0.f); // Update "OnConstruction" traits
return std::move(o);
}
////////////////////////////////////////////////////////////
ActorPtr Organism::reproduce(SharedContext& t_context) {
auto o{ std::make_unique<Organism>(m_context, m_name, m_position, m_rotation, 0.f) }; // Reset the organism's age
o->m_traits = std::move(*m_traits.reproduce(t_context).release());
o->m_traits.onOrganismConstruction(o.get(), 0.f);
return std::move(o);
}
////////////////////////////////////////////////////////////
void Organism::die() {
m_isDead = true;
setColorRGB(S_DEATH_COLOR);
m_sprite.setColor(S_DEATH_COLOR);
m_name += " (dead)";
setTextString(m_name);
}
////////////////////////////////////////////////////////////
void Organism::eat(Food* t_food) {
if (!t_food || t_food->shouldBeDestroyed()) { return; } // Trying to eat ghost food doesn't work at this level of conciousness.
if (m_energy > 0.8f * m_trait_maxEnergy) { return; } // Ogranisms at and over 80% of energy are not experiencing hunger
float foodEnergy{ t_food->getEnergy() };
float energyDelta{ foodEnergy * m_trait_digestiveEfficiency }; // Get the energy boost affected by digestive efficiency
m_energy += energyDelta;
m_scenario->addEnergy(foodEnergy - energyDelta); // Return the energy to the rest of the energy to the environment
if (m_energy > m_trait_maxEnergy) {
m_scenario->addEnergy(m_energy - m_trait_maxEnergy); // Return aswell any energy from overeating
m_energy = m_trait_maxEnergy;
}
t_food->setWasEaten(true); // State that the food was eaten, so that it does not try to return its energy itelf, its the organism's task now.
t_food->setShouldBeDestroyed(true); // Tell the engine the food no longer exists (ha)
}
////////////////////////////////////////////////////////////
void Organism::updateCollider() {
auto aabb{ m_sprite.getLocalBounds() };
m_collider->update(this, m_position, { aabb.width * m_trait_size, aabb.height * m_trait_size });
}
////////////////////////////////////////////////////////////
float Organism::getRadius()const { return Actor_Base::getRadius() * m_trait_size; }
////////////////////////////////////////////////////////////
bool Organism::canSpawn(SharedContext& t_context)const {
return m_scenario->getEnergy() >= m_energy; // Make sure there is enough energy in the environment for it to spawn
}
////////////////////////////////////////////////////////////
void Organism::onSpawn() {m_scenario->addEnergy(-m_energy); } // Capture energy from the environment
////////////////////////////////////////////////////////////
void Organism::onDestruction(SharedContext& t_context) {
m_scenario->addEnergy(m_energy); // Return the energy to the environment
Actor_Base::onDestruction(t_context);
}