X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fcreature%2Fcreature.cpp;h=1278e267135f4748fd125e9ddef6fe5844bb2ba5;hb=8a3907bb0bed257bf5d6f40f39f15114e8345913;hp=66931e921f58d06e5c227d1b3035f697203886d4;hpb=7c0cb00fac415d393fc3c3397caeb97e31235e69;p=blobs.git diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index 66931e9..1278e26 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -1,14 +1,18 @@ #include "Creature.hpp" #include "Situation.hpp" +#include "Steering.hpp" +#include "Goal.hpp" #include "InhaleNeed.hpp" #include "IngestNeed.hpp" #include "Need.hpp" #include "../app/Assets.hpp" #include "../world/Body.hpp" #include "../world/Planet.hpp" +#include "../world/Simulation.hpp" #include "../world/TileType.hpp" +#include #include #include @@ -21,7 +25,10 @@ Creature::Creature() : name() , health(1.0) , needs() +, goals() , situation() +, steering() +, vel(0.0) , vao() { } @@ -32,15 +39,50 @@ void Creature::Hurt(double dt) noexcept { health = std::max(0.0, health - dt); } +void Creature::AddGoal(std::unique_ptr &&g) { + g->Enable(*this); + goals.emplace_back(std::move(g)); +} + +namespace { + +bool GoalCompare(const std::unique_ptr &a, const std::unique_ptr &b) { + return b->Urgency() < a->Urgency(); +} + +} + void Creature::Tick(double dt) { - // update needs + // TODO: better integration method + glm::dvec3 acc(steering.Acceleration(*this)); + situation.Move(vel * dt); + vel += acc * dt; + for (auto &need : needs) { need->Tick(dt); } + for (auto &goal : goals) { + goal->Tick(dt); + } // do background stuff for (auto &need : needs) { need->ApplyEffect(*this, dt); } + if (goals.empty()) { + return; + } + // if active goal can be interrupted, check priorities + if (goals.size() > 1 && goals[0]->Interruptible()) { + std::sort(goals.begin(), goals.end(), GoalCompare); + } + goals[0]->Action(*this); + for (auto goal = goals.begin(); goal != goals.end();) { + if ((*goal)->Complete()) { + goals.erase(goal); + } else { + ++goal; + } + } } glm::dmat4 Creature::LocalTransform() noexcept { @@ -149,7 +191,7 @@ void Spawn(Creature &c, world::Planet &p, app::Assets &assets) { std::map yields; for (int y = start; y < end; ++y) { for (int x = start; x < end; ++x) { - const world::TileType &t = assets.data.tiles[p.TileAt(0, x, y).type]; + const world::TileType &t = assets.data.tile_types[p.TileAt(0, x, y).type]; for (auto yield : t.resources) { yields[yield.resource] += yield.ubiquity; } @@ -182,16 +224,16 @@ void Spawn(Creature &c, world::Planet &p, app::Assets &assets) { std::cout << "require drinking " << assets.data.resources[liquid].label << std::endl; std::unique_ptr need(new IngestNeed(liquid, 0.2, 0.01)); need->name = assets.data.resources[liquid].label; - need->gain = 0.0001; + need->gain = 0.01; need->inconvenient = 0.6; need->critical = 0.95; c.AddNeed(std::move(need)); } if (solid > -1) { std::cout << "require eating " << assets.data.resources[solid].label << std::endl; - std::unique_ptr need(new IngestNeed(solid, 0.03, 0.001)); + std::unique_ptr need(new IngestNeed(solid, 0.1, 0.001)); need->name = assets.data.resources[solid].label; - need->gain = 0.00001; + need->gain = 0.007; need->inconvenient = 0.6; need->critical = 0.95; c.AddNeed(std::move(need)); @@ -212,6 +254,30 @@ bool Situation::OnPlanet() const noexcept { return type == PLANET_SURFACE; } +bool Situation::OnSurface() const noexcept { + return type == PLANET_SURFACE; +} + +world::Tile &Situation::GetTile() const noexcept { + double side_length = planet->SideLength(); + double offset = side_length * 0.5; + double x = std::max(0.0, std::min(side_length, position.x + offset)); + double y = std::max(0.0, std::min(side_length, position.y + offset)); + return planet->TileAt(surface, int(x), int(y)); +} + +const world::TileType &Situation::GetTileType() const noexcept { + return planet->GetSimulation().TileTypes()[GetTile().type]; +} + +void Situation::Move(const glm::dvec3 &dp) noexcept { + position += dp; + if (OnSurface()) { + // enforce ground constraint + position.z = std::max(0.0, position.z); + } +} + void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &pos) noexcept { type = PLANET_SURFACE; planet = &p; @@ -219,5 +285,63 @@ void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &po position = pos; } + +Steering::Steering() +: seek_target(0.0) +, max_accel(1.0) +, max_speed(1.0) +, halting(false) +, seeking(false) { +} + +Steering::~Steering() { +} + +void Steering::Halt() noexcept { + halting = true; + seeking = false; +} + +void Steering::GoTo(const glm::dvec3 &t) noexcept { + seek_target = t; + halting = false; + seeking = true; +} + +glm::dvec3 Steering::Acceleration(Creature &c) const noexcept { + glm::dvec3 acc(0.0); + if (halting) { + SumForce(acc, c.Velocity() * -max_accel); + } + if (seeking) { + glm::dvec3 diff = seek_target - c.GetSituation().Position(); + if (!allzero(diff)) { + SumForce(acc, ((normalize(diff) * max_speed) - c.Velocity()) * max_accel); + } + } + return acc; +} + +bool Steering::SumForce(glm::dvec3 &out, const glm::dvec3 &in) const noexcept { + if (allzero(in) || anynan(in)) { + return false; + } + double cur = allzero(out) ? 0.0 : length(out); + double rem = max_accel - cur; + if (rem < 0.0) { + return true; + } + double add = length(in); + if (add > rem) { + // this method is off if in and out are in different + // directions, but gives okayish results + out += in * (1.0 / add); + return true; + } else { + out += in; + return false; + } +} + } }