use bevy::{color::palettes, prelude::*}; use rand::Rng; use vleue_navigator::prelude::*; #[derive(Component)] pub struct Navigator { speed: f32, } #[derive(Component)] pub struct Path { current: Vec2, next: Vec, target: Entity, } pub fn setup_agent(mut commands: Commands) { commands.spawn(( SpriteBundle { sprite: Sprite { color: palettes::css::RED.into(), custom_size: Some(Vec2::ONE), ..default() }, transform: Transform::from_translation(Vec3::new(0.0, 0.0, 1.0)) .with_scale(Vec3::splat(SIZE as f32)), ..default() }, Navigator { speed: SIZE as f32 * 5.0, }, )); } pub fn give_target_to_navigator( mut commands: Commands, navigator: Query<(Entity, &Transform), (With, Without)>, navmeshes: Res>, navmesh: Query<&Handle>, ) { for (entity, transform) in &navigator { let Some(navmesh) = navmeshes.get(navmesh.single()) else { continue; }; let mut x = 1.0; let mut y = 1.0; for _ in 0..10 { x = rand::thread_rng().gen_range(0.0..(X as f32)); y = rand::thread_rng().gen_range(0.0..(Y as f32)); if navmesh.is_in_mesh(Vec2::new(x, y)) { break; } } let Some(path) = navmesh.transformed_path( transform.translation.xyz(), navmesh.transform().transform_point(Vec3::new(x, y, 0.0)), ) else { break; }; if let Some((first, remaining)) = path.path.split_first() { let mut remaining = remaining.iter().map(|p| p.xy()).collect::>(); remaining.reverse(); let id = commands .spawn(SpriteBundle { sprite: Sprite { color: palettes::tailwind::FUCHSIA_500.into(), custom_size: Some(Vec2::ONE), ..default() }, transform: Transform::from_translation( remaining.first().unwrap_or(&first.xy()).extend(1.5), ) .with_scale(Vec3::splat(SIZE as f32)), ..default() }) .id(); commands.entity(entity).insert(Path { current: first.xy(), next: remaining, target: id, }); } } } pub fn refresh_path( mut commands: Commands, mut navigator: Query<(Entity, &Transform, &mut Path), With>, mut navmeshes: ResMut>, navmesh: Query<(&Handle, Ref)>, transforms: Query<&Transform>, mut delta: Local, ) { let (navmesh_handle, status) = navmesh.single(); if (!status.is_changed() || *status != NavMeshStatus::Built) && *delta == 0.0 { return; } let Some(navmesh) = navmeshes.get_mut(navmesh_handle) else { return; }; for (entity, transform, mut path) in &mut navigator { let target = transforms.get(path.target).unwrap().translation.xy(); if !navmesh.transformed_is_in_mesh(transform.translation) { *delta += 0.1; navmesh.set_search_delta(*delta); continue; } if !navmesh.transformed_is_in_mesh(target.extend(0.0)) { commands.entity(path.target).despawn(); commands.entity(entity).remove::(); continue; } let Some(new_path) = navmesh.transformed_path(transform.translation, target.extend(0.0)) else { commands.entity(path.target).despawn(); commands.entity(entity).remove::(); continue; }; if let Some((first, remaining)) = new_path.path.split_first() { let mut remaining = remaining.iter().map(|p| p.xy()).collect::>(); remaining.reverse(); path.current = first.xy(); path.next = remaining; *delta = 0.0; } } } pub fn move_navigator( mut commands: Commands, mut navigator: Query<(&mut Transform, &mut Path, Entity, &Navigator)>, time: Res