X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fai%2Fai.cpp;h=343bacf774aebe56d0828e3ab74a079149779f7a;hb=f0a20986c573c4df1eb1212333489252c4b30efa;hp=f24d0694e0838222d457471ba1f254a76417471c;hpb=0ab149c70b3f984b2cc0c7a122b4aa347bc5fd79;p=blank.git diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index f24d069..343bacf 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -1,5 +1,6 @@ #include "AIController.hpp" #include "IdleState.hpp" +#include "RoamState.hpp" #include "../model/geometry.hpp" #include "../rand/GaloisLFSR.hpp" @@ -17,12 +18,16 @@ namespace blank { namespace { IdleState idle; +RoamState roam; } AIController::AIController(GaloisLFSR &rand) : random(rand) , state(&idle) +, decision_timer(1.0f) +, halted(false) +, halt_speed(1.0f) , flee_target(nullptr) , flee_speed(5.0f) , seek_target(nullptr) @@ -47,7 +52,9 @@ void AIController::SetState(const AIState &s) { } void AIController::Update(Entity &e, float dt) { - // movement: for now, wander only + decision_timer.Update(dt); + state->Update(*this, e, dt); + if (wandering) { glm::vec3 displacement( random.SNorm() * wander_disp, @@ -69,6 +76,9 @@ void AIController::Update(Entity &e, float dt) { } glm::vec3 AIController::ControlForce(const Entity &entity, const EntityState &state) const { + if (IsHalted()) { + return Halt(state, halt_speed); + } glm::vec3 force(0.0f); if (IsFleeing()) { glm::vec3 diff(GetFleeTarget().GetState().Diff(state)); @@ -82,7 +92,7 @@ glm::vec3 AIController::ControlForce(const Entity &entity, const EntityState &st return force; } } - if (wandering) { + if (IsWandering()) { glm::vec3 wander_target(normalize(Heading(state) * wander_dist + wander_pos) * wander_speed); if (MaxOutForce(force, TargetVelocity(wander_target, state, 2.0f), entity.MaxControlForce())) { return force; @@ -100,6 +110,35 @@ glm::vec3 AIController::Heading(const EntityState &state) noexcept { } } +void AIController::CueDecision( + float minimum, + float variance +) noexcept { + decision_timer = FineTimer(minimum + variance * random.SNorm()); + decision_timer.Start(); +} + +bool AIController::DecisionDue() const noexcept { + return decision_timer.HitOnce(); +} + +unsigned int AIController::Decide(unsigned int num_choices) noexcept { + return random.Next() % num_choices; +} + +void AIController::EnterHalt(float speed) noexcept { + halted = true; + halt_speed = speed; +} + +void AIController::ExitHalt() noexcept { + halted = false; +} + +bool AIController::IsHalted() const noexcept { + return halted; +} + void AIController::StartFleeing(const Entity &e, float speed) noexcept { flee_target = &e; flee_speed = speed; @@ -146,19 +185,62 @@ void AIController::StartWandering( wander_radius = radius; wander_disp = displacement; } + void AIController::StopWandering() noexcept { wandering = false; } +bool AIController::IsWandering() const noexcept { + return wandering; +} + void IdleState::Enter(AIController &ctrl) const { - ctrl.StartWandering(1.0f); + ctrl.EnterHalt(2.0f); + ctrl.StartWandering(0.001f, 1.1f); + ctrl.CueDecision(10.0f, 5.0f); } void IdleState::Update(AIController &ctrl, Entity &e, float dt) const { + // TODO: check for players + if (!ctrl.DecisionDue()) return; + + unsigned int d = ctrl.Decide(10); + if (d == 0) { + // .1 chance to start going + ctrl.SetState(roam); + } else if (d < 3) { + // .2 chance of looking around + ctrl.ExitHalt(); + } else { + ctrl.EnterHalt(2.0f); + } + ctrl.CueDecision(10.0f, 5.0f); } void IdleState::Exit(AIController &ctrl) const { + ctrl.ExitHalt(); + ctrl.StopWandering(); +} + +void RoamState::Enter(AIController &ctrl) const { + ctrl.StartWandering(1.0f); + ctrl.CueDecision(10.0f, 5.0f); +} + +void RoamState::Update(AIController &ctrl, Entity &e, float dt) const { + // TODO: check for players + if (!ctrl.DecisionDue()) return; + + unsigned int d = ctrl.Decide(10); + if (d == 0) { + // .1 chance of idling + ctrl.SetState(idle); + } + ctrl.CueDecision(10.0f, 5.0f); +} + +void RoamState::Exit(AIController &ctrl) const { ctrl.StopWandering(); }