-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathbasic.rs
More file actions
204 lines (173 loc) · 6.03 KB
/
basic.rs
File metadata and controls
204 lines (173 loc) · 6.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// This example uses a simple point-and-click movement system to move units around the map.
use bevy::{color::palettes::tailwind::*, prelude::*, window::PrimaryWindow};
use bevy_pathfinding::{
components::*, debug::resources::DbgOptions, events::InitializeFlowFieldEv, grid::Grid, utils,
BevyPathfindingPlugin,
};
const CELL_SIZE: f32 = 10.0; // size of each cell in the grid
const BUCKETS: f32 = 5.0; // size of each bucket (spatial partitioning) in the grid
const MAP_GRID: IVec2 = IVec2::new(25, 25); // number of cell rows and columns
// size of the map is determined by the grid size and cell size
const MAP_WIDTH: f32 = MAP_GRID.x as f32 * CELL_SIZE;
const MAP_DEPTH: f32 = MAP_GRID.y as f32 * CELL_SIZE;
const UNIT_COUNT: usize = 25;
fn main() {
let mut app = App::new();
app.insert_resource(Grid::new(BUCKETS, MAP_GRID, CELL_SIZE)) // ADD THIS!
.add_plugins((
DefaultPlugins,
BevyPathfindingPlugin, // ADD THIS!
))
.add_systems(Startup, (camera, setup, spawn_units))
.add_systems(PostStartup, spawn_obstacles)
.add_systems(Update, (set_unit_destination, move_unit))
.run();
}
#[derive(Component)]
struct Speed(f32);
fn camera(mut cmds: Commands) {
cmds.spawn((
Camera3d::default(),
GameCamera, // ADD THIS!
Transform::from_translation(Vec3::new(0.0, 150.0, 250.0)).looking_at(Vec3::ZERO, Vec3::Y),
));
}
// spawn ground and light
fn setup(
mut cmds: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let ground = (
Mesh3d(meshes.add(Plane3d::default().mesh().size(MAP_WIDTH, MAP_DEPTH))),
MeshMaterial3d(materials.add(StandardMaterial::from_color(GREEN_600))),
MapBase, // ADD THIS!
Name::new("Map Base"),
);
let translation = Vec3::new(0.0, 0.0, 0.0);
let rotation = Quat::from_euler(EulerRot::XYZ, -0.7, 0.2, 0.0);
let light = (
DirectionalLight {
illuminance: 5000.0,
shadows_enabled: true,
shadow_depth_bias: 1.5,
shadow_normal_bias: 1.0,
..default()
},
Transform {
translation,
rotation,
..default()
},
Name::new("Sun Light"),
);
cmds.spawn(ground);
cmds.spawn(light);
}
fn spawn_units(
mut cmds: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let mut unit = |pos: Vec3| {
(
Mesh3d(meshes.add(Cuboid::new(5.0, 5.0, 5.0))),
MeshMaterial3d(materials.add(StandardMaterial::from_color(BLUE_500))),
Transform::from_translation(pos),
Speed(25.0),
Boid::default(), // ADD THIS! - Can also be set with custom parameters `Boid::new(50.0, 0.0, 0.0, 5.0)`
Name::new("Unit"),
)
};
let side = (UNIT_COUNT as f32).sqrt().ceil() as u32;
// spacing between units
let spacing = 10.0;
// offset to center the whole formation on (0,0)
let half = (side as f32 - 1.0) * spacing * 0.5;
for idx in 0..UNIT_COUNT {
let col = (idx as u32) % side;
let row = (idx as u32) / side;
let x = col as f32 * spacing - half;
let z = row as f32 * spacing - half;
cmds.spawn(unit(Vec3::new(x, 2.5, z)));
}
}
fn spawn_obstacles(
mut cmds: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let size = Vec3::new(35.0, 10.0, 35.0);
let mut obstacle = |pos: Vec3| {
(
Mesh3d(meshes.add(Cuboid::from_size(size))),
MeshMaterial3d(materials.add(StandardMaterial::from_color(GRAY_400))),
Transform::from_translation(pos),
Obstacle(size.xz()), // ADD THIS!
Name::new("Obstacle"),
)
};
cmds.spawn(obstacle(Vec3::new(-80.0, 5.0, 0.0)));
cmds.spawn(obstacle(Vec3::new(80.0, 5.0, 0.0)));
cmds.spawn(obstacle(Vec3::new(0.0, 5.0, 80.0)));
cmds.spawn(obstacle(Vec3::new(0.0, 5.0, -80.0)));
}
// uses the mouse position to set the destination of all units
fn set_unit_destination(
mut cmds: Commands,
input: Res<ButtonInput<MouseButton>>,
mut q_units: Query<Entity, With<Boid>>,
q_map: Query<&GlobalTransform, With<MapBase>>,
q_cam: Query<(&Camera, &GlobalTransform), With<GameCamera>>,
q_window: Query<&Window, With<PrimaryWindow>>,
dbg_options: Option<ResMut<DbgOptions>>,
) {
// if hovering over the debug UI, then do not set the destination
if let Some(dbg) = dbg_options {
if dbg.hover {
return;
}
};
if !input.just_pressed(MouseButton::Left) {
return;
}
let Ok(map_tf) = q_map.single() else {
return;
};
let Ok((cam, cam_transform)) = q_cam.single() else {
return;
};
let Ok(window) = q_window.single() else {
return;
};
let Some(cursor_pos) = window.cursor_position() else {
return;
};
// ADD THIS!
{
// collect all the units you wish to assign to a flowfield
let mut units = Vec::new();
for unit_entity in q_units.iter_mut() {
units.push(unit_entity);
}
// get the destination position in world space using the 'get_world_pos' function
let destination_pos = utils::get_world_pos(map_tf, cam_transform, cam, cursor_pos);
// create a flowfield and assign the units and destination position it it
cmds.trigger(InitializeFlowFieldEv {
entities: units,
destination_pos,
});
}
}
// ADD THIS!
// moves all units (boids) that have a destination, towards it
// if you are using a physics engine, you would want to swap out the 'Transform' here
fn move_unit(
mut q_units: Query<(&mut Transform, &mut Boid, &Speed), With<Destination>>,
time: Res<Time>,
) {
let delta_secs = time.delta_secs();
for (mut tf, boid, speed) in q_units.iter_mut() {
tf.translation += boid.steering.normalize_or_zero() * delta_secs * speed.0;
}
}