From: Daniel Karbach Date: Tue, 28 Nov 2017 22:33:11 +0000 (+0100) Subject: fix AI X-Git-Url: http://git.localhorst.tv/?p=blobs.git;a=commitdiff_plain;h=6c1097479fd1ea41f0f76b91e67613822acf2e90 fix AI lol duh --- diff --git a/src/creature/Creature.hpp b/src/creature/Creature.hpp index f36a2db..d3cd86c 100644 --- a/src/creature/Creature.hpp +++ b/src/creature/Creature.hpp @@ -58,7 +58,7 @@ public: const Genome::Properties &GetProperties() const noexcept { return properties; } const Genome::PropertySet &CurProps() const noexcept { return properties.props[cur_prop]; } - const Genome::PropertySet &NextProps() const noexcept { return properties.props[cur_prop + 1]; } + const Genome::PropertySet &NextProps() const noexcept { return properties.props[std::min(5, cur_prop + 1)]; } void BaseColor(const glm::dvec3 &c) noexcept { base_color = c; } const glm::dvec3 &BaseColor() const noexcept { return base_color; } @@ -68,13 +68,14 @@ public: void Mass(double m) noexcept { mass = m; size = std::cbrt(mass / density); } double Mass() const noexcept { return mass; } - void Grow(double amount) noexcept; + void Ingest(int res, double amount) noexcept; void Density(double d) noexcept { density = d; size = std::cbrt(mass / density); } double Density() const noexcept { return density; } double Size() const noexcept; double Age() const noexcept; + std::string AgeName() const; double AgeLerp(double from, double to) const noexcept; // change of giving birth per tick double Fertility() const noexcept; diff --git a/src/creature/Genome.hpp b/src/creature/Genome.hpp index b14efc1..3361fde 100644 --- a/src/creature/Genome.hpp +++ b/src/creature/Genome.hpp @@ -20,9 +20,13 @@ struct Genome { template struct PropertySet { + /// the age at which to transition to the next phase T age; + /// maximum body mass T mass; + /// fertility factor T fertility; + /// skin highlight pronounciation T highlight; }; template @@ -40,6 +44,20 @@ struct Genome { const PropertySet &Elder() const noexcept { return props[4]; } PropertySet &Death() noexcept { return props[5]; } const PropertySet &Death() const noexcept { return props[5]; } + + /// "typical" properties + /// every one of these should have at least one + /// negative impact to prevent super-beings evolving + /// power at the cost of higher solid intake + T strength; + /// more endurance at the cost of higher liquid intake + T stamina; + /// more speed at the cost of higher fatigue + T dexerty; + /// higher mental capacity at the cost of boredom + T intelligence; + /// how likely to mutate + T mutability; }; Properties properties; @@ -87,7 +105,12 @@ struct Genome { Instantiate(p.props[2], rand), Instantiate(p.props[3], rand), Instantiate(p.props[4], rand), - Instantiate(p.props[5], rand) + Instantiate(p.props[5], rand), + p.strength.FakeNormal(rand.SNorm()), + p.stamina.FakeNormal(rand.SNorm()), + p.dexerty.FakeNormal(rand.SNorm()), + p.intelligence.FakeNormal(rand.SNorm()), + p.mutability.FakeNormal(rand.SNorm()) }; } diff --git a/src/creature/Situation.hpp b/src/creature/Situation.hpp index a12f422..f29d9b0 100644 --- a/src/creature/Situation.hpp +++ b/src/creature/Situation.hpp @@ -56,6 +56,7 @@ public: void SetState(const State &s) noexcept { state = s; } const State &GetState() const noexcept { return state; } + const glm::dvec3 &Velocity() const noexcept { return state.vel; } bool Moving() const noexcept { return glm::length2(state.vel) < 0.00000001; } void Move(const glm::dvec3 &dp) noexcept; void SetPlanetSurface(world::Planet &, int srf, const glm::dvec3 &pos) noexcept; diff --git a/src/creature/Steering.hpp b/src/creature/Steering.hpp index 3ccf9e3..cca757e 100644 --- a/src/creature/Steering.hpp +++ b/src/creature/Steering.hpp @@ -23,21 +23,24 @@ public: public: void Halt() noexcept; + void Pass(const glm::dvec3 &) noexcept; void GoTo(const glm::dvec3 &) noexcept; glm::dvec3 Acceleration(const Situation::State &) const noexcept; private: bool SumForce(glm::dvec3 &out, const glm::dvec3 &in) const noexcept; + glm::dvec3 TargetVelocity(const Situation::State &, const glm::dvec3 &) const noexcept; private: - glm::dvec3 seek_target; + glm::dvec3 target; double max_accel = 1.0; double max_speed = 1.0; bool halting; bool seeking; + bool arriving; }; diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index 92fa367..456e081 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -57,9 +57,20 @@ glm::dvec4 Creature::HighlightColor() const noexcept { return glm::dvec4(highlight_color, AgeLerp(CurProps().highlight, NextProps().highlight)); } -void Creature::Grow(double amount) noexcept { - const double max_mass = AgeLerp(CurProps().mass, NextProps().mass); - Mass(std::min(max_mass, mass + amount)); +void Creature::Ingest(int res, double amount) noexcept { + const Genome::Composition *cmp = nullptr; + for (const auto &c : genome.composition) { + if (c.resource == res) { + cmp = &c; + break; + } + } + if (cmp) { + const double max_mass = AgeLerp(CurProps().mass, NextProps().mass); + Mass(std::min(max_mass, mass + amount)); + } else { + // foreign material. poisonous? + } } void Creature::Hurt(double dt) noexcept { @@ -89,6 +100,25 @@ double Creature::Age() const noexcept { return sim.Time() - birth; } +std::string Creature::AgeName() const { + switch (cur_prop) { + case 0: + return "Newborn"; + case 1: + return "Child"; + case 2: + return "Youth"; + case 3: + return "Adult"; + case 4: + return "Elder"; + case 5: + return "Dead"; + default: + return "Unknown"; + } +} + double Creature::AgeLerp(double from, double to) const noexcept { return glm::mix(from, to, glm::smoothstep(CurProps().age, NextProps().age, Age())); } @@ -112,13 +142,12 @@ bool GoalCompare(const std::unique_ptr &a, const std::unique_ptr &b) } void Creature::Tick(double dt) { - if (cur_prop < 5 && Age() > properties.props[cur_prop + 1].age) { - if (cur_prop == 4) { + if (cur_prop < 5 && Age() > NextProps().age) { + ++cur_prop; + if (cur_prop == 5) { std::cout << "[" << int(sim.Time()) << "s] " << name << " died of old age" << std::endl; Die(); - } else { - ++cur_prop; } } @@ -339,6 +368,12 @@ void Spawn(Creature &c, world::Planet &p) { genome.properties.Death().fertility = { 0.0, 0.0 }; genome.properties.Death().highlight = { 0.5, 0.1 }; + genome.properties.strength = { 1.0, 0.1 }; + genome.properties.stamina = { 1.0, 0.1 }; + genome.properties.dexerty = { 1.0, 0.1 }; + genome.properties.intelligence = { 1.0, 0.1 }; + genome.properties.mutability = { 1.0, 0.1 }; + glm::dvec3 color_avg(0.0); double color_divisor = 0.0; @@ -397,6 +432,7 @@ void Genome::Configure(Creature &c) const { double mass = 0.0; double volume = 0.0; for (const auto &comp : composition) { + const world::Resource &resource = c.GetSimulation().Resources()[comp.resource]; double comp_mass = comp.mass.FakeNormal(random.SNorm()); double intake = comp.intake.FakeNormal(random.SNorm()); double penalty = comp.penalty.FakeNormal(random.SNorm()); @@ -405,10 +441,12 @@ void Genome::Configure(Creature &c) const { volume += comp_mass / c.GetSimulation().Resources()[comp.resource].density; std::unique_ptr need; - if (c.GetSimulation().Resources()[comp.resource].state == world::Resource::SOLID) { + if (resource.state == world::Resource::SOLID) { + intake *= std::atan(c.GetProperties().strength); need.reset(new IngestNeed(comp.resource, intake, penalty)); need->gain = intake * 0.05; - } else if (c.GetSimulation().Resources()[comp.resource].state == world::Resource::LIQUID) { + } else if (resource.state == world::Resource::LIQUID) { + intake *= std::atan(c.GetProperties().stamina); need.reset(new IngestNeed(comp.resource, intake, penalty)); need->gain = intake * 0.1; } else { @@ -416,7 +454,6 @@ void Genome::Configure(Creature &c) const { need->gain = intake * 0.5; } need->name = c.GetSimulation().Resources()[comp.resource].label; - need->growth = comp.growth.FakeNormal(random.SNorm()); need->inconvenient = 0.5; need->critical = 0.95; c.AddNeed(std::move(need)); @@ -437,8 +474,8 @@ void Genome::Configure(Creature &c) const { c.Mass(c.GetProperties().props[0].mass); c.Density(mass / volume); - c.GetSteering().MaxAcceleration(1.4); - c.GetSteering().MaxSpeed(4.4); + c.GetSteering().MaxAcceleration(1.4 * std::atan(c.GetProperties().strength)); + c.GetSteering().MaxSpeed(4.4 * std::atan(c.GetProperties().dexerty)); c.AddGoal(std::unique_ptr(new IdleGoal(c))); } @@ -576,11 +613,12 @@ void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &po Steering::Steering() -: seek_target(0.0) +: target(0.0) , max_accel(1.0) , max_speed(1.0) , halting(false) -, seeking(false) { +, seeking(false) +, arriving(false) { } Steering::~Steering() { @@ -589,12 +627,21 @@ Steering::~Steering() { void Steering::Halt() noexcept { halting = true; seeking = false; + arriving = false; } -void Steering::GoTo(const glm::dvec3 &t) noexcept { - seek_target = t; +void Steering::Pass(const glm::dvec3 &t) noexcept { + target = t; halting = false; seeking = true; + arriving = false; +} + +void Steering::GoTo(const glm::dvec3 &t) noexcept { + target = t; + halting = false; + seeking = false; + arriving = true; } glm::dvec3 Steering::Acceleration(const Situation::State &s) const noexcept { @@ -603,9 +650,16 @@ glm::dvec3 Steering::Acceleration(const Situation::State &s) const noexcept { SumForce(acc, s.vel * -max_accel); } if (seeking) { - glm::dvec3 diff = seek_target - s.pos; + glm::dvec3 diff = target - s.pos; if (!allzero(diff)) { - SumForce(acc, ((normalize(diff) * max_speed) - s.vel) * max_accel); + SumForce(acc, TargetVelocity(s, (normalize(diff) * max_speed))); + } + } + if (arriving) { + glm::dvec3 diff = target - s.pos; + double dist = length(diff); + if (!allzero(diff) && dist > std::numeric_limits::epsilon()) { + SumForce(acc, TargetVelocity(s, diff * std::min(dist * max_accel, max_speed) / dist)); } } return acc; @@ -632,5 +686,9 @@ bool Steering::SumForce(glm::dvec3 &out, const glm::dvec3 &in) const noexcept { } } +glm::dvec3 Steering::TargetVelocity(const Situation::State &s, const glm::dvec3 &vel) const noexcept { + return (vel - s.vel) * max_accel; +} + } } diff --git a/src/creature/goal.cpp b/src/creature/goal.cpp index ee51a91..9c45a34 100644 --- a/src/creature/goal.cpp +++ b/src/creature/goal.cpp @@ -130,8 +130,7 @@ void LocateResourceGoal::Action() { } else { double dist = glm::length2(GetSituation().Position() - target_pos); if (dist < 0.0001) { - GetSteering().Halt(); - searching = false; + LocateResource(); } else { GetSteering().GoTo(target_pos); } @@ -212,6 +211,8 @@ void LocateResourceGoal::SearchVicinity() { target_pos = GetSituation().Position(); target_pos[(srf + 0) % 3] += Assets().random.SNorm(); target_pos[(srf + 1) % 3] += Assets().random.SNorm(); + // bias towards current direction + target_pos += glm::normalize(GetSituation().Velocity()) * 0.5; GetSteering().GoTo(target_pos); } } diff --git a/src/creature/need.cpp b/src/creature/need.cpp index 1b832b7..576655a 100644 --- a/src/creature/need.cpp +++ b/src/creature/need.cpp @@ -51,7 +51,7 @@ void IngestNeed::ApplyEffect(Creature &c, double dt) { found = true; // TODO: check if not busy with something else double amount = std::min(yield.ubiquity, speed) * dt; - c.Grow(amount * growth * dt); + c.Ingest(resource, amount * growth * dt); Decrease(amount); if (value == 0.0) { ingesting = false; diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index c53426a..e62894d 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -43,7 +43,7 @@ CreaturePanel::CreaturePanel(const app::Assets &assets) ->Spacing(10.0f) ->Direction(Panel::HORIZONTAL); - age->Text("0000s"); + age->Text("0000s (Newborn)"); Label *age_label = new Label(assets.fonts.medium); age_label->Text("Age"); Panel *age_panel = new Panel; @@ -152,7 +152,7 @@ void CreaturePanel::Hide() noexcept { void CreaturePanel::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept { if (!c) return; - age->Text(std::to_string(int(c->Age())) + "s"); + age->Text(std::to_string(int(c->Age())) + "s (" + c->AgeName() + ")"); { std::stringstream ss; ss << std::fixed << std::setprecision(3) << c->Mass() << "kg";