From: Daniel Karbach Date: Wed, 22 Nov 2017 21:18:44 +0000 (+0100) Subject: abstract needs a little X-Git-Url: http://git.localhorst.tv/?p=blobs.git;a=commitdiff_plain;h=e59f3058d8786dc0a053c42bcec8f01b22ec25a9 abstract needs a little and let the little sucker breathe for a change --- diff --git a/src/creature/Creature.hpp b/src/creature/Creature.hpp index f4c0004..7c3d1ef 100644 --- a/src/creature/Creature.hpp +++ b/src/creature/Creature.hpp @@ -6,6 +6,7 @@ #include "../graphics/glm.hpp" #include "../graphics/SimpleVAO.hpp" +#include #include #include @@ -41,9 +42,10 @@ public: void Health(double h) noexcept { health = h; } double Health() const noexcept { return health; } + void Hurt(double d) noexcept; - void AddNeed(const Need &n) { needs.push_back(n); } - const std::vector &Needs() const noexcept { return needs; } + void AddNeed(std::unique_ptr &&n) { needs.emplace_back(std::move(n)); } + const std::vector> &Needs() const noexcept { return needs; } void Tick(double dt); @@ -58,7 +60,7 @@ public: private: std::string name; double health; - std::vector needs; + std::vector> needs; Situation situation; diff --git a/src/creature/IngestNeed.hpp b/src/creature/IngestNeed.hpp new file mode 100644 index 0000000..b64ee0c --- /dev/null +++ b/src/creature/IngestNeed.hpp @@ -0,0 +1,32 @@ +#ifndef BLOBS_CREATURE_INGESTNEED_HPP_ +#define BLOBS_CREATURE_INGESTNEED_HPP_ + +#include "Need.hpp" + + +namespace blobs { +namespace creature { + +class Need; + +class IngestNeed +: public Need { + +public: + IngestNeed(int resource, double speed, double damage); + ~IngestNeed() override; + +public: + void ApplyEffect(Creature &, double dt) override; + +private: + int resource; + double speed; + double damage; + +}; + +} +} + +#endif diff --git a/src/creature/InhaleNeed.hpp b/src/creature/InhaleNeed.hpp new file mode 100644 index 0000000..365bb04 --- /dev/null +++ b/src/creature/InhaleNeed.hpp @@ -0,0 +1,32 @@ +#ifndef BLOBS_CREATURE_INHALENEED_HPP_ +#define BLOBS_CREATURE_INHALENEED_HPP_ + +#include "Need.hpp" + + +namespace blobs { +namespace creature { + +class Need; + +class InhaleNeed +: public Need { + +public: + InhaleNeed(int resource, double speed, double damage); + ~InhaleNeed() override; + +public: + void ApplyEffect(Creature &, double dt) override; + +private: + int resource; + double speed; + double damage; + +}; + +} +} + +#endif diff --git a/src/creature/Need.hpp b/src/creature/Need.hpp index 93d46e8..2fd4898 100644 --- a/src/creature/Need.hpp +++ b/src/creature/Need.hpp @@ -1,24 +1,37 @@ #ifndef BLOBS_CREATURE_NEED_HPP_ #define BLOBS_CREATURE_NEED_HPP_ +#include + + namespace blobs { namespace creature { +class Creature; +class Effect; + struct Need { - int resource = -1; + std::string name; + double value = 0.0; // how fast value grows per second double gain = 0.0; // the value at which this need is no longer satisfied + double inconvenient = 0.0; + // the value at which this need starts to hurt double critical = 0.0; - // the price to pay for not satsfying the need - double penalty = 0.0; + + virtual ~Need() noexcept; void Tick(double dt) noexcept; - bool IsSatisfied() const noexcept { return value < critical; } + bool IsSatisfied() const noexcept { return value < inconvenient; } + bool IsInconvenient() const noexcept { return value >= inconvenient && value < critical; } + bool IsCritical() const noexcept { return value >= critical; } + + virtual void ApplyEffect(Creature &, double dt) = 0; }; diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index f279641..3c4f544 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -1,7 +1,9 @@ #include "Creature.hpp" -#include "Need.hpp" #include "Situation.hpp" +#include "InhaleNeed.hpp" +#include "IngestNeed.hpp" +#include "Need.hpp" #include "../app/Assets.hpp" #include "../world/Body.hpp" #include "../world/Planet.hpp" @@ -26,13 +28,18 @@ Creature::Creature() Creature::~Creature() { } +void Creature::Hurt(double dt) noexcept { + health = std::max(0.0, health - dt); +} void Creature::Tick(double dt) { - for (Need &need : needs) { - need.Tick(dt); - if (!need.IsSatisfied()) { - health = std::max(0.0, health - need.penalty * dt); - } + // update needs + for (auto &need : needs) { + need->Tick(dt); + } + // do background stuff + for (auto &need : needs) { + need->ApplyEffect(*this, dt); } } @@ -164,39 +171,33 @@ void Spawn(Creature &c, world::Planet &p, app::Assets &assets) { if (p.HasAtmosphere()) { std::cout << "require breathing " << assets.data.resources[p.Atmosphere()].label << std::endl; - Need need; - need.resource = p.Atmosphere(); - need.gain = 0.25; - need.critical = 0.95; - need.penalty = 0.1; - c.AddNeed(need); + std::unique_ptr need(new InhaleNeed(p.Atmosphere(), 0.25, 0.1)); + need->name = assets.data.resources[p.Atmosphere()].label; + need->gain = 0.25; + need->inconvenient = 0.4; + need->critical = 0.95; + c.AddNeed(std::move(need)); } if (liquid > -1) { std::cout << "require drinking " << assets.data.resources[liquid].label << std::endl; - Need need; - need.resource = liquid; - need.gain = 0.0001; - need.critical = 0.95; - need.penalty = 0.01; - c.AddNeed(need); + std::unique_ptr need(new IngestNeed(liquid, 0.2, 0.01)); + need->name = assets.data.resources[liquid].label; + need->gain = 0.0001; + 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; - Need need; - need.resource = solid; - need.gain = 0.00001; - need.critical = 0.95; - need.penalty = 0.001; - c.AddNeed(need); + std::unique_ptr need(new IngestNeed(solid, 0.03, 0.001)); + need->name = assets.data.resources[solid].label; + need->gain = 0.00001; + need->inconvenient = 0.6; + need->critical = 0.95; + c.AddNeed(std::move(need)); } } - -void Need::Tick(double dt) noexcept { - value = std::min(1.0, value + gain * dt); -} - - Situation::Situation() : planet(nullptr) , position(0.0) diff --git a/src/creature/need.cpp b/src/creature/need.cpp new file mode 100644 index 0000000..b569500 --- /dev/null +++ b/src/creature/need.cpp @@ -0,0 +1,63 @@ +#include "Need.hpp" +#include "InhaleNeed.hpp" +#include "IngestNeed.hpp" + +#include "Creature.hpp" +#include "../world/Planet.hpp" + + +namespace blobs { +namespace creature { + +Need::~Need() { +} + +void Need::Tick(double dt) noexcept { + value = std::min(1.0, value + gain * dt); +} + + +IngestNeed::IngestNeed(int resource, double speed, double damage) +: resource(resource) +, speed(speed) +, damage(damage) { +} + +IngestNeed::~IngestNeed() { +} + +void IngestNeed::ApplyEffect(Creature &c, double dt) { + if (!IsSatisfied()) { + // TODO: find resource and start ingest task + } + if (IsCritical()) { + c.Hurt(damage * dt); + } +} + + +InhaleNeed::InhaleNeed(int resource, double speed, double damage) +: resource(resource) +, speed(speed) +, damage(damage) { +} + +InhaleNeed::~InhaleNeed() { +} + +void InhaleNeed::ApplyEffect(Creature &c, double dt) { + if (!IsSatisfied()) { + // TODO: make condition more natural with thresholds and stuff + if (c.GetSituation().OnPlanet() && c.GetSituation().GetPlanet().Atmosphere() == resource) { + value = std::max(0.0, value - (speed * dt)); + } else { + // TODO: panic + } + } + if (IsCritical()) { + c.Hurt(damage * dt); + } +} + +} +} diff --git a/src/ui/CreaturePanel.hpp b/src/ui/CreaturePanel.hpp index 76455d9..3a33b8c 100644 --- a/src/ui/CreaturePanel.hpp +++ b/src/ui/CreaturePanel.hpp @@ -48,7 +48,8 @@ private: Panel *needs; Panel panel; - std::vector meters; + Meter *health_meter; + std::vector need_meters; }; diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 7ad47da..cedbcd1 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -4,6 +4,7 @@ #include "Meter.hpp" #include "../app/Assets.hpp" #include "../creature/Creature.hpp" +#include "../creature/Need.hpp" #include "../graphics/Viewport.hpp" #include @@ -17,9 +18,25 @@ CreaturePanel::CreaturePanel(const app::Assets &assets) , c(nullptr) , name(new Label(assets.fonts.large)) , needs(new Panel) -, panel() { +, panel() +, health_meter(new Meter) +, need_meters() { + Label *health_label = new Label(assets.fonts.medium); + health_label->Text("Health"); + health_meter + ->Size(glm::vec2(100.0f, assets.fonts.medium.Height() + assets.fonts.medium.Descent())) + ->Padding(glm::vec2(1.0f)) + ->Border(1.0f) + ->FillColor(glm::vec4(0.9f, 0.0f, 0.0f, 1.0f)) + ->BorderColor(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + Panel *health_panel = new Panel; + health_panel + ->Add(health_label) + ->Add(health_meter) + ->Direction(Panel::HORIZONTAL); panel .Add(name) + ->Add(health_panel) ->Add(needs) ->Padding(glm::vec2(10.0f)) ->Spacing(10.0f) @@ -39,15 +56,14 @@ void CreaturePanel::Show(creature::Creature &cr) { void CreaturePanel::CreateNeeds() { needs->Clear()->Reserve(c->Needs().size()); - meters.clear(); - meters.reserve(c->Needs().size()); + need_meters.clear(); + need_meters.reserve(c->Needs().size()); for (auto &need : c->Needs()) { Label *label = new Label(assets.fonts.medium); - label - ->Text(assets.data.resources[need.resource].label); + label->Text(need->name); Meter *meter = new Meter; meter - ->Value(1.0f - need.value) + ->Value(1.0f - need->value) ->Size(glm::vec2(100.0f, assets.fonts.medium.Height() + assets.fonts.medium.Descent())) ->Padding(glm::vec2(1.0f)) ->Border(1.0f) @@ -60,7 +76,7 @@ void CreaturePanel::CreateNeeds() { ->Add(label) ->Add(meter); needs->Add(need_panel); - meters.push_back(meter); + need_meters.push_back(meter); } panel.Relayout(); } @@ -72,16 +88,23 @@ void CreaturePanel::Hide() noexcept { void CreaturePanel::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept { if (!c) return; - if (meters.size() != c->Needs().size()) { + health_meter->Value(c->Health()); + + if (need_meters.size() != c->Needs().size()) { CreateNeeds(); } else { auto need = c->Needs().begin(); auto need_end = c->Needs().end(); - auto meter = meters.begin(); + auto meter = need_meters.begin(); for (; need != need_end; ++need, ++meter) { - (*meter)->Value(1.0f - need->value)->FillColor(need->IsSatisfied() - ? glm::vec4(0.0f, 0.0f, 0.0f, 1.0f) - : glm::vec4(1.0f, 0.0f, 0.0f, 1.0f)); + (*meter)->Value(1.0f - (*need)->value); + if ((*need)->IsSatisfied()) { + (*meter)->FillColor(glm::vec4(0.0f, 0.7f, 0.0f, 1.0f)); + } else if ((*need)->IsInconvenient()) { + (*meter)->FillColor(glm::vec4(0.7f, 0.5f, 0.0f, 1.0f)); + } else { + (*meter)->FillColor(glm::vec4(0.9f, 0.0f, 0.0f, 1.0f)); + } } }