// 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()
#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"
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();
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;
--- /dev/null
+#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
double speed;
double damage;
bool ingesting;
+ bool locating;
};
--- /dev/null
+#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
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:
--- /dev/null
+#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
#include "Creature.hpp"
#include "Situation.hpp"
+#include "Steering.hpp"
+#include "Goal.hpp"
#include "InhaleNeed.hpp"
#include "IngestNeed.hpp"
#include "Need.hpp"
#include "../world/Simulation.hpp"
#include "../world/TileType.hpp"
+#include <algorithm>
#include <glm/gtx/transform.hpp>
#include <iostream>
: name()
, health(1.0)
, needs()
+, goals()
, situation()
+, steering()
+, vel(0.0)
, vao() {
}
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 {
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;
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;
+ }
+}
+
}
}
--- /dev/null
+#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?
+ }
+}
+
+}
+}
#include "IngestNeed.hpp"
#include "Creature.hpp"
+#include "LocateResourceGoal.hpp"
#include "../world/Planet.hpp"
#include "../world/TileType.hpp"
: resource(resource)
, speed(speed)
, damage(damage)
-, ingesting(false) {
+, ingesting(false)
+, locating(false) {
}
IngestNeed::~IngestNeed() {
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()) {
# 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
#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
};
std::vector<Yield> resources;
+ std::vector<Yield>::const_iterator FindResource(int) const;
+
};
}
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;
+}
+
}
}