]> git.localhorst.tv Git - blobs.git/commitdiff
eating and drinking
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 23 Nov 2017 23:11:46 +0000 (00:11 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 23 Nov 2017 23:11:46 +0000 (00:11 +0100)
the aim is a bit off so the little guy starves in the end :/

13 files changed:
src/blobs.cpp
src/creature/Creature.hpp
src/creature/Goal.hpp [new file with mode: 0644]
src/creature/IngestNeed.hpp
src/creature/LocateResourceGoal.hpp [new file with mode: 0644]
src/creature/Situation.hpp
src/creature/Steering.hpp [new file with mode: 0644]
src/creature/creature.cpp
src/creature/goal.cpp [new file with mode: 0644]
src/creature/need.cpp
src/graphics/glm.hpp
src/world/TileType.hpp
src/world/world.cpp

index 23ab012fed3a0d31aaca785e327074da2dde6e41..18e62aad75e82d10e6850b45ab81321504ec8bf1 100644 (file)
@@ -80,9 +80,9 @@ int main(int argc, char *argv[]) {
                // sunset
                //.FirstPerson(3, glm::vec3(0.0f, 0.0f, 0.1f), glm::vec3(1.0f, -0.75f, 0.1f))
                // from afar
-               //.MapView(0, glm::vec3(0.0f, 0.0f, 60.0f), 0.0f)
+               .MapView(0, glm::vec3(0.0f, 0.0f, 30.0f), 0.0f)
                // from afar, rotating
-               .Orbital(glm::vec3(-60.0f, 0.0f, 0.0f))
+               //.Orbital(glm::vec3(-60.0f, 0.0f, 0.0f))
        ;
        // system view
        //state.GetCamera()
index 7c3d1ef0f924cad93614a7c8dba26a59d005fbf5..aaeb6cfb544387a654d5017483ee000caed1b10a 100644 (file)
@@ -1,8 +1,10 @@
 #ifndef BLOBS_CREATURE_CREATURE_HPP_
 #define BLOBS_CREATURE_CREATURE_HPP_
 
+#include "Goal.hpp"
 #include "Need.hpp"
 #include "Situation.hpp"
+#include "Steering.hpp"
 #include "../graphics/glm.hpp"
 #include "../graphics/SimpleVAO.hpp"
 
@@ -47,11 +49,20 @@ public:
        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; }
 
+       void AddGoal(std::unique_ptr<Goal> &&);
+       const std::vector<std::unique_ptr<Goal>> &Goals() const noexcept { return goals; }
+
        void Tick(double dt);
 
        Situation &GetSituation() noexcept { return situation; }
        const Situation &GetSituation() const noexcept { return situation; }
 
+       Steering &GetSteering() noexcept { return steering; }
+       const Steering &GetSteering() const noexcept { return steering; }
+
+       void Velocity(const glm::dvec3 &v) noexcept { vel = v; }
+       const glm::dvec3 &Velocity() const noexcept { return vel; }
+
        glm::dmat4 LocalTransform() noexcept;
 
        void BuildVAO();
@@ -60,9 +71,14 @@ public:
 private:
        std::string name;
        double health;
+
        std::vector<std::unique_ptr<Need>> needs;
+       std::vector<std::unique_ptr<Goal>> goals;
 
        Situation situation;
+       Steering steering;
+
+       glm::dvec3 vel;
 
        struct Attributes {
                glm::vec3 position;
diff --git a/src/creature/Goal.hpp b/src/creature/Goal.hpp
new file mode 100644 (file)
index 0000000..d664e6b
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef BLOBS_CREATURE_GOAL_HPP_
+#define BLOBS_CREATURE_GOAL_HPP_
+
+namespace blobs {
+namespace creature {
+
+class Creature;
+
+class Goal {
+
+public:
+       Goal();
+       virtual ~Goal() noexcept;
+
+public:
+       double Urgency() const noexcept { return urgency; }
+       void Urgency(double u) noexcept { urgency = u; }
+
+       bool Interruptible() const noexcept { return interruptible; }
+       void Interruptible(bool i) noexcept { interruptible = i; }
+
+       bool Complete() const noexcept { return complete; }
+       void Complete(bool i) noexcept { complete = i; }
+
+public:
+       virtual void Enable(Creature &) { }
+       virtual void Tick(double dt) { }
+       virtual void Action(Creature &) { }
+
+private:
+       double urgency;
+       bool interruptible;
+       bool complete;
+
+};
+
+}
+}
+
+#endif
index 3ad3bf071d792eab1ad297ca55c5afbd6248b12e..4244293a139dc3e2362b0e9c22ba7ab258daeb44 100644 (file)
@@ -24,6 +24,7 @@ private:
        double speed;
        double damage;
        bool ingesting;
+       bool locating;
 
 };
 
diff --git a/src/creature/LocateResourceGoal.hpp b/src/creature/LocateResourceGoal.hpp
new file mode 100644 (file)
index 0000000..b5d390c
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef BLOBS_CREATURE_LOCATERESOURCEGOAL_HPP_
+#define BLOBS_CREATURE_LOCATERESOURCEGOAL_HPP_
+
+namespace blobs {
+namespace creature {
+
+class LocateResourceGoal
+: public Goal {
+
+public:
+       explicit LocateResourceGoal(int resource);
+       ~LocateResourceGoal() noexcept override;
+
+public:
+       void Enable(Creature &) override;
+       void Tick(double dt) override;
+       void Action(Creature &) override;
+
+private:
+       int res;
+
+};
+
+}
+}
+
+#endif
index d4a376a8d6f25cfdd853cf46ab729553ec353f0a..12b7490914783c6aac2bb9219d0bcd2f2f9c9c82 100644 (file)
@@ -27,6 +27,7 @@ public:
        world::Tile &GetTile() const noexcept;
        const world::TileType &GetTileType() const noexcept;
 
+       void Move(const glm::dvec3 &dp) noexcept;
        void SetPlanetSurface(world::Planet &, int srf, const glm::dvec3 &pos) noexcept;
 
 public:
diff --git a/src/creature/Steering.hpp b/src/creature/Steering.hpp
new file mode 100644 (file)
index 0000000..6d5b40a
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef BLOBS_CREATURE_STEERING_HPP_
+#define BLOBS_CREATURE_STEERING_HPP_
+
+#include "../graphics/glm.hpp"
+
+
+namespace blobs {
+namespace creature {
+
+class Creature;
+
+class Steering {
+
+public:
+       Steering();
+       ~Steering();
+
+public:
+       void MaxAcceleration(double a) noexcept { max_accel = a; }
+       double MaxAcceleration() const noexcept { return max_accel; }
+
+       void MaxSpeed(double s) noexcept { max_speed = s; }
+       double MaxSpeed() const noexcept { return max_speed; }
+
+public:
+       void Halt() noexcept;
+       void GoTo(const glm::dvec3 &) noexcept;
+
+       glm::dvec3 Acceleration(Creature &) const noexcept;
+
+private:
+       bool SumForce(glm::dvec3 &out, const glm::dvec3 &in) const noexcept;
+
+private:
+       glm::dvec3 seek_target;
+
+       double max_accel = 1.0;
+       double max_speed = 1.0;
+
+       bool halting;
+       bool seeking;
+
+};
+
+}
+}
+
+#endif
index de3a4b7dc6d1b19aea9ccb61e345df6950308fef..1278e267135f4748fd125e9ddef6fe5844bb2ba5 100644 (file)
@@ -1,6 +1,8 @@
 #include "Creature.hpp"
 #include "Situation.hpp"
+#include "Steering.hpp"
 
+#include "Goal.hpp"
 #include "InhaleNeed.hpp"
 #include "IngestNeed.hpp"
 #include "Need.hpp"
@@ -10,6 +12,7 @@
 #include "../world/Simulation.hpp"
 #include "../world/TileType.hpp"
 
+#include <algorithm>
 #include <glm/gtx/transform.hpp>
 
 #include <iostream>
@@ -22,7 +25,10 @@ Creature::Creature()
 : name()
 , health(1.0)
 , needs()
+, goals()
 , situation()
+, steering()
+, vel(0.0)
 , vao() {
 }
 
@@ -33,15 +39,50 @@ void Creature::Hurt(double dt) noexcept {
        health = std::max(0.0, health - dt);
 }
 
+void Creature::AddGoal(std::unique_ptr<Goal> &&g) {
+       g->Enable(*this);
+       goals.emplace_back(std::move(g));
+}
+
+namespace {
+
+bool GoalCompare(const std::unique_ptr<Goal> &a, const std::unique_ptr<Goal> &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 {
@@ -229,6 +270,14 @@ 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;
@@ -236,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;
+       }
+}
+
 }
 }
