Skip to main content

steel_core/entity/ai/goal/
squid_random_movement_goal.rs

1use std::f32::consts::TAU;
2
3use glam::DVec3;
4use steel_math::trig;
5use steel_utils::Downcast;
6
7use crate::entity::{
8    Entity, LivingEntity, PathfinderMob, SharedEntity,
9    ai::goal::{
10        reduced_tick_delay,
11        selector::{Goal, GoalControls},
12    },
13    entities::SquidEntity,
14};
15
16/// Ticks without action after which the squid stops moving.
17const NO_ACTION_TIME_LIMIT: i32 = 100;
18/// Average ticks between picking a new movement vector.
19const MOVEMENT_CHANGE_INTERVAL: i32 = 50;
20/// Horizontal speed of a random movement vector.
21const MOVEMENT_SPEED: f32 = 0.2;
22/// Downward bias of the vertical component of a random movement vector.
23const MOVEMENT_VERTICAL_BASE: f32 = -0.1;
24
25pub struct SquidRandomMovementGoal;
26
27impl SquidRandomMovementGoal {
28    #[must_use]
29    pub(crate) const fn new() -> Self {
30        Self
31    }
32}
33
34impl Goal for SquidRandomMovementGoal {
35    fn controls(&self) -> GoalControls {
36        GoalControls::EMPTY
37    }
38
39    fn can_use(&mut self, _mob: &dyn PathfinderMob) -> bool {
40        true
41    }
42
43    fn tick(&mut self, mob: &dyn PathfinderMob, _entity: &SharedEntity) {
44        let Some(squid) = mob.downcast_ref::<SquidEntity>() else {
45            tracing::warn!("SquidRandomMovementGoal assigned to non-squid entity");
46            return;
47        };
48
49        if squid.no_action_time() > NO_ACTION_TIME_LIMIT {
50            squid.set_movement_vector(DVec3::ZERO);
51            return;
52        }
53
54        if rand::random_range(0..reduced_tick_delay(MOVEMENT_CHANGE_INTERVAL)) != 0
55            && squid.is_in_water()
56            && squid.has_movement_vector()
57        {
58            return;
59        }
60
61        let angle = rand::random::<f32>() * TAU;
62        let movement = DVec3::new(
63            f64::from(trig::cos(f64::from(angle)) * MOVEMENT_SPEED),
64            f64::from(MOVEMENT_VERTICAL_BASE + rand::random::<f32>() * MOVEMENT_SPEED),
65            f64::from(trig::sin(f64::from(angle)) * MOVEMENT_SPEED),
66        );
67
68        squid.set_movement_vector(movement);
69    }
70}