use bevy::{ color::palettes::css::{ANTIQUE_WHITE, PURPLE, SEA_GREEN}, input::common_conditions::input_just_pressed, prelude::*, render::mesh::{CylinderAnchor, CylinderMeshBuilder}, }; use bevy_landmass::{ debug::{EnableLandmassDebug, Landmass3dDebugPlugin}, prelude::*, }; use bevy_rapier3d::{ geometry::{AsyncCollider, ComputedColliderShape}, plugin::{NoUserData, RapierPhysicsPlugin}, prelude::Collider, }; use landmass_oxidized_navigation::{ LandmassOxidizedNavigationPlugin, OxidizedArchipelago, }; use oxidized_navigation::{ NavMeshAffector, NavMeshSettings, OxidizedNavigationPlugin, }; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(RapierPhysicsPlugin::::default()) .add_plugins(OxidizedNavigationPlugin::::new(NavMeshSettings { tile_width: 40, ..NavMeshSettings::from_agent_and_bounds(0.5, 2.0, 10.0, -5.0) })) .add_plugins(Landmass3dPlugin::default()) .add_plugins(Landmass3dDebugPlugin::default()) .add_plugins(LandmassOxidizedNavigationPlugin) .add_systems(Startup, setup) .add_systems(Update, handle_clicks) .add_systems(Update, toggle_debug.run_if(input_just_pressed(KeyCode::F12))) .add_systems( Update, (update_agent_velocity, move_agent_by_velocity).chain(), ) .run(); } fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, asset_server: Res, ) { commands.spawn(Camera3dBundle { transform: Transform::from_xyz(0.0, 1.0, -1.0) .looking_to(Vec3::new(0.0, -1.0, 0.0), Vec3::new(0.0, 0.0, -1.0)), projection: Projection::Orthographic(OrthographicProjection { scaling_mode: bevy::render::camera::ScalingMode::FixedVertical(12.0), ..Default::default() }), ..Default::default() }); commands.spawn(TextBundle { text: Text::from_section( "LMB - Spawn agent\nRMB - Change target point\nF12 - Toggle debug view", TextStyle::default(), ) .with_justify(JustifyText::Right), style: Style { position_type: PositionType::Absolute, right: Val::Px(0.0), bottom: Val::Px(0.0), ..Default::default() }, ..Default::default() }); let archipelago_entity = commands.spawn((Archipelago3d::new(), OxidizedArchipelago)).id(); // Spawn the floors. commands.spawn(( MaterialMeshBundle { mesh: asset_server.load("floor.glb#Mesh0/Primitive0"), material: materials.add(StandardMaterial { unlit: true, base_color: ANTIQUE_WHITE.into(), ..Default::default() }), ..Default::default() }, AsyncCollider(ComputedColliderShape::TriMesh), NavMeshAffector, )); commands.spawn(( MaterialMeshBundle { mesh: asset_server.load("floor.glb#Mesh1/Primitive0"), material: materials.add(StandardMaterial { unlit: true, base_color: ANTIQUE_WHITE.into(), ..Default::default() }), ..Default::default() }, AsyncCollider(ComputedColliderShape::TriMesh), NavMeshAffector, )); // Spawn the target. let target_entity = commands .spawn(( MaterialMeshBundle { transform: Transform::from_translation(Vec3::new(0.0, 0.0, 3.0)), mesh: meshes.add( CylinderMeshBuilder { cylinder: Cylinder { radius: 0.25, half_height: 0.1 }, resolution: 20, segments: 1, anchor: CylinderAnchor::MidPoint, caps: true, } .build(), ), material: materials.add(StandardMaterial { unlit: true, base_color: PURPLE.into(), ..Default::default() }), ..Default::default() }, Target, )) .id(); commands.insert_resource(AgentSpawner { mesh: meshes.add( CylinderMeshBuilder { cylinder: Cylinder { radius: 0.5, half_height: 0.1 }, resolution: 20, segments: 1, anchor: CylinderAnchor::MidPoint, caps: true, } .build(), ), material: materials.add(StandardMaterial { unlit: true, base_color: SEA_GREEN.into(), ..Default::default() }), archipelago_entity, target_entity, }); } #[derive(Resource)] struct AgentSpawner { mesh: Handle, material: Handle, archipelago_entity: Entity, target_entity: Entity, } impl AgentSpawner { fn spawn(&self, position: Vec3, commands: &mut Commands) { commands.spawn(( MaterialMeshBundle { transform: Transform::from_translation(position), mesh: self.mesh.clone(), material: self.material.clone(), ..Default::default() }, Agent3dBundle { agent: Agent { radius: 0.5, desired_speed: 2.0, max_speed: 3.0 }, archipelago_ref: ArchipelagoRef3d::new(self.archipelago_entity), target: AgentTarget3d::Entity(self.target_entity), state: Default::default(), velocity: Default::default(), desired_velocity: Default::default(), }, )); } } /// Use the desired velocity as the agent's velocity. fn update_agent_velocity( mut agent_query: Query<(&mut Velocity3d, &AgentDesiredVelocity3d)>, ) { for (mut velocity, desired_velocity) in agent_query.iter_mut() { velocity.velocity = desired_velocity.velocity(); } } /// Apply the agent's velocity to its position. fn move_agent_by_velocity( time: Res