diff --git a/src/creature/goal.cpp b/src/creature/goal.cpp
new file mode 100644 (file)
index 0000000..1b9d5d0
--- /dev/null
@@ -0,0 +1,84 @@
+#include "Goal.hpp"
+#include "LocateResourceGoal.hpp"
+
+#include "Creature.hpp"
+#include "../world/Planet.hpp"
+#include "../world/TileType.hpp"
+
+namespace blobs {
+namespace creature {
+
+Goal::Goal()
+: urgency(0.0)
+, interruptible(true)
+, complete(false) {
+}
+
+Goal::~Goal() noexcept {
+}
+
+
+LocateResourceGoal::LocateResourceGoal(int res)
+: res(res) {
+}
+
+LocateResourceGoal::~LocateResourceGoal() noexcept {
+}
+
+void LocateResourceGoal::Enable(Creature &c) {
+}
+
+void LocateResourceGoal::Tick(double dt) {
+}
+
+void LocateResourceGoal::Action(Creature &c) {
+       if (c.GetSituation().OnSurface()) {
+               const world::TileType &t = c.GetSituation().GetTileType();
+               auto yield = t.FindResource(res);
+               if (yield != t.resources.cend()) {
+                       // hoooray
+                       c.GetSteering().Halt();
+                       Complete(true);
+               } else {
+                       // go find somewhere else
+                       const world::Planet &planet = c.GetSituation().GetPlanet();
+                       double side_length = planet.SideLength();
+                       double offset = side_length * 0.5;
+                       glm::ivec2 loc = glm::ivec2(c.GetSituation().Position() + offset);
+                       glm::ivec2 seek_radius(2);
+                       glm::ivec2 begin(glm::max(glm::ivec2(0), loc - seek_radius));
+                       glm::ivec2 end(glm::min(glm::ivec2(side_length), loc + seek_radius));
+                       const world::TileType::Yield *best = nullptr;
+                       glm::ivec2 best_pos;
+                       double best_distance = 2 * side_length * side_length;
+                       for (int y = begin.y; y < end.y; ++y) {
+                               for (int x = begin.x; x < end.x; ++x) {
+                                       const world::TileType &type = planet.TypeAt(c.GetSituation().Surface(), x, y);
+                                       auto yield = type.FindResource(res);
+                                       if (yield != type.resources.cend()) {
+                                               double dist = glm::length2(glm::dvec3(x - offset + 0.5, y - offset + 0.5, 0.0) - c.GetSituation().Position());
+                                               if (!best) {
+                                                       best = &*yield;
+                                                       best_pos = glm::ivec2(x, y);
+                                                       best_distance = dist;
+                                               } else if (yield->ubiquity + (dist * 0.125) > best->ubiquity + (best_distance * 0.125)) {
+                                                       best = &*yield;
+                                                       best_pos = glm::ivec2(x, y);
+                                                       best_distance = dist;
+                                               }
+                                       }
+                               }
+                       }
+                       if (best) {
+                               c.GetSteering().GoTo(glm::dvec3(best_pos.x - offset + 0.5, best_pos.y - offset + 0.5, 0.0));
+                       } else {
+                               // oh crap
+                       }
+               }
+       } else {
+               // well, what now?
+       }
+}
+
+}
+}
index 8249631038a639925697d9fb4a535d5135a9e1c0..60e7cb816b3a0b8cd375df295da00e80723dbc3a 100644 (file)
@@ -3,6 +3,7 @@
 #include "IngestNeed.hpp"
 
 #include "Creature.hpp"
