From: Daniel Karbach Date: Fri, 23 Oct 2015 15:12:30 +0000 (+0200) Subject: AI state machine X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=d122d3e445d64f7d710c1cfaf285ff01bbe955b9;p=blank.git AI state machine only one state atm, but it's a start --- diff --git a/src/ai/AIController.hpp b/src/ai/AIController.hpp index 53bdc82..0eca2b7 100644 --- a/src/ai/AIController.hpp +++ b/src/ai/AIController.hpp @@ -8,6 +8,7 @@ namespace blank { +class AIState; class GaloisLFSR; class AIController @@ -17,20 +18,38 @@ public: explicit AIController(GaloisLFSR &); ~AIController(); + void SetState(const AIState &); + void Update(Entity &, float dt) override; glm::vec3 ControlForce(const EntityState &) const override; static glm::vec3 Heading(const EntityState &) noexcept; + void StartFleeing(const Entity &, float speed) noexcept; + void StopFleeing() noexcept; + bool IsFleeing() const noexcept; + const Entity &GetFleeTarget() const noexcept; + + void StartSeeking(const Entity &, float speed) noexcept; + void StopSeeking() noexcept; + bool IsSeeking() const noexcept; + const Entity &GetSeekTarget() const noexcept; + + void StartWandering() noexcept; + void StopWandering() noexcept; + private: GaloisLFSR &random; + const AIState *state; - float chase_speed; + const Entity *flee_target; float flee_speed; - float stop_dist; - float flee_dist; + const Entity *seek_target; + float seek_speed; + + bool wandering; glm::vec3 wander_pos; float wander_dist; float wander_radius; diff --git a/src/ai/AIState.hpp b/src/ai/AIState.hpp new file mode 100644 index 0000000..ed82cc0 --- /dev/null +++ b/src/ai/AIState.hpp @@ -0,0 +1,17 @@ +#ifndef BLANK_AI_AISTATE_HPP_ +#define BLANK_AI_AISTATE_HPP_ + + +namespace blank { + +struct AIState { + + virtual void Enter(AIController &) const = 0; + virtual void Update(AIController &, Entity &, float dt) const = 0; + virtual void Exit(AIController &) const = 0; + +}; + +} + +#endif diff --git a/src/ai/IdleState.hpp b/src/ai/IdleState.hpp new file mode 100644 index 0000000..76358f8 --- /dev/null +++ b/src/ai/IdleState.hpp @@ -0,0 +1,20 @@ +#ifndef BLANK_AI_IDLESTATE_HPP_ +#define BLANK_AI_IDLESTATE_HPP_ + +#include "AIState.hpp" + + +namespace blank { + +class IdleState +: public AIState { + + void Enter(AIController &) const override; + void Update(AIController &, Entity &, float dt) const override; + void Exit(AIController &) const override; + +}; + +} + +#endif diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 1d424cc..837c412 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -1,4 +1,5 @@ #include "AIController.hpp" +#include "IdleState.hpp" #include "../model/geometry.hpp" #include "../rand/GaloisLFSR.hpp" @@ -13,22 +14,36 @@ namespace blank { +namespace { + +IdleState idle; + +} + AIController::AIController(GaloisLFSR &rand) : random(rand) -, chase_speed(2.0f) +, state(&idle) +, flee_target(nullptr) , flee_speed(-5.0f) -, stop_dist(10.0f) -, flee_dist(5.0f) +, seek_target(nullptr) +, seek_speed(-5.0f) +, wandering(false) , wander_pos(1.0f, 0.0f, 0.0f) , wander_dist(2.0f) , wander_radius(1.0f) , wander_disp(1.0f) , wander_speed(1.0f) { - + state->Enter(*this); } AIController::~AIController() { + state->Exit(*this); +} +void AIController::SetState(const AIState &s) { + state->Exit(*this); + state = &s; + state->Enter(*this); } void AIController::Update(Entity &e, float dt) { @@ -52,7 +67,23 @@ void AIController::Update(Entity &e, float dt) { } glm::vec3 AIController::ControlForce(const EntityState &state) const { - return (Heading(state) * wander_dist + wander_pos) * wander_speed; + glm::vec3 force(0.0f); + if (IsFleeing()) { + glm::vec3 diff(GetFleeTarget().GetState().Diff(state)); + if (dot(diff, diff) > std::numeric_limits::epsilon()) { + force += normalize(diff) * flee_speed; + } + } + if (IsSeeking()) { + glm::vec3 diff(state.Diff(GetSeekTarget().GetState())); + if (dot(diff, diff) > std::numeric_limits::epsilon()) { + force += normalize(diff) * seek_speed; + } + } + if (wandering) { + force += (Heading(state) * wander_dist + wander_pos) * wander_speed; + } + return force; } glm::vec3 AIController::Heading(const EntityState &state) noexcept { @@ -64,4 +95,57 @@ glm::vec3 AIController::Heading(const EntityState &state) noexcept { } } +void AIController::StartFleeing(const Entity &e, float speed) noexcept { + flee_target = &e; + flee_speed = speed; +} + +void AIController::StopFleeing() noexcept { + flee_target = nullptr; +} + +bool AIController::IsFleeing() const noexcept { + return flee_target; +} + +const Entity &AIController::GetFleeTarget() const noexcept { + return *flee_target; +} + +void AIController::StartSeeking(const Entity &e, float speed) noexcept { + seek_target = &e; + seek_speed = speed; +} + +void AIController::StopSeeking() noexcept { + seek_target = nullptr; +} + +bool AIController::IsSeeking() const noexcept { + return seek_target; +} + +const Entity &AIController::GetSeekTarget() const noexcept { + return *seek_target; +} + +void AIController::StartWandering() noexcept { + wandering = true; +} +void AIController::StopWandering() noexcept { + wandering = false; +} + + +void IdleState::Enter(AIController &ctrl) const { + ctrl.StartWandering(); +} + +void IdleState::Update(AIController &ctrl, Entity &e, float dt) const { +} + +void IdleState::Exit(AIController &ctrl) const { + ctrl.StopWandering(); +} + } diff --git a/src/world/world.cpp b/src/world/world.cpp index e77192b..ee5bf02 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -507,6 +507,10 @@ EntityDerivative World::CalculateStep( next.velocity += delta.velocity * dt; next.AdjustPosition(); + if (dot(next.velocity, next.velocity) > entity.MaxVelocity() * entity.MaxVelocity()) { + next.velocity = normalize(next.velocity) * entity.MaxVelocity(); + } + EntityDerivative out; out.position = next.velocity; out.velocity = CalculateForce(entity, next); // by mass = 1kg @@ -517,7 +521,12 @@ glm::vec3 World::CalculateForce( const Entity &entity, const EntityState &state ) { - return ControlForce(entity, state) + CollisionForce(entity, state) + Gravity(entity, state); + glm::vec3 force(ControlForce(entity, state) + CollisionForce(entity, state) + Gravity(entity, state)); + if (dot(force, force) > entity.MaxControlForce() * entity.MaxControlForce()) { + return normalize(force) * entity.MaxControlForce(); + } else { + return force; + } } glm::vec3 World::ControlForce(