auto blob = new creature::Creature(sim);
blob->Name(assets.name.Sequential());
Spawn(*blob, planet);
+ // decrease chances of ur-blob dying without splitting
+ blob->GetProperties().Youth().fertility = 1.0;
+ blob->GetProperties().Adult().fertility = 1.0;
blob->BuildVAO();
app::MasterState state(assets, sim);
--- /dev/null
+#ifndef BLOBS_CREATURE_BLOBBACKGROUNDTASK_HPP_
+#define BLOBS_CREATURE_BLOBBACKGROUNDTASK_HPP_
+
+#include "Goal.hpp"
+
+
+namespace blobs {
+namespace creature {
+
+class BlobBackgroundTask
+: public Goal {
+
+public:
+ explicit BlobBackgroundTask(Creature &);
+ ~BlobBackgroundTask() override;
+
+public:
+ std::string Describe() const override;
+ void Tick(double dt) override;
+ void Action() override;
+
+};
+
+}
+}
+
+#endif
double Age() const noexcept;
std::string AgeName() const;
double AgeLerp(double from, double to) const noexcept;
- // change of giving birth per tick
+ // chance of giving birth per tick
double Fertility() const noexcept;
+ // chance of random genetic mutation per tick
+ double Mutability() const noexcept;
void Health(double h) noexcept { health = h; }
double Health() const noexcept { return health; }
Memory &GetMemory() noexcept { return memory; }
const Memory &GetMemory() const noexcept { return memory; }
+ /// constantly active goal. every creature in the simulation is required to have one
+ void SetBackgroundTask(std::unique_ptr<Goal> &&g) { bg_task = std::move(g); }
+ Goal &BackgroundTask() { return *bg_task; }
+
void AddNeed(std::unique_ptr<Need> &&n) { needs.emplace_back(std::move(n)); }
const std::vector<std::unique_ptr<Need>> &Needs() const noexcept { return needs; }
Memory memory;
+ std::unique_ptr<Goal> bg_task;
std::vector<std::unique_ptr<Need>> needs;
std::vector<std::unique_ptr<Goal>> goals;
#include "Situation.hpp"
#include "Steering.hpp"
+#include "BlobBackgroundTask.hpp"
#include "Goal.hpp"
#include "IdleGoal.hpp"
#include "InhaleNeed.hpp"
, on_death()
, removable(false)
, memory(*this)
+, bg_task()
, needs()
, goals()
, situation()
}
double Creature::Fertility() const noexcept {
- return AgeLerp(CurProps().fertility, NextProps().fertility) / 3600.0;
+ return AgeLerp(CurProps().fertility, NextProps().fertility) * (1.0 / 3600.0);
+}
+
+double Creature::Mutability() const noexcept {
+ return GetProperties().mutability * (1.0 / 3600.0);
}
void Creature::AddGoal(std::unique_ptr<Goal> &&g) {
situation.SetState(state);
}
+ bg_task->Tick(dt);
+ bg_task->Action();
memory.Tick(dt);
for (auto &need : needs) {
need->Tick(dt);
c.Density(mass / volume);
c.GetSteering().MaxAcceleration(1.4 * std::atan(c.GetProperties().strength));
c.GetSteering().MaxSpeed(4.4 * std::atan(c.GetProperties().dexerty));
+ c.SetBackgroundTask(std::unique_ptr<Goal>(new BlobBackgroundTask(c)));
c.AddGoal(std::unique_ptr<Goal>(new IdleGoal(c)));
}
+#include "BlobBackgroundTask.hpp"
#include "Goal.hpp"
#include "IdleGoal.hpp"
#include "LocateResourceGoal.hpp"
namespace blobs {
namespace creature {
+BlobBackgroundTask::BlobBackgroundTask(Creature &c)
+: Goal(c) {
+}
+
+BlobBackgroundTask::~BlobBackgroundTask() {
+}
+
+std::string BlobBackgroundTask::Describe() const {
+ return "being a blob";
+}
+
+void BlobBackgroundTask::Tick(double dt) {
+}
+
+void BlobBackgroundTask::Action() {
+ // check if eligible to split
+ if (GetCreature().Mass() > GetCreature().GetProperties().Birth().mass * 1.8) {
+ double fert = GetCreature().Fertility();
+ double rand = Assets().random.UNorm();
+ if (fert > rand) {
+ std::cout << "[" << int(GetCreature().GetSimulation().Time())
+ << "s] " << GetCreature().Name() << " split" << std::endl;
+ Split(GetCreature());
+ return;
+ }
+ }
+ // check for random property mutation
+ if (GetCreature().Mutability() > Assets().random.UNorm()) {
+ double amount = 1.0 + (Assets().random.SNorm() * 0.05);
+ auto &props = GetCreature().GetGenome().properties;
+ double r = Assets().random.UNorm();
+ math::Distribution *d = nullptr;
+ if (Assets().random.UNorm() < 0.5) {
+ auto &set = props.props[(int(Assets().random.UNorm() * 4.0) % 4) + 1];
+ if (r < 0.25) {
+ d = &set.age;
+ } else if (r < 0.5) {
+ d = &set.mass;
+ } else if (r < 0.75) {
+ d = &set.fertility;
+ } else {
+ d = &set.highlight;
+ }
+ } else {
+ if (r < 0.2) {
+ d = &props.strength;
+ } else if (r < 0.4) {
+ d = &props.stamina;
+ } else if (r < 0.6) {
+ d = &props.dexerty;
+ } else if (r < 0.8) {
+ d = &props.intelligence;
+ } else {
+ d = &props.mutability;
+ }
+ }
+ if (Assets().random.UNorm() < 0.5) {
+ d->Mean(d->Mean() * amount);
+ } else {
+ d->StandardDeviation(d->StandardDeviation() * amount);
+ }
+ }
+}
+
+
Goal::Goal(Creature &c)
: c(c)
, on_complete()
}
void IdleGoal::Action() {
- // check if eligible to split
- if (GetCreature().Mass() > GetCreature().GetProperties().Birth().mass * 1.8) {
- double fert = GetCreature().Fertility();
- double rand = Assets().random.UNorm();
- if (fert > rand) {
- std::cout << "[" << int(GetCreature().GetSimulation().Time())
- << "s] " << GetCreature().Name() << " split" << std::endl;
- Split(GetCreature());
- }
- }
}
{ }
public:
+ void Mean(double m) noexcept { mean = m; }
double Mean() const noexcept { return mean; }
+ void StandardDeviation(double d) noexcept { stddev = d; }
double StandardDeviation() const noexcept { return stddev; }
double Variance() const noexcept { return stddev * stddev; }
}
double UNorm() noexcept {
- return double(Next<std::uint64_t>()) / double(std::numeric_limits<std::uint64_t>::max());
+ return double(Next<std::uint64_t>()) * (1.0 / double(std::numeric_limits<std::uint64_t>::max()));
}
template<class Container>