+#include "LocateResourceGoal.hpp"
 #include "../world/Planet.hpp"
 #include "../world/TileType.hpp"
 
@@ -30,7 +31,8 @@ IngestNeed::IngestNeed(int resource, double speed, double damage)
 : resource(resource)
 , speed(speed)
 , damage(damage)
-, ingesting(false) {
+, ingesting(false)
+, locating(false) {
 }
 
 IngestNeed::~IngestNeed() {
@@ -40,16 +42,26 @@ void IngestNeed::ApplyEffect(Creature &c, double dt) {
        if (!IsSatisfied()) {
                ingesting = true;
        }
-       if (!IsSatisfied()) {
-               // TODO: find resource and start ingest task
+       if (ingesting) {
                if (c.GetSituation().OnSurface()) {
                        const world::TileType &t = c.GetSituation().GetTileType();
+                       bool found = false;
                        for (auto &yield : t.resources) {
                                if (yield.resource == resource) {
+                                       found = true;
+                                       // TODO: check if not busy with something else
                                        Decrease(std::min(yield.ubiquity, speed) * dt);
+                                       if (value == 0.0) {
+                                               ingesting = false;
+                                               locating = false;
+                                       }
                                        break;
                                }
                        }
+                       if (!found && !locating) {
+                               c.AddGoal(std::unique_ptr<Goal>(new LocateResourceGoal(resource)));
+                               locating = true;
+                       }
                }
        }
        if (IsCritical()) {
index 1c39ba5e059ae75ff48d187d0a022b1fbb8154fd..8003f0b751ada30fa9aff5fe6bea160afd2eb497 100644 (file)
@@ -5,7 +5,10 @@
 #  define GLM_FORCE_RADIANS 1
 #endif
 
+#include <limits>
 #include <glm/glm.hpp>
+#include <glm/gtx/norm.hpp>
+#include <glm/gtx/component_wise.hpp>
 
 // GLM moved tvec[1234] from glm::detail to glm in 0.9.6
 
@@ -20,4 +23,17 @@ namespace glm {
 
 #endif
 
+template <class T>
+inline bool allzero(const T &v) noexcept {
+       return glm::length2(v) <
+               std::numeric_limits<typename T::value_type>::epsilon()
+               * std::numeric_limits<typename T::value_type>::epsilon();
+}
+
+template <class T>
+inline bool anynan(const T &v) noexcept {
+       return glm::any(glm::isnan(v));
+}
+
+
 #endif
index c4eadcfc899a93eeb979f5a91638c8faec8c8e60..b5561fffa7a014875975c1325b96f84a456883a2 100644 (file)
@@ -22,6 +22,8 @@ struct TileType {
        };
        std::vector<Yield> resources;
 
+       std::vector<Yield>::const_iterator FindResource(int) const;
+
 };
 
 }
index 449307abeefbeeb88ea148171600aed8b2e1a596..0f9cb1e373d36d1ad8b20e2719b1dbadb5736f5b 100644 (file)
@@ -535,5 +535,16 @@ Sun::Sun()
 Sun::~Sun() {
 }
 
+
+std::vector<TileType::Yield>::const_iterator TileType::FindResource(int r) const {
+       auto yield = resources.cbegin();
+       for (; yield != resources.cend(); ++yield) {
+               if (yield->resource == r) {
+                       break;
+               }
+       }
+       return yield;
+}
+
 }
 }