Skip to content

Commit ffc73c4

Browse files
committed
Added pathfinding beginning code
1 parent f035f4d commit ffc73c4

7 files changed

Lines changed: 128 additions & 59 deletions

File tree

‎crates/core/wde/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ wde-physics = { path = "../../wrappers/wde-physics" }
1313
wde-terrain = { path = "../../terrain/wde-terrain" }
1414
wde-terrain-grid = { path = "../../terrain/wde-terrain-grid" }
1515
wde-terrain-editor = { path = "../../terrain/wde-terrain-editor" }
16+
wde-terrain-navigation = { path = "../../terrain/wde-terrain-navigation" }
1617
wde-scene = { path = "../wde-scene" }
1718
wde-pbr-outline = { path = "../../render/wde-pbr-outline" }
1819
wde-gizmos = { path = "../../render/wde-gizmos", optional = true }

‎crates/core/wde/src/lib.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//! - [`wde_terrain`](wde_terrain): A plugin for generating and rendering procedural terrain.
88
//! - [`wde_terrain_editor`](wde_terrain_editor): A plugin for editing terrain in-game.
99
//! - [`wde_terrain_grid`](wde_terrain_grid): A plugin for managing terrain grids and LOD.
10+
//! - [`wde_terrain_navigation`](wde_terrain_navigation): A plugin for pathfinding and navigation on terrain.
1011
//! - Render:
1112
//! - [`wde_pbr`](wde_pbr): A plugin for physically based rendering (PBR) materials and lighting.
1213
//! - [`wde_camera`](wde_camera): A plugin for managing cameras and viewports.
@@ -125,6 +126,7 @@ impl Plugin for CustomWdePlugins {
125126
wde_terrain::TerrainPlugin,
126127
wde_terrain_grid::TerrainGridPlugin,
127128
wde_terrain_editor::TerrainEditorPlugin,
129+
wde_terrain_navigation::TerrainNavigationPlugin,
128130
wde_pbr_outline::PbrOutlinePlugin
129131
));
130132

@@ -166,6 +168,7 @@ pub mod prelude {
166168
pub use wde_scene::prelude::*;
167169
pub use wde_terrain::prelude::*;
168170
pub use wde_terrain_grid::prelude::*;
171+
pub use wde_terrain_navigation::prelude::*;
169172

170173
// Optional feature modules
171174
#[cfg(feature = "editor")]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "wde-terrain-navigation"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
wde-logger = { path = "../../wrappers/wde-logger" }
8+
bevy = { workspace = true }
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use bevy::prelude::*;
2+
3+
mod navigation;
4+
mod navmap;
5+
6+
pub mod prelude {
7+
pub use super::TerrainNavigator;
8+
}
9+
10+
pub struct TerrainNavigationPlugin;
11+
impl Plugin for TerrainNavigationPlugin {
12+
fn build(&self, app: &mut App) {
13+
app.add_plugins(navigation::NavigationPlugin)
14+
.init_resource::<TerrainNavigator>()
15+
.add_systems(Update, handle_changes);
16+
}
17+
}
18+
19+
20+
21+
#[derive(Resource, Default)]
22+
pub struct TerrainNavigator {
23+
new_entities: Vec<(Entity, Vec3)>,
24+
removed_entities: Vec<Entity>,
25+
}
26+
impl TerrainNavigator {
27+
pub fn add(&mut self, entity: Entity, position: Vec3) {
28+
self.new_entities.push((entity, position));
29+
}
30+
31+
pub fn remove(&mut self, entity: Entity) {
32+
self.removed_entities.push(entity);
33+
}
34+
}
35+
36+
#[derive(Component)]
37+
pub(crate) struct TargetLocation(Vec3);
38+
39+
fn handle_changes(
40+
mut commands: Commands,
41+
mut navigator: ResMut<TerrainNavigator>,
42+
) {
43+
for (entity, position) in navigator.new_entities.drain(..) {
44+
commands.entity(entity).insert(TargetLocation(position));
45+
}
46+
47+
for entity in navigator.removed_entities.drain(..) {
48+
commands.entity(entity).remove::<TargetLocation>();
49+
}
50+
}
51+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use bevy::prelude::*;
2+
3+
use crate::TargetLocation;
4+
5+
pub struct NavigationPlugin;
6+
impl Plugin for NavigationPlugin {
7+
fn build(&self, app: &mut App) {
8+
app.add_systems(Update, move_entities_towards_target);
9+
}
10+
}
11+
12+
fn move_entities_towards_target(
13+
mut commands: Commands,
14+
mut query: Query<(Entity, &mut Transform, &TargetLocation)>,
15+
time: Res<Time>
16+
) {
17+
for (entity, mut transform, target_location) in &mut query {
18+
let direction = (target_location.0 - transform.translation).normalize_or_zero();
19+
let speed = 2.0; // units per second
20+
let delta_move = direction * speed * time.delta_secs();
21+
transform.translation += delta_move;
22+
transform.rotation = Quat::from_rotation_arc(Vec3::Z, direction) * Quat::from_rotation_y(-std::f32::consts::FRAC_PI_2);
23+
24+
// Check if the entity has reached the target location
25+
if transform.translation.distance(target_location.0) < 0.1 {
26+
commands.entity(entity).remove::<TargetLocation>();
27+
}
28+
}
29+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use bevy::prelude::*;
2+
3+
pub struct NavMapPlugin;
4+
impl Plugin for NavMapPlugin {
5+
fn build(&self, app: &mut App) {
6+
}
7+
}

‎src/src/test.rs‎

Lines changed: 29 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@ impl Plugin for TestPlugin {
66
fn build(&self, app: &mut App) {
77
app.add_systems(Startup, init_scene).add_systems(
88
Update,
9-
(
10-
add_human_collider,
11-
select_entity,
12-
set_entities_target,
13-
move_entities_towards_target
14-
)
9+
(add_human_collider, select_entity, set_entities_target),
1510
);
1611
}
1712
}
@@ -32,7 +27,7 @@ struct SelectionOutlineMaterial(Handle<OutlineMaterial>);
3227
#[derive(Resource)]
3328
struct SelectionAreaAssets {
3429
mesh: Handle<Mesh>,
35-
material: Handle<SelectionAreaMaterial>
30+
material: Handle<SelectionAreaMaterial>,
3631
}
3732

3833
/// Marker component for the drag-selection ground decal entity.
@@ -45,14 +40,14 @@ const SELECTION_AREA_Y_OFFSET: f32 = 0.01;
4540
fn init_scene(
4641
mut commands: Commands,
4742
mut gltf_spawn_queue: ResMut<GltfSpawnQueue>,
48-
asset_server: Res<AssetServer>
43+
asset_server: Res<AssetServer>,
4944
) {
5045
// Main camera
5146
commands.spawn((
5247
Name::new("Main Camera"),
5348
Transform::from_xyz(2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
5449
ActiveCamera,
55-
ThirdPersonController::default() // FreeCameraController::default()
50+
ThirdPersonController::default(), // FreeCameraController::default()
5651
));
5752

5853
// Spawn the lights
@@ -64,7 +59,7 @@ fn init_scene(
6459
color: WdeColor::from_srgba(0.8, 0.2, 0.2, 1.0),
6560
..Default::default()
6661
},
67-
ChildOf(entity)
62+
ChildOf(entity),
6863
));
6964
commands.spawn((
7065
Name::new("Green Light"),
@@ -73,7 +68,7 @@ fn init_scene(
7368
color: WdeColor::from_srgba(0.2, 0.8, 0.2, 1.0),
7469
..Default::default()
7570
},
76-
ChildOf(entity)
71+
ChildOf(entity),
7772
));
7873
commands.spawn((
7974
Name::new("Blue Light"),
@@ -82,7 +77,7 @@ fn init_scene(
8277
color: WdeColor::from_srgba(0.2, 0.2, 0.8, 1.0),
8378
..Default::default()
8479
},
85-
ChildOf(entity)
80+
ChildOf(entity),
8681
));
8782
// commands.spawn((
8883
// Name::new("Directional Light"),
@@ -99,7 +94,7 @@ fn init_scene(
9994
label: "selection-outline".to_string(),
10095
color: WdeColor::from_srgba(1.0, 0.85, 0.0, 1.0),
10196
..Default::default()
102-
}
97+
},
10398
)));
10499

105100
commands.insert_resource(SelectionAreaAssets {
@@ -108,7 +103,7 @@ fn init_scene(
108103
label: "selection-area".to_string(),
109104
color: WdeColor::from_srgba(0.8, 0.8, 0.4, 0.2),
110105
..Default::default()
111-
})
106+
}),
112107
});
113108

114109
let global_parent = commands
@@ -122,11 +117,11 @@ fn init_scene(
122117
Transform::from_scale(Vec3::splat(2.0)).with_translation(Vec3::new(
123118
i as f32 * 1.0,
124119
0.0,
125-
0.0
120+
0.0,
126121
)),
127122
PendingHumanCollider(gltf_asset.clone()),
128123
EntityMarker,
129-
ChildOf(global_parent)
124+
ChildOf(global_parent),
130125
))
131126
.id();
132127
GltfLoader::spawn(&mut gltf_spawn_queue, gltf_asset.clone(), parent);
@@ -138,7 +133,7 @@ fn init_scene(
138133
fn add_human_collider(
139134
mut commands: Commands,
140135
gltf_assets: Res<Assets<GltfAsset>>,
141-
query: Query<(Entity, &PendingHumanCollider)>
136+
query: Query<(Entity, &PendingHumanCollider)>,
142137
) {
143138
for (entity, pending) in &query {
144139
let Some(gltf_asset) = gltf_assets.get(&pending.0) else {
@@ -154,7 +149,7 @@ fn add_human_collider(
154149
Name::new("Human Collider"),
155150
Transform::from_translation(bbox_offset),
156151
Collider::from(BoxCollider::new(bbox_extent)),
157-
ChildOf(entity)
152+
ChildOf(entity),
158153
));
159154
}
160155
}
@@ -172,11 +167,13 @@ fn select_entity(
172167
outline_material: Res<SelectionOutlineMaterial>,
173168
selection_area_assets: Res<SelectionAreaAssets>,
174169
selected_entities: Query<Entity, With<EntitySelectedMarker>>,
175-
entities_query: Query<(Entity, &Transform), (With<EntityMarker>, Without<SelectionAreaQuadMarker>)>,
170+
entities_query: Query<
171+
(Entity, &Transform),
172+
(With<EntityMarker>, Without<SelectionAreaQuadMarker>),
173+
>,
176174
children_query: Query<&Children>,
177175
mesh_query: Query<(), With<Mesh3d>>,
178176
mut quad_transform_query: Query<&mut Transform, With<SelectionAreaQuadMarker>>,
179-
asset_server: Res<AssetServer>
180177
) {
181178
if mouse_input.just_pressed(MouseButton::Left) {
182179
let start_pos = cursor_pos.pos_or_last();
@@ -190,9 +187,10 @@ fn select_entity(
190187
Mesh3d(selection_area_assets.mesh.clone()),
191188
PbrMaterial3d(selection_area_assets.material.clone()),
192189
Transform::from_translation(
193-
start_pos + Vec3::new(0.0, SELECTION_AREA_Y_OFFSET, 0.0)
194-
).with_scale(Vec3::new(0.0, 1.0, 0.0)),
195-
PbrSsboTransformUuid::default()
190+
start_pos + Vec3::new(0.0, SELECTION_AREA_Y_OFFSET, 0.0),
191+
)
192+
.with_scale(Vec3::new(0.0, 1.0, 0.0)),
193+
PbrSsboTransformUuid::default(),
196194
))
197195
.id();
198196
*selection_area_quad = Some(entity);
@@ -205,9 +203,7 @@ fn select_entity(
205203

206204
// Deselect all previously selected entities and remove their contour outline
207205
for entity in &selected_entities {
208-
commands
209-
.entity(entity)
210-
.remove::<(EntitySelectedMarker, TargetLocation)>();
206+
commands.entity(entity).remove::<EntitySelectedMarker>();
211207
set_entity_outline(&mut commands, &children_query, &mesh_query, entity, None);
212208
}
213209

@@ -221,7 +217,7 @@ fn select_entity(
221217
&children_query,
222218
&mesh_query,
223219
entity,
224-
Some(&outline_material.0)
220+
Some(&outline_material.0),
225221
);
226222
}
227223
}
@@ -246,7 +242,7 @@ fn select_entity(
246242
transform.scale = Vec3::new(
247243
(max.x - min.x).max(f32::EPSILON),
248244
1.0,
249-
(max.z - min.z).max(f32::EPSILON)
245+
(max.z - min.z).max(f32::EPSILON),
250246
);
251247
}
252248
}
@@ -259,7 +255,7 @@ fn set_entity_outline(
259255
children_query: &Query<&Children>,
260256
mesh_query: &Query<(), With<Mesh3d>>,
261257
entity: Entity,
262-
outline_material: Option<&Handle<OutlineMaterial>>
258+
outline_material: Option<&Handle<OutlineMaterial>>,
263259
) {
264260
let Ok(children) = children_query.get(entity) else {
265261
return;
@@ -285,43 +281,17 @@ fn set_entity_outline(
285281
}
286282
}
287283

288-
#[derive(Component)]
289-
struct TargetLocation(Vec3);
290-
291284
fn set_entities_target(
292-
mut commands: Commands,
293285
selected_entities: Query<Entity, With<EntitySelectedMarker>>,
294286
mouse_input: Res<ButtonInput<MouseButton>>,
295-
cursor_pos: Res<TerrainCursorPos>
287+
cursor_pos: Res<TerrainCursorPos>,
288+
mut navigator: ResMut<TerrainNavigator>,
296289
) {
297-
if selected_entities.is_empty() {
298-
return;
299-
}
300-
if !mouse_input.just_pressed(MouseButton::Right) {
290+
if selected_entities.is_empty() || !mouse_input.just_pressed(MouseButton::Right) {
301291
return;
302292
}
303293
for entity in &selected_entities {
304294
let target_location = cursor_pos.pos_or_last();
305-
commands
306-
.entity(entity)
307-
.insert(TargetLocation(target_location));
308-
}
309-
}
310-
311-
fn move_entities_towards_target(
312-
mut commands: Commands,
313-
mut query: Query<(Entity, &mut Transform, &TargetLocation), With<EntitySelectedMarker>>,
314-
time: Res<Time>
315-
) {
316-
for (entity, mut transform, target_location) in &mut query {
317-
let direction = (target_location.0 - transform.translation).normalize_or_zero();
318-
let speed = 2.0; // units per second
319-
let delta_move = direction * speed * time.delta_secs();
320-
transform.translation += delta_move;
321-
322-
// Check if the entity has reached the target location
323-
if transform.translation.distance(target_location.0) < 0.1 {
324-
commands.entity(entity).remove::<TargetLocation>();
325-
}
295+
navigator.add(entity, target_location);
326296
}
327297
}

0 commit comments

Comments
 (0)