]> git.localhorst.tv Git - blank.git/blob - src/ai/ai.cpp
837c412f7280467336dd29afbdf22e8f889133d6
[blank.git] / src / ai / ai.cpp
1 #include "AIController.hpp"
2 #include "IdleState.hpp"
3
4 #include "../model/geometry.hpp"
5 #include "../rand/GaloisLFSR.hpp"
6 #include "../world/Entity.hpp"
7 #include "../world/World.hpp"
8 #include "../world/WorldCollision.hpp"
9
10 #include <cmath>
11 #include <limits>
12 #include <glm/glm.hpp>
13
14
15 namespace blank {
16
17 namespace {
18
19 IdleState idle;
20
21 }
22
23 AIController::AIController(GaloisLFSR &rand)
24 : random(rand)
25 , state(&idle)
26 , flee_target(nullptr)
27 , flee_speed(-5.0f)
28 , seek_target(nullptr)
29 , seek_speed(-5.0f)
30 , wandering(false)
31 , wander_pos(1.0f, 0.0f, 0.0f)
32 , wander_dist(2.0f)
33 , wander_radius(1.0f)
34 , wander_disp(1.0f)
35 , wander_speed(1.0f) {
36         state->Enter(*this);
37 }
38
39 AIController::~AIController() {
40         state->Exit(*this);
41 }
42
43 void AIController::SetState(const AIState &s) {
44         state->Exit(*this);
45         state = &s;
46         state->Enter(*this);
47 }
48
49 void AIController::Update(Entity &e, float dt) {
50         // movement: for now, wander only
51         glm::vec3 displacement(
52                 random.SNorm() * wander_disp,
53                 random.SNorm() * wander_disp,
54                 random.SNorm() * wander_disp
55         );
56         if (dot(displacement, displacement) > std::numeric_limits<float>::epsilon()) {
57                 wander_pos = normalize(wander_pos + displacement * dt) * wander_radius;
58         }
59
60         if (e.Moving()) {
61                 // orient head towards heading
62                 glm::vec3 heading(Heading(e.GetState()));
63                 float tgt_pitch = std::atan(heading.y / length(glm::vec2(heading.x, heading.z)));
64                 float tgt_yaw = std::atan2(-heading.x, -heading.z);
65                 e.SetHead(tgt_pitch, tgt_yaw);
66         }
67 }
68
69 glm::vec3 AIController::ControlForce(const EntityState &state) const {
70         glm::vec3 force(0.0f);
71         if (IsFleeing()) {
72                 glm::vec3 diff(GetFleeTarget().GetState().Diff(state));
73                 if (dot(diff, diff) > std::numeric_limits<float>::epsilon()) {
74                         force += normalize(diff) * flee_speed;
75                 }
76         }
77         if (IsSeeking()) {
78                 glm::vec3 diff(state.Diff(GetSeekTarget().GetState()));
79                 if (dot(diff, diff) > std::numeric_limits<float>::epsilon()) {
80                         force += normalize(diff) * seek_speed;
81                 }
82         }
83         if (wandering) {
84                 force += (Heading(state) * wander_dist + wander_pos) * wander_speed;
85         }
86         return force;
87 }
88
89 glm::vec3 AIController::Heading(const EntityState &state) noexcept {
90         if (dot(state.velocity, state.velocity) > std::numeric_limits<float>::epsilon()) {
91                 return normalize(state.velocity);
92         } else {
93                 float cp = std::cos(state.pitch);
94                 return glm::vec3(std::cos(state.yaw) * cp, std::sin(state.yaw) * cp, std::sin(state.pitch));
95         }
96 }
97
98 void AIController::StartFleeing(const Entity &e, float speed) noexcept {
99         flee_target = &e;
100         flee_speed = speed;
101 }
102
103 void AIController::StopFleeing() noexcept {
104         flee_target = nullptr;
105 }
106
107 bool AIController::IsFleeing() const noexcept {
108         return flee_target;
109 }
110
111 const Entity &AIController::GetFleeTarget() const noexcept {
112         return *flee_target;
113 }
114
115 void AIController::StartSeeking(const Entity &e, float speed) noexcept {
116         seek_target = &e;
117         seek_speed = speed;
118 }
119
120 void AIController::StopSeeking() noexcept {
121         seek_target = nullptr;
122 }
123
124 bool AIController::IsSeeking() const noexcept {
125         return seek_target;
126 }
127
128 const Entity &AIController::GetSeekTarget() const noexcept {
129         return *seek_target;
130 }
131
132 void AIController::StartWandering() noexcept {
133         wandering = true;
134 }
135 void AIController::StopWandering() noexcept {
136         wandering = false;
137 }
138
139
140 void IdleState::Enter(AIController &ctrl) const {
141         ctrl.StartWandering();
142 }
143
144 void IdleState::Update(AIController &ctrl, Entity &e, float dt) const {
145 }
146
147 void IdleState::Exit(AIController &ctrl) const {
148         ctrl.StopWandering();
149 }
150
151 }