diff --git a/examples/demo.rs b/examples/demo.rs index ebb7786..fae32b8 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -229,7 +229,7 @@ fn setup(mut commands: Commands, mut materials: ResMut> build_timeout: Some(0.5), ..default() }, - transform: Transform::from_rotation(Quat::from_rotation_x(FRAC_PI_2)), + transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)), // Mark it for update as soon as obstacles are changed. // Other modes can be debounced or manually triggered. update_mode: NavMeshUpdateMode::Debounced(0.2), diff --git a/examples/primitive_3d.rs b/examples/primitive_3d.rs index a6c2c46..8b1d36c 100644 --- a/examples/primitive_3d.rs +++ b/examples/primitive_3d.rs @@ -1,6 +1,11 @@ use std::f32::consts::{FRAC_PI_2, PI}; -use bevy::{color::palettes, math::vec2, pbr::NotShadowCaster, prelude::*, window::PrimaryWindow}; +use bevy::{ + color::palettes, + math::{vec2, vec3}, + prelude::*, + window::PrimaryWindow, +}; use polyanya::Triangulation; use rand::Rng; use vleue_navigator::prelude::*; @@ -44,7 +49,6 @@ fn main() { .add_systems( Update, ( - display_mesh, spawn_obstacle_on_click.after(ui::update_settings::<10>), ui::update_stats::, remove_obstacles, @@ -99,24 +103,46 @@ fn setup( } // Spawn a new navmesh that will be automatically updated. - commands.spawn(NavMeshBundle { - settings: NavMeshSettings { - // Define the outer borders of the navmesh. - fixed: Triangulation::from_outer_edges(&vec![ - vec2(0.0, 0.0), - vec2(MESH_WIDTH as f32, 0.0), - vec2(MESH_WIDTH as f32, MESH_HEIGHT as f32), - vec2(0.0, MESH_HEIGHT as f32), - ]), - simplify: 0.001, - merge_steps: 0, + commands.spawn(( + NavMeshBundle { + settings: NavMeshSettings { + // Define the outer borders of the navmesh. + fixed: Triangulation::from_outer_edges(&vec![ + vec2(0.0, 0.0), + vec2(MESH_WIDTH as f32, 0.0), + vec2(MESH_WIDTH as f32, MESH_HEIGHT as f32), + vec2(0.0, MESH_HEIGHT as f32), + ]), + simplify: 0.001, + merge_steps: 0, + + ..default() + }, + transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)), + // Mark it for update as soon as obstacles are changed. + // Other modes can be debounced or manually triggered. + update_mode: NavMeshUpdateMode::Direct, ..default() }, - transform: Transform::from_rotation(Quat::from_rotation_x(FRAC_PI_2)), - // Mark it for update as soon as obstacles are changed. - // Other modes can be debounced or manually triggered. - update_mode: NavMeshUpdateMode::Direct, + NavMeshDebug(palettes::tailwind::SLATE_800.into()), + )); + + commands.spawn(PbrBundle { + mesh: meshes + .add(Plane3d::new( + Vec3::Y, + Vec2::new(MESH_WIDTH as f32 / 2.0, MESH_HEIGHT as f32 / 2.0), + )) + .into(), + transform: Transform::from_translation(Vec3::new( + MESH_WIDTH as f32 / 2.0, + 0.0, + MESH_HEIGHT as f32 / 2.0, + )), + material: materials.add(StandardMaterial::from(Color::Srgba( + palettes::tailwind::BLUE_800, + ))), ..default() }); @@ -159,8 +185,7 @@ fn new_obstacle( }; commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Rectangle(larger_primitive), )) .with_children(|parent| { @@ -181,8 +206,7 @@ fn new_obstacle( }; commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Circle(larger_primitive), )) .with_children(|parent| { @@ -203,8 +227,7 @@ fn new_obstacle( }; commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Ellipse(larger_primitive), )) .with_children(|parent| { @@ -225,8 +248,7 @@ fn new_obstacle( }); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::CircularSector(larger_primitive), )) .with_children(|parent| { @@ -246,8 +268,7 @@ fn new_obstacle( }); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::CircularSegment(larger_primitive), )) .with_children(|parent| { @@ -265,8 +286,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), )) .with_children(|parent| { @@ -284,8 +304,7 @@ fn new_obstacle( RegularPolygon::new(primitive.circumradius() + radius, primitive.sides); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::RegularPolygon(larger_primitive), )) .with_children(|parent| { @@ -305,8 +324,7 @@ fn new_obstacle( ); commands .spawn(( - transform, - GlobalTransform::default(), + SpatialBundle::from_transform(transform), PrimitiveObstacle::Rhombus(larger_primitive), )) .with_children(|parent| { @@ -322,66 +340,6 @@ fn new_obstacle( } } -fn display_mesh( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, - navmeshes: Res>, - mut current_mesh_entity: Local>, - navmesh: Query<(&Handle, Ref)>, -) { - let (navmesh_handle, status) = navmesh.single(); - if !status.is_changed() { - return; - } - - let Some(navmesh) = navmeshes.get(navmesh_handle) else { - return; - }; - if let Some(entity) = *current_mesh_entity { - commands.entity(entity).despawn_recursive(); - } - - *current_mesh_entity = Some( - commands - .spawn(PbrBundle { - mesh: meshes - .add(Plane3d::new( - Vec3::Y, - Vec2::new(MESH_WIDTH as f32 / 2.0, MESH_HEIGHT as f32 / 2.0), - )) - .into(), - transform: Transform::from_translation(Vec3::new( - (MESH_WIDTH as f32) / 2.0, - 0.0, - MESH_HEIGHT as f32 / 2.0, - )), - material: materials.add(StandardMaterial::from(Color::Srgba( - palettes::tailwind::BLUE_800, - ))), - ..default() - }) - .with_children(|main_mesh| { - main_mesh.spawn(( - PbrBundle { - mesh: meshes.add(navmesh.to_wireframe_mesh()).into(), - material: materials.add(StandardMaterial::from(Color::Srgba( - palettes::tailwind::BLUE_400, - ))), - transform: Transform::from_translation(Vec3::new( - -(MESH_WIDTH as f32) / 2.0, - 0.1, - -(MESH_HEIGHT as f32) / 2.0, - )), - ..default() - }, - NotShadowCaster, - )); - }) - .id(), - ); -} - fn spawn_obstacle_on_click( mouse_button_input: Res>, primary_window: Query<&Window, With>, diff --git a/src/lib.rs b/src/lib.rs index 83ffef1..036301b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ missing_docs )] -use std::{f32::consts::PI, sync::Arc}; +use std::sync::Arc; #[cfg(feature = "debug-with-gizmos")] use bevy::{ @@ -24,7 +24,7 @@ use bevy::{ app::{App, Plugin}, asset::{Asset, AssetApp}, log::{debug, warn}, - math::{vec2, Quat, Vec2, Vec3, Vec3Swizzles}, + math::{Quat, Vec2, Vec3, Vec3Swizzles}, prelude::{Mesh, Transform}, reflect::TypePath, render::{ @@ -334,13 +334,11 @@ impl NavMesh { } pub(crate) fn mesh_to_world(navmesh_transform: &Transform) -> Transform { - let mut transform = Transform { + Transform { translation: navmesh_transform.translation, rotation: navmesh_transform.rotation.inverse(), scale: 1.0 / navmesh_transform.scale, - }; - // transform.rotate(Quat::from_rotation_x(std::f32::consts::PI)); - transform + } } fn get_vectors( diff --git a/src/obstacles/primitive.rs b/src/obstacles/primitive.rs index a71ec3f..e6abb66 100644 --- a/src/obstacles/primitive.rs +++ b/src/obstacles/primitive.rs @@ -76,41 +76,47 @@ impl ObstacleSource for PrimitiveObstacle { navmesh_transform: &Transform, ) -> Vec { let transform = obstacle_transform.compute_transform(); - let to_vec2 = |v: Vec3| navmesh_transform.transform_point(v).xy(); + let to_vec2 = |v: Vec3| v.xy(); + + let to_navmesh_vec3 = |v: Vec3| { + let v = navmesh_transform.rotation.mul_vec3(v); + v + }; + let to_navmesh = |v: Vec2| { - navmesh_transform - .compute_affine() - .inverse() - .transform_point3(v.extend(0.0)) + let v = v.extend(0.0); + let v = navmesh_transform.rotation.inverse().mul_vec3(v); + let v = transform.transform_point(v); + to_navmesh_vec3(v) }; match self { PrimitiveObstacle::Rectangle(primitive) => vec![ - to_vec2(transform.transform_point(to_navmesh(vec2( + to_vec2(to_navmesh(vec2( -primitive.half_size.x, -primitive.half_size.y, - )))), - to_vec2(transform.transform_point(to_navmesh(vec2( + ))), + to_vec2(to_navmesh(vec2( -primitive.half_size.x, primitive.half_size.y, - )))), - to_vec2(transform.transform_point(to_navmesh(vec2( + ))), + to_vec2(to_navmesh(vec2( primitive.half_size.x, primitive.half_size.y, - )))), - to_vec2(transform.transform_point(to_navmesh(vec2( + ))), + to_vec2(to_navmesh(vec2( primitive.half_size.x, -primitive.half_size.y, - )))), + ))), ], PrimitiveObstacle::Circle(primitive) => { copypasta::ellipse_inner(vec2(primitive.radius, primitive.radius), RESOLUTION) - .map(|v| to_vec2(transform.transform_point(to_navmesh(v)))) + .map(|v| to_vec2(to_navmesh(v))) .collect() } PrimitiveObstacle::Ellipse(primitive) => { copypasta::ellipse_inner(primitive.half_size, RESOLUTION) - .map(|v| to_vec2(transform.transform_point(to_navmesh(v)))) + .map(|v| to_vec2(to_navmesh(v))) .collect() } PrimitiveObstacle::CircularSector(primitive) => { @@ -120,9 +126,9 @@ impl ObstacleSource for PrimitiveObstacle { primitive.arc.radius, RESOLUTION, ) - .map(|v| to_vec2(transform.transform_point(to_navmesh(v)))) + .map(|v| to_vec2(to_navmesh(v))) .collect::>(); - arc.push(to_vec2(transform.translation)); + arc.push(to_vec2(to_navmesh_vec3(transform.translation))); arc } PrimitiveObstacle::CircularSegment(primitive) => copypasta::arc_2d_inner( @@ -131,7 +137,7 @@ impl ObstacleSource for PrimitiveObstacle { primitive.arc.radius, RESOLUTION, ) - .map(|v| to_vec2(transform.transform_point(to_navmesh(v)))) + .map(|v| to_vec2(to_navmesh(v))) .collect(), PrimitiveObstacle::Capsule(primitive) => { let mut points = copypasta::arc_2d_inner( @@ -140,11 +146,7 @@ impl ObstacleSource for PrimitiveObstacle { primitive.radius, RESOLUTION, ) - .map(|v| { - to_vec2( - transform.transform_point(to_navmesh(v + primitive.half_length * Vec2::Y)), - ) - }) + .map(|v| to_vec2(to_navmesh(v + primitive.half_length * Vec2::Y))) .collect::>(); points.extend( copypasta::arc_2d_inner( @@ -154,10 +156,10 @@ impl ObstacleSource for PrimitiveObstacle { RESOLUTION, ) .map(|v| { - to_vec2(transform.transform_point(to_navmesh( + to_vec2(to_navmesh( (Rot2::radians(std::f32::consts::PI) * v) - primitive.half_length * Vec2::Y, - ))) + )) }), ); points @@ -170,7 +172,7 @@ impl ObstacleSource for PrimitiveObstacle { p, ) }) - .map(|v| to_vec2(transform.transform_point(to_navmesh(v)))) + .map(|v| to_vec2(to_navmesh(v))) .collect(), PrimitiveObstacle::Rhombus(primitive) => { [(1.0, 0.0), (0.0, 1.0), (-1.0, 0.0), (0.0, -1.0)] @@ -181,7 +183,7 @@ impl ObstacleSource for PrimitiveObstacle { ) }) .into_iter() - .map(|v| to_vec2(transform.transform_point(to_navmesh(v)))) + .map(|v| to_vec2(to_navmesh(v))) .collect() } }