- if (!line_of_sight) {
- Controlled().Velocity(glm::vec3(0.0f));
- } else if (dist > stop_dist) {
- Controlled().Velocity(norm_diff * chase_speed);
- } else if (dist < flee_dist) {
- Controlled().Velocity(norm_diff * flee_speed);
+bool AIController::MayThink() const noexcept {
+ return think_timer.Hit();
+}
+
+void AIController::SetThinkInterval(float i) noexcept {
+ think_timer = FineTimer(i);
+ think_timer.Start();
+}
+
+// decide
+
+void AIController::CueDecision(
+ float minimum,
+ float variance
+) noexcept {
+ decision_timer = FineTimer(minimum + variance * world.Random().SNorm());
+ decision_timer.Start();
+}
+
+bool AIController::DecisionDue() const noexcept {
+ return decision_timer.HitOnce();
+}
+
+unsigned int AIController::Decide(unsigned int num_choices) noexcept {
+ return world.Random().Next<unsigned int>() % num_choices;
+}
+
+
+// chase
+
+void ChaseState::Enter(AIController &ctrl, Entity &e) const {
+ e.GetSteering()
+ .SetAcceleration(1.0f)
+ .SetSpeed(4.0f)
+ .Enable(Steering::PURSUE_TARGET)
+ ;
+}
+
+void ChaseState::Update(AIController &ctrl, Entity &e, float dt) const {
+ Steering &steering = e.GetSteering();
+ // check if target still alive and in sight
+ if (
+ !steering.HasTargetEntity() || // lost
+ steering.GetTargetEntity().Dead() || // dead
+ !ctrl.LineOfSight(e, steering.GetTargetEntity()) // escaped
+ ) {
+ steering.ClearTargetEntity();
+ ctrl.SetState(idle, e);
+ return;
+ }
+ // halt if we're close enough, flee if we're too close
+ float dist_sq = length2(e.AbsoluteDifference(steering.GetTargetEntity()));
+ if (dist_sq < 8.0f) {
+ ctrl.SetState(flee, e);
+ } else if (dist_sq < 25.0f) {
+ steering.Enable(Steering::HALT).Disable(Steering::PURSUE_TARGET);