X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fai%2Fai.cpp;h=837c412f7280467336dd29afbdf22e8f889133d6;hb=d122d3e445d64f7d710c1cfaf285ff01bbe955b9;hp=b3e1a0ceae5fb852c2f8fd653bfa2675cd193022;hpb=c52405fad9c070e1370f852234c6eb723b52916c;p=blank.git diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index b3e1a0c..837c412 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -1,101 +1,151 @@ -#include "Chaser.hpp" -#include "Controller.hpp" -#include "RandomWalk.hpp" +#include "AIController.hpp" +#include "IdleState.hpp" +#include "../model/geometry.hpp" +#include "../rand/GaloisLFSR.hpp" #include "../world/Entity.hpp" +#include "../world/World.hpp" +#include "../world/WorldCollision.hpp" +#include +#include #include namespace blank { -Chaser::Chaser(Entity &ctrl, Entity &tgt) noexcept -: Controller(ctrl) -, tgt(tgt) -, speed(0.002f) -, stop_dist(5 * 5) -, flee_dist(3 * 3) { +namespace { + +IdleState idle; } -Chaser::~Chaser() { +AIController::AIController(GaloisLFSR &rand) +: random(rand) +, state(&idle) +, flee_target(nullptr) +, flee_speed(-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 Chaser::Update(int dt) { - glm::vec3 diff(Target().AbsoluteDifference(Controlled())); - float dist = dot (diff, diff); - // TODO: line of sight test - if (dist > stop_dist) { - Controlled().Velocity(normalize(diff) * speed); - } else if (dist < flee_dist) { - Controlled().Velocity(normalize(diff) * -speed); - } else { - Controlled().Velocity(glm::vec3(0.0f)); +void AIController::SetState(const AIState &s) { + state->Exit(*this); + state = &s; + state->Enter(*this); +} + +void AIController::Update(Entity &e, float dt) { + // movement: for now, wander only + glm::vec3 displacement( + random.SNorm() * wander_disp, + random.SNorm() * wander_disp, + random.SNorm() * wander_disp + ); + if (dot(displacement, displacement) > std::numeric_limits::epsilon()) { + wander_pos = normalize(wander_pos + displacement * dt) * wander_radius; + } + + if (e.Moving()) { + // orient head towards heading + glm::vec3 heading(Heading(e.GetState())); + float tgt_pitch = std::atan(heading.y / length(glm::vec2(heading.x, heading.z))); + float tgt_yaw = std::atan2(-heading.x, -heading.z); + e.SetHead(tgt_pitch, tgt_yaw); } } +glm::vec3 AIController::ControlForce(const EntityState &state) const { + 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; +} -Controller::Controller(Entity &e) noexcept -: entity(e) { +glm::vec3 AIController::Heading(const EntityState &state) noexcept { + if (dot(state.velocity, state.velocity) > std::numeric_limits::epsilon()) { + return normalize(state.velocity); + } else { + float cp = std::cos(state.pitch); + return glm::vec3(std::cos(state.yaw) * cp, std::sin(state.yaw) * cp, std::sin(state.pitch)); + } +} +void AIController::StartFleeing(const Entity &e, float speed) noexcept { + flee_target = &e; + flee_speed = speed; } -Controller::~Controller() { +void AIController::StopFleeing() noexcept { + flee_target = nullptr; +} +bool AIController::IsFleeing() const noexcept { + return flee_target; } +const Entity &AIController::GetFleeTarget() const noexcept { + return *flee_target; +} -RandomWalk::RandomWalk(Entity &e) noexcept -: Controller(e) -, time_left(0) { +void AIController::StartSeeking(const Entity &e, float speed) noexcept { + seek_target = &e; + seek_speed = speed; +} +void AIController::StopSeeking() noexcept { + seek_target = nullptr; } -RandomWalk::~RandomWalk() { +bool AIController::IsSeeking() const noexcept { + return seek_target; +} +const Entity &AIController::GetSeekTarget() const noexcept { + return *seek_target; } -void RandomWalk::Update(int dt) { - time_left -= dt; - if (time_left > 0) return; - time_left += 2500 + (rand() % 5000); +void AIController::StartWandering() noexcept { + wandering = true; +} +void AIController::StopWandering() noexcept { + wandering = false; +} - constexpr float move_vel = 0.0005f; - glm::vec3 new_vel = Controlled().Velocity(); +void IdleState::Enter(AIController &ctrl) const { + ctrl.StartWandering(); +} - switch (rand() % 9) { - case 0: - new_vel.x = -move_vel; - break; - case 1: - new_vel.x = 0.0f; - break; - case 2: - new_vel.x = move_vel; - break; - case 3: - new_vel.y = -move_vel; - break; - case 4: - new_vel.y = 0.0f; - break; - case 5: - new_vel.y = move_vel; - break; - case 6: - new_vel.z = -move_vel; - break; - case 7: - new_vel.z = 0.0f; - break; - case 8: - new_vel.z = move_vel; - break; - } +void IdleState::Update(AIController &ctrl, Entity &e, float dt) const { +} - Controlled().Velocity(new_vel); +void IdleState::Exit(AIController &ctrl) const { + ctrl.StopWandering(); } }