1use bevy::prelude::*;
2use bitflags::bitflags;
3
4use crate::{
5 behaviors::{
6 alignment,
7 approach::{self, debug_approach},
8 avoid, cohesion,
9 evasion::{self as evasion_behavior, debug_evasion},
10 flee,
11 path_following::{self, debug_path_following},
12 pursuit::{self, debug_pursuit},
13 seek,
14 separation::{self, debug_separation},
15 wander,
16 },
17 control::{
18 combine_steering_targets, debug_combined_steering, debug_forward_dir, temporal_smoothing,
19 update_forward_dir, update_previous_steering_outputs,
20 },
21 movement::{debug_movement, move_agent},
22 neighbors::{debug_neighborhoods, update_neighborhoods},
23 obstacles::{
24 debug_obstacles, setup_obstacle_tracking, update_nearby_obstacles, update_obstacle_tracking,
25 },
26 speed::{debug_speed, reset_speed_override, speed_control},
27};
28
29#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
30pub struct BehaviorSystemSet;
31
32#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
33pub struct SteeringSystemSet;
34
35pub struct SteeringPlugin;
36
37impl Plugin for SteeringPlugin {
38 fn build(&self, app: &mut App) {
39 let behavior_systems = (
40 alignment::run,
41 approach::run,
42 avoid::run,
43 cohesion::run,
44 evasion_behavior::run,
45 flee::run,
46 path_following::run,
47 pursuit::run,
48 seek::run,
49 separation::run,
50 wander::run,
51 )
52 .in_set(BehaviorSystemSet);
53 let update_systems = (
54 update_forward_dir,
55 setup_obstacle_tracking,
56 update_obstacle_tracking,
57 update_nearby_obstacles,
58 update_neighborhoods,
59 behavior_systems,
60 speed_control,
61 temporal_smoothing,
62 update_previous_steering_outputs,
63 combine_steering_targets,
64 move_agent,
65 )
66 .chain()
67 .in_set(SteeringSystemSet);
68 app.add_systems(FixedPreUpdate, reset_speed_override);
69 app.add_systems(FixedUpdate, update_systems);
70 }
71}
72
73#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
74pub struct DebugSteeringSystem;
75
76bitflags! {
77 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
78 pub struct DebugSteeringFlags: u32 {
79 const APPROACH = 1 << 0;
80 const FORWARD_DIR = 1 << 1;
81 const OBSTACLES = 1 << 2;
82 const NEIGHBORHOODS = 1 << 3;
83 const SEPARATION = 1 << 4;
84 const EVASION = 1 << 5;
85 const PURSUIT = 1 << 6;
86 const PATH_FOLLOWING = 1 << 7;
87 const SPEED = 1 << 8;
88 const COMBINED_STEERING = 1 << 9;
89 const MOVEMENT = 1 << 10;
90 }
91}
92
93#[derive(Resource, Debug, Clone)]
94pub struct DebugSteeringConfig {
95 pub flags: DebugSteeringFlags,
96}
97
98impl Default for DebugSteeringConfig {
99 fn default() -> Self {
100 Self {
101 flags: DebugSteeringFlags::all(),
102 }
103 }
104}
105
106fn flag_enabled(flag: DebugSteeringFlags) -> impl Fn(Res<DebugSteeringConfig>) -> bool {
107 move |config: Res<DebugSteeringConfig>| config.flags.contains(flag)
108}
109
110pub struct DebugSteeringPlugin;
111
112impl Plugin for DebugSteeringPlugin {
113 fn build(&self, app: &mut App) {
114 app.init_resource::<DebugSteeringConfig>();
115
116 app.add_systems(
117 FixedUpdate,
118 (
119 debug_approach.run_if(flag_enabled(DebugSteeringFlags::APPROACH)),
120 debug_forward_dir.run_if(flag_enabled(DebugSteeringFlags::FORWARD_DIR)),
121 debug_obstacles.run_if(flag_enabled(DebugSteeringFlags::OBSTACLES)),
122 debug_neighborhoods.run_if(flag_enabled(DebugSteeringFlags::NEIGHBORHOODS)),
123 debug_separation.run_if(flag_enabled(DebugSteeringFlags::SEPARATION)),
124 debug_evasion.run_if(flag_enabled(DebugSteeringFlags::EVASION)),
125 debug_pursuit.run_if(flag_enabled(DebugSteeringFlags::PURSUIT)),
126 debug_path_following.run_if(flag_enabled(DebugSteeringFlags::PATH_FOLLOWING)),
127 debug_speed.run_if(flag_enabled(DebugSteeringFlags::SPEED)),
128 debug_combined_steering.run_if(flag_enabled(DebugSteeringFlags::COMBINED_STEERING)),
129 debug_movement.run_if(flag_enabled(DebugSteeringFlags::MOVEMENT)),
130 )
131 .in_set(DebugSteeringSystem),
132 );
133 }
134}