]> git.localhorst.tv Git - blank.git/blob - src/ai/ai.cpp
brought some order to the whole controller thing
[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_speed(1.0f)
33 , wander_dist(2.0f)
34 , wander_radius(1.5f)
35 , wander_disp(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         if (wandering) {
52                 glm::vec3 displacement(
53                         random.SNorm() * wander_disp,
54                         random.SNorm() * wander_disp,
55                         random.SNorm() * wander_disp
56                 );
57                 if (!iszero(displacement)) {
58                         wander_pos = normalize(wander_pos + displacement * dt) * wander_radius;
59                 }
60         }
61
62         if (e.Moving()) {
63                 // orient head towards heading
64                 glm::vec3 heading(Heading(e.GetState()));
65                 float tgt_pitch = std::atan(heading.y / length(glm::vec2(heading.x, heading.z)));
66                 float tgt_yaw = std::atan2(-heading.x, -heading.z);
67                 e.SetHead(tgt_pitch, tgt_yaw);
68         }
69 }
70
71 glm::vec3 AIController::ControlForce(const Entity &entity, const EntityState &state) const {
72         glm::vec3 force(0.0f);
73         if (IsFleeing()) {
74                 glm::vec3 diff(GetFleeTarget().GetState().Diff(state));
75                 if (MaxOutForce(force, TargetVelocity(normalize(diff) * flee_speed, state, 0.5f), entity.MaxControlForce())) {
76                         return force;
77                 }
78         }
79         if (IsSeeking()) {
80                 glm::vec3 diff(state.Diff(GetSeekTarget().GetState()));
81                 if (MaxOutForce(force, TargetVelocity(normalize(diff) * seek_speed, state, 0.5f), entity.MaxControlForce())) {
82                         return force;
83                 }
84         }
85         if (wandering) {
86                 glm::vec3 wander_target(normalize(Heading(state) * wander_dist + wander_pos) * wander_speed);
87                 if (MaxOutForce(force, TargetVelocity(wander_target, state, 2.0f), entity.MaxControlForce())) {
88                         return force;
89                 }
90         }
91         return force;
92 }
93
94 glm::vec3 AIController::Heading(const EntityState &state) noexcept {
95         if (dot(state.velocity, state.velocity) > std::numeric_limits<float>::epsilon()) {
96                 return normalize(state.velocity);
97         } else {
98                 float cp = std::cos(state.pitch);
99                 return glm::vec3(std::cos(state.yaw) * cp, std::sin(state.yaw) * cp, std::sin(state.pitch));
100         }
101 }
102
103 void AIController::StartFleeing(const Entity &e, float speed) noexcept {
104         flee_target = &e;
105         flee_speed = speed;
106 }
107
108 void AIController::StopFleeing() noexcept {
109         flee_target = nullptr;
110 }
111
112 bool AIController::IsFleeing() const noexcept {
113         return flee_target;
114 }
115
116 const Entity &AIController::GetFleeTarget() const noexcept {
117         return *flee_target;
118 }
119
120 void AIController::StartSeeking(const Entity &e, float speed) noexcept {
121         seek_target = &e;
122         seek_speed = speed;
123 }
124
125 void AIController::StopSeeking() noexcept {
126         seek_target = nullptr;
127 }
128
129 bool AIController::IsSeeking() const noexcept {
130         return seek_target;
131 }
132
133 const Entity &AIController::GetSeekTarget() const noexcept {
134         return *seek_target;
135 }
136
137 void AIController::StartWandering(
138         float speed,
139         float distance,
140         float radius,
141         float displacement
142 ) noexcept {
143         wandering = true;
144         wander_speed = speed;
145         wander_dist = distance;
146         wander_radius = radius;
147         wander_disp = displacement;
148 }
149 void AIController::StopWandering() noexcept {
150         wandering = false;
151 }
152
153
154 void IdleState::Enter(AIController &ctrl) const {
155         ctrl.StartWandering(1.0f);
156 }
157
158 void IdleState::Update(AIController &ctrl, Entity &e, float dt) const {
159 }
160
161 void IdleState::Exit(AIController &ctrl) const {
162         ctrl.StopWandering();
163 }
164
165 }