diff --git a/Cargo.toml b/Cargo.toml index ff8eea3..962af30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ categories = ["game-development"] [dependencies] itertools = "0.13" +tracing = { version = "0.1", optional = true } [dependencies.polyanya] version = "0.7.1" @@ -47,8 +48,9 @@ features = [ default-features = false [features] -default = [] +default = ["debug-with-gizmos"] linuxci = ["bevy/x11"] +debug-with-gizmos = ["bevy/bevy_gizmos"] [profile.dev.package."*"] opt-level = 3 diff --git a/examples/demo.rs b/examples/demo.rs index eb01ad4..6c98ce3 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,12 +1,11 @@ use std::f32::consts::{FRAC_PI_2, PI}; use bevy::{ - color::palettes, ecs::entity::EntityHashSet, math::vec2, pbr::NotShadowCaster, prelude::*, - render::view::RenderLayers, + color::palettes, ecs::entity::EntityHashSet, math::vec2, prelude::*, render::view::RenderLayers, }; use polyanya::Triangulation; use rand::Rng; -use vleue_navigator::prelude::*; +use vleue_navigator::{prelude::*, NavMeshDebug}; #[path = "helpers/agent3d.rs"] mod agent3d; @@ -71,6 +70,7 @@ fn main() { ) .add_systems(FixedUpdate, random_obstacle) .insert_resource(Time::::from_seconds(0.25)) + .insert_resource(NavMeshDebug(palettes::tailwind::RED_800.into())) .run(); } @@ -283,8 +283,7 @@ fn new_obstacle( }; commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Rectangle(larger_primitive), Lifetime(Timer::from_seconds( rng.gen_range(20.0..40.0), @@ -309,8 +308,7 @@ fn new_obstacle( }; commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Circle(larger_primitive), Lifetime(Timer::from_seconds( rng.gen_range(20.0..40.0), @@ -335,8 +333,7 @@ fn new_obstacle( }; commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Ellipse(larger_primitive), Lifetime(Timer::from_seconds( rng.gen_range(20.0..40.0), @@ -358,8 +355,7 @@ fn new_obstacle( Capsule2d::new(primitive.radius + radius, primitive.half_length * 2.0); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Capsule(larger_primitive), Lifetime(Timer::from_seconds( rng.gen_range(20.0..40.0), @@ -381,8 +377,7 @@ fn new_obstacle( RegularPolygon::new(primitive.circumradius() + radius, primitive.sides); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::RegularPolygon(larger_primitive), Lifetime(Timer::from_seconds( rng.gen_range(20.0..40.0), @@ -406,8 +401,7 @@ fn new_obstacle( ); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Rhombus(larger_primitive), Lifetime(Timer::from_seconds( rng.gen_range(20.0..40.0), @@ -439,7 +433,7 @@ fn display_mesh( return; } - let Some(navmesh) = navmeshes.get(navmesh_handle) else { + if navmeshes.get(navmesh_handle).is_none() { return; }; if let Some(entity) = *current_mesh_entity { @@ -463,22 +457,6 @@ fn display_mesh( material: MATERIAL_NAVMESH, ..default() }) - .with_children(|main_mesh| { - main_mesh.spawn(( - PbrBundle { - mesh: meshes.add(navmesh.to_wireframe_mesh()).into(), - material: MATERIAL_NAVMESH, - transform: Transform::from_translation(Vec3::new( - -(MESH_WIDTH as f32) / 2.0, - 0.1, - -(MESH_HEIGHT as f32) / 2.0, - )), - ..default() - }, - NotShadowCaster, - RenderLayers::none().with(1), - )); - }) .id(), ); } diff --git a/src/lib.rs b/src/lib.rs index c862dba..7d4c180 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,10 +43,25 @@ pub mod prelude { #[derive(Debug, Clone, Copy)] pub struct VleueNavigatorPlugin; +/// Controls wether to display the NavMesh with gizmos. +/// When this resource is present, the NavMesh will be visible. +#[cfg(feature = "debug-with-gizmos")] +#[derive(Resource, Clone, Copy, Debug)] +pub struct NavMeshDebug( + /// Color to display the NavMesh with + pub Color, +); + impl Plugin for VleueNavigatorPlugin { fn build(&self, app: &mut App) { app.register_asset_loader(asset_loaders::NavMeshPolyanyaLoader) .init_asset::(); + + #[cfg(feature = "debug-with-gizmos")] + app.add_systems( + Update, + display_navmesh.run_if(resource_exists::), + ); } } @@ -290,7 +305,7 @@ impl NavMesh { } #[inline] - fn inverse_transform(&self) -> Transform { + pub(crate) fn inverse_transform(&self) -> Transform { Transform { translation: -self.transform.translation, rotation: self.transform.rotation.inverse(), @@ -311,6 +326,41 @@ fn get_vectors( vectors.iter().cloned().map(Vec3::from) } +#[cfg(feature = "debug-with-gizmos")] +/// Use gizmos to display navmeshes +pub fn display_navmesh( + live_navmeshes: Query<&Handle>, + mut gizmos: Gizmos, + navmeshes: Res>, + controls: Res, +) { + use bevy::math::vec3; + for mesh in &live_navmeshes { + if let Some(navmesh) = navmeshes.get(mesh) { + let inverse_transform = navmesh.inverse_transform(); + let navmesh = navmesh.get(); + for polygon in &navmesh.polygons { + let mut v = polygon + .vertices + .iter() + .map(|i| &navmesh.vertices[*i as usize].coords) + .map(|v| inverse_transform.transform_point(vec3(v.x, v.y, 0.0))) + .collect::>(); + if !v.is_empty() { + let first = polygon.vertices[0]; + let first = &navmesh.vertices[first as usize]; + v.push(inverse_transform.transform_point(vec3( + first.coords.x, + first.coords.y, + 0.0, + ))); + gizmos.linestrip(v, controls.0); + } + } + } + } +} + #[cfg(test)] mod tests { use polyanya::Trimesh;