### Complete Bevy Landmass Setup Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md A full example demonstrating the setup of a Bevy application with the Landmass3dPlugin. It includes creating an archipelago, a nav mesh, an island, and an agent, along with basic agent control. ```rust use bevy::prelude::*; use bevy_landmass::prelude::*; use glam::Vec3; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(Landmass3dPlugin::default()) .add_systems(Startup, setup) .add_systems(Update, control_agent_target) .run(); } fn setup( mut commands: Commands, mut meshes: ResMut>, ) { // Create archipelago let archipelago = Archipelago3d::new( ArchipelagoOptions::from_agent_radius(0.5) ); let archipelago_entity = commands.spawn(archipelago).id(); // Create nav mesh let nav_mesh = NavigationMesh3d { vertices: vec![ Vec3::new(0.0, 0.0, 0.0), Vec3::new(10.0, 0.0, 0.0), Vec3::new(10.0, 10.0, 0.0), Vec3::new(0.0, 10.0, 0.0), ], polygons: vec![vec![0, 1, 2, 3]], polygon_type_indices: vec![0], height_mesh: None, }; let valid_mesh = nav_mesh.validate().unwrap(); let mesh_handle = meshes.add(NavMesh3d { nav_mesh: Arc::new(valid_mesh), }); // Add island commands.spawn(Island3dBundle { island: Island, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), nav_mesh: NavMeshHandle(mesh_handle), ..default() }); // Add agent commands.spawn(( Agent3dBundle { agent: Agent::::default(), settings: AgentSettings { radius: 0.5, desired_speed: 3.0, max_speed: 5.0, }, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), ..default() }, Transform::from_xyz(1.0, 0.0, 1.0), )); } fn control_agent_target( keyboard: Res>, mut targets: Query<&mut AgentTarget3d>, ) { if keyboard.just_pressed(KeyCode::Space) { for mut target in targets.iter_mut() { target.0 = Some(Vec3::new(8.0, 0.0, 8.0)); } } } ``` -------------------------------- ### Minimal Core Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/00-index.md Demonstrates the basic setup for creating a navigation mesh, an archipelago, adding an island and an agent, and running a simple update loop to observe agent behavior. ```rust use landmass::{Archipelago, Agent, Island, NavigationMesh, XYZ}; use glam::Vec3; use std::sync::Arc; // Create mesh let mesh = NavigationMesh { vertices: vec![Vec3::ZERO, Vec3::X * 10.0, Vec3::Y * 10.0, Vec3::ONE * 10.0], polygons: vec![vec![0, 1, 3, 2]], polygon_type_indices: vec![0], height_mesh: None, }; // Create archipelago let mut archipelago = Archipelago::new( ArchipelagoOptions::from_agent_radius(0.5) ); // Add island let island = Island::new(Default::default(), Arc::new(mesh.validate()?)); archipelago.add_island(island); // Add agent let mut agent = Agent::create(Vec3::ZERO, Vec3::ZERO, 0.5, 3.0, 5.0); agent.current_target = Some(Vec3::new(8.0, 8.0, 0.0)); let agent_id = archipelago.add_agent(agent); // Update loop for _ in 0..100 { archipelago.update(0.016); if let Some(agent) = archipelago.get_agent(agent_id) { println!("Desired velocity: {:?}", agent.get_desired_velocity()); } } ``` -------------------------------- ### Bevy App Setup with Landmass Rerecast Source: https://github.com/andriydev/landmass/blob/main/crates/landmass_rerecast/README.md Sets up a Bevy application with necessary plugins for landmass, rerecast, and the landmass_rerecast integration. Includes asset initialization and system definitions for agent pathfinding and navmesh readiness checks. This example is for demonstration and testing purposes. ```rust use bevy::prelude::*; use bevy::time::TimeUpdateStrategy; use bevy_landmass::{Agent, PointSampleDistance3d, prelude::*}; use bevy_rerecast::{Mesh3dBackendPlugin, prelude::*}; use landmass_rerecast::LandmassRerecastPlugin; use landmass_rerecast::{Island3dBundle, NavMeshHandle3d}; use std::time::Duration; fn main() { App::new() .add_plugins(( MinimalPlugins, AssetPlugin::default(), TransformPlugin, NavmeshPlugins::default(), Mesh3dBackendPlugin::default(), Landmass3dPlugin::default(), LandmassRerecastPlugin::default(), )) // This is just here to ensure that the fixed timestep is run when this code is run as an automated test. // Don't copy it into your own code. .insert_resource(TimeUpdateStrategy::ManualDuration( Time::::default().timestep(), )) .init_asset::() .init_asset::() .add_systems(Startup, setup) .add_systems( Update, check_for_path_and_exit.run_if(resource_exists::), ) .add_observer(check_after_navmesh_ready) .run(); } fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, mut generator: NavmeshGenerator, ) { commands.spawn(( Mesh3d(meshes.add(Cuboid::new(20.0, 1.0, 20.0))), MeshMaterial3d(materials.add(StandardMaterial { base_color: Srgba::WHITE.into(), ..Default::default() })), )); let archipelago = commands .spawn(Archipelago3d::new(ArchipelagoOptions { point_sample_distance: PointSampleDistance3d { distance_above: 0.5, distance_below: 0.5, ..PointSampleDistance3d::from_agent_radius(0.5) }, ..ArchipelagoOptions::from_agent_radius(0.5) })) .id(); // This island's nav mesh will be generated by `bevy_rerecast`! commands.spawn(Island3dBundle { island: Island, archipelago_ref: ArchipelagoRef3d::new(archipelago), nav_mesh: NavMeshHandle3d( generator .generate(NavmeshSettings { agent_radius: 0.5, ..Default::default() }), ), }); // Create an agent that will find a path as soon as the nav mesh is generated. commands.spawn(( Agent3dBundle { agent: Agent::default(), archipelago_ref: ArchipelagoRef3d::new(archipelago), settings: AgentSettings { desired_speed: 5.0, max_speed: 10.0, radius: 0.5, }, }, Transform::from_xyz(-5.0, 0.5, -5.0), AgentTarget3d::Point(Vec3::new(5.0, 0.5, 5.0)), )); } // All the stuff below here is just to allow the doc tests to pass. fn check_after_navmesh_ready(_: On, mut commands: Commands) { // Allow checking three times before failure, in case we need an extra frame // for the meshes to propagate. commands.insert_resource(CheckCounter(3)); } #[derive(Resource)] struct CheckCounter(usize); fn check_for_path_and_exit( agent: Single<(&AgentState, &AgentDesiredVelocity3d)>, mut check_counter: ResMut, mut exit: MessageWriter, ) { let (state, desired_velocity) = *agent; let expected_velocity = Vec3::new(1.0, 0.0, 1.0).normalize() * 5.0; if *state == AgentState::Moving && desired_velocity.velocity().abs_diff_eq(expected_velocity, 1e-3) { exit.write(AppExit::Success); return; } check_counter.0 -= 1; if check_counter.0 == 0 { panic!("Did not find expected path! state={state:?}, desired_velocity={desired_velocity:?}"); } } ``` -------------------------------- ### Complete Example: Creating and Managing Animation Links Source: https://github.com/andriydev/landmass/blob/main/_autodocs/06-animation-link.md A comprehensive example showing how to create a jump animation link, add it to the archipelago, and then handle agent interactions with it during an update loop. It also demonstrates how to manage multiple links. ```rust use landmass::{AnimationLink, Agent, XYZ}; use glam::Vec3; // Create a jump link let jump_link = AnimationLink { start_edge: ( Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 0.0, 0.0), ), end_edge: ( Vec3::new(5.0, 0.0, 0.0), Vec3::new(7.0, 0.0, 0.0), ), kind: 1, // Jump cost: 1.2, bidirectional: true, }; let jump_link_id = archipelago.add_animation_link(jump_link); // Update loop loop { archipelago.update(0.016); for agent_id in archipelago.get_agent_ids() { if let Some(agent) = archipelago.get_agent(agent_id) { if let Some(reached) = agent.reached_animation_link() { if reached.link_id == jump_link_id { println!("Agent reached jump!"); // Play jump animation // Then call agent.start_animation_link() // And finally agent.end_animation_link() when done } } } } } ``` ```rust use std::collections::HashMap; let mut link_ids = HashMap::new(); // Add links link_ids.insert("jump", archipelago.add_animation_link(jump_link)); link_ids.insert("climb", archipelago.add_animation_link(climb_link)); link_ids.insert("slide", archipelago.add_animation_link(slide_link)); // Remove links for (name, id) in link_ids.iter() { archipelago.remove_animation_link(*id); } ``` -------------------------------- ### Complete Pathfinding Example with Custom Function Source: https://github.com/andriydev/landmass/blob/main/_autodocs/08-queries-paths.md A comprehensive Rust function demonstrating how to find a walking path between two points, including sampling start and end points and iterating through the resulting path steps. This function encapsulates the pathfinding logic for reuse. ```rust use landmass::{Archipelago, PointSampleDistance3d, PermittedAnimationLinks, PathStep, XYZ}; use glam::Vec3; use std::collections::HashMap; fn find_walking_path( archipelago: &Archipelago, from: Vec3, to: Vec3, agent_radius: f32, ) -> Result>, Box> { let sample_dist = PointSampleDistance3d::from_agent_radius(agent_radius); let start = archipelago.sample_point(from, &sample_dist)?; let end = archipelago.sample_point(to, &sample_dist)?; let path = archipelago.find_path( &start, &end, &HashMap::new(), PermittedAnimationLinks::All, )?; Ok(path) } // Usage let path = find_walking_path(&archipelago, start_pos, end_pos, 0.5)?; for (i, step) in path.iter().enumerate() { match step { PathStep::Waypoint(point) => { println!("Step {}: Walk to ({:.1}, {:.1}, {:.1})", i, point.x, point.y, point.z); } PathStep::AnimationLink { link_id, .. } => { println!("Step {}: Use animation link {:?}", i, link_id); } } } ``` -------------------------------- ### PointSampleDistance3d Example Usage Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md Example of manually creating a PointSampleDistance3d instance and using it to sample a point on the archipelago. ```rust let sample_dist = PointSampleDistance3d { horizontal_distance: 2.0, distance_above: 1.0, distance_below: 2.0, vertical_preference_ratio: 1.0, animation_link_max_vertical_distance: 0.5, }; let sampled = archipelago.sample_point( Vec3::new(10.0, 5.0, 0.0), &sample_dist, )?; ``` -------------------------------- ### Animation Link Cost Examples Source: https://github.com/andriydev/landmass/blob/main/_autodocs/06-animation-link.md Provides examples of setting the 'cost' field for animation links to influence pathfinding. Lower costs are preferred by agents. ```rust // Cost examples (relative to normal walking cost of 1.0) AnimationLink { cost: 0.5, // Takes less time than walking (e.g., zipline) // ... } AnimationLink { cost: 1.0, // Same as walking // ... } AnimationLink { cost: 3.0, // Takes 3x as long (e.g., slow climb) // ... } ``` -------------------------------- ### AgentTarget Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Example of how to query and update the target position for an agent in a 3D environment. ```APIDOC ## AgentTarget Update ### Description Demonstrates how to query for agents and update their target destination. ### Method Query and mutable access to `AgentTarget` component. ### Example ```rust fn set_target(mut targets: Query<&mut AgentTarget3d>) { for mut target in targets.iter_mut() { target.0 = Some(Vec3::new(10.0, 0.0, 5.0)); } } ``` ``` -------------------------------- ### Example: Handling Reached Animation Link Source: https://github.com/andriydev/landmass/blob/main/_autodocs/06-animation-link.md Demonstrates how to check if an agent has reached an animation link and initiate actions based on it, such as finding and starting the associated animation or ending the link if it's no longer valid. ```rust if let Some(link) = agent.reached_animation_link() { println!("Agent should move from {:?} to {:?}", link.start_point, link.end_point); match find_animation_by_link_id(link.link_id) { Some(anim) => { start_animation(anim); agent.start_animation_link()?; } None => { // Link no longer valid, agent continues pathfinding agent.end_animation_link()?; } } } ``` -------------------------------- ### Example: Updating an Island's Transform Source: https://github.com/andriydev/landmass/blob/main/_autodocs/05-island.md Shows how to get a mutable reference to an island, modify its transform, and apply the changes using set_transform. ```rust if let Some(mut island) = archipelago.get_island_mut(island_id) { let mut new_transform = island.get_transform().clone(); new_transform.translation = Vec3::new(10.0, 0.0, 5.0); island.set_transform(new_transform); } ``` -------------------------------- ### Example: Set Terrain Type Cost Source: https://github.com/andriydev/landmass/blob/main/_autodocs/01-archipelago-core.md Demonstrates how to set a terrain type's traversal cost. This example makes sand cost twice as much to traverse. ```rust // Make sand cost 2x as much to traverse as normal terrain archipelago.set_type_index_cost(2, 2.0)?; ``` -------------------------------- ### Bevy Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/00-index.md Shows how to integrate Landmass with the Bevy game engine using the `bevy_landmass` plugin for 3D navigation. ```rust use bevy::prelude::*; use bevy_landmass::prelude::*; App::new() .add_plugins(Landmass3dPlugin::default()) .add_systems(Startup, |mut commands: Commands| { let archipelago = Archipelago3d::new( ArchipelagoOptions::from_agent_radius(0.5) ); let arch_entity = commands.spawn(archipelago).id(); commands.spawn(Agent3dBundle { archipelago_ref: ArchipelagoRef::from_entity(arch_entity), ..default() }); }) .run(); ``` -------------------------------- ### Example: Creating a Transform Source: https://github.com/andriydev/landmass/blob/main/_autodocs/05-island.md Illustrates the creation of a Transform object with specific translation and rotation values. ```rust use landmass::Transform; use glam::Vec3; use std::f32::consts::PI; let transform = Transform { translation: Vec3::new(10.0, 5.0, 0.0), rotation: PI / 4.0, // 45 degrees }; ``` -------------------------------- ### Generic Navigation Setup Function Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md A generic function that works with any `CoordinateSystem` to set up navigation in an archipelago. ```rust fn setup_navigation( archipelago: &mut Archipelago, mesh_data: &NavigationMesh, ) -> Result<(), ValidationError> { let valid_mesh = mesh_data.clone().validate()?; let island = Island::new(Transform::default(), std::sync::Arc::new(valid_mesh)); archipelago.add_island(island); Ok(()) } // Works for both 2D and 3D setup_navigation::(&mut arch_2d, &mesh_2d)?; setup_navigation::(&mut arch_3d, &mesh_3d)?; ``` -------------------------------- ### Bevy Integration: Setup Source: https://github.com/andriydev/landmass/blob/main/_autodocs/12-quick-start.md Sets up a Bevy application with Landmass integration, including creating an Archipelago, a navigation mesh, an island, and an agent. ```rust use bevy::prelude::*; use bevy_landmass::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(Landmass3dPlugin::default()) .add_systems(Startup, setup) .run(); } fn setup( mut commands: Commands, mut meshes: ResMut>, ) { // Create archipelago let archipelago = Archipelago3d::new( ArchipelagoOptions::from_agent_radius(0.5) ); let archipelago_entity = commands.spawn(archipelago).id(); // Create nav mesh let nav_mesh = NavigationMesh3d { vertices: vec![ Vec3::new(0.0, 0.0, 0.0), Vec3::new(10.0, 0.0, 0.0), Vec3::new(10.0, 10.0, 0.0), Vec3::new(0.0, 10.0, 0.0), ], polygons: vec![vec![0, 1, 2, 3]], polygon_type_indices: vec![0], height_mesh: None, }; let valid_mesh = nav_mesh.validate().unwrap(); let mesh_handle = meshes.add(NavMesh3d { nav_mesh: Arc::new(valid_mesh), }); // Add island commands.spawn(Island3dBundle { island: Island, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), nav_mesh: NavMeshHandle(mesh_handle), ..default() }); // Add agent commands.spawn(( Agent3dBundle { agent: Agent::default(), settings: AgentSettings { radius: 0.5, desired_speed: 3.0, max_speed: 5.0, }, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), ..default() }, Transform::from_xyz(1.0, 0.0, 1.0), )); } ``` -------------------------------- ### Example: Creating and Adding an Island Source: https://github.com/andriydev/landmass/blob/main/_autodocs/05-island.md Demonstrates how to create a navigation mesh, define its transform, instantiate an Island, and add it to an archipelago. ```rust use landmass::{Island, NavigationMesh, Transform, XYZ}; use glam::Vec3; use std::sync::Arc; let nav_mesh = NavigationMesh { /* ... */ }.validate()?; let transform = Transform { translation: Vec3::new(5.0, 0.0, 5.0), rotation: 0.0, }; let island = Island::new(transform, Arc::new(nav_mesh)); let island_id = archipelago.add_island(island); ``` -------------------------------- ### Example: Iterating and Matching Path Steps Source: https://github.com/andriydev/landmass/blob/main/_autodocs/08-queries-paths.md Demonstrates how to iterate through a found path and handle each `PathStep`, whether it's a `Waypoint` to move to or an `AnimationLink` to use. ```rust let path = archipelago.find_path(&start, &end, &HashMap::new(), PermittedAnimationLinks::All)?; for step in path { match step { PathStep::Waypoint(point) => { println!("Walk to {:?}", point); agent.target = point; } PathStep::AnimationLink { start_point, end_point, link_id } => { println!("Use animation link from {:?} to {:?}", start_point, end_point); // Handle animation link } } } ``` -------------------------------- ### Bevy Landmass Setup and Scene Configuration Source: https://github.com/andriydev/landmass/blob/main/crates/bevy_landmass/README.md Demonstrates how to set up a Bevy application with the Landmass2dPlugin and configure a scene with an archipelago, an island, and an agent for pathfinding. ```rust use std::sync::Arc; use bevy::{app::AppExit, prelude::*}; use bevy_landmass::{prelude::*, NavMeshHandle}; fn main() { App::new() .add_plugins(MinimalPlugins) .add_plugins(AssetPlugin::default()) .add_plugins(TransformPlugin) .add_plugins(Landmass2dPlugin::default()) .add_systems(Startup, set_up_scene) .add_systems(Update, print_desired_velocity) .add_systems(Update, quit.after(print_desired_velocity)) .run(); } fn set_up_scene( mut commands: Commands, mut nav_meshes: ResMut>, ) { let archipelago_id = commands .spawn(Archipelago2d::new(ArchipelagoOptions::from_agent_radius(0.5))) .id(); let nav_mesh_handle = nav_meshes.reserve_handle(); commands .spawn(( Island2dBundle { island: Island, archipelago_ref: ArchipelagoRef2d::new(archipelago_id), nav_mesh: NavMeshHandle(nav_mesh_handle.clone()), }, )); // The nav mesh can be populated in another system, or even several frames // later. let nav_mesh = Arc::new(NavigationMesh2d { vertices: vec![ Vec2::new(1.0, 1.0), Vec2::new(2.0, 1.0), Vec2::new(2.0, 2.0), Vec2::new(1.0, 2.0), Vec2::new(2.0, 3.0), Vec2::new(1.0, 3.0), Vec2::new(2.0, 4.0), Vec2::new(1.0, 4.0), ], polygons: vec![ vec![0, 1, 2, 3], vec![3, 2, 4, 5], vec![5, 4, 6, 7], ], polygon_type_indices: vec![0, 0, 0], height_mesh: None, }.validate().expect("is valid")); nav_meshes.insert(&nav_mesh_handle, NavMesh2d { nav_mesh }); commands.spawn(( Transform::from_translation(Vec3::new(1.5, 1.5, 0.0)), Agent2dBundle { agent: Default::default(), settings: AgentSettings { radius: 0.5, desired_speed: 1.0, max_speed: 2.0, }, archipelago_ref: ArchipelagoRef2d::new(archipelago_id), }, AgentTarget2d::Point(Vec2::new(1.5, 3.5)), )); } fn print_desired_velocity(query: Query<(Entity, &AgentDesiredVelocity2d)>) { for (entity, desired_velocity) in query.iter() { println!( "entity={{:?}}, desired_velocity={}", entity, desired_velocity.velocity()); } } fn quit(mut exit: MessageWriter) { // Quit so doctests pass. exit.write(AppExit::Success); } ``` -------------------------------- ### Creating a Default Character Source: https://github.com/andriydev/landmass/blob/main/_autodocs/03-character.md Example of how to create a default Character instance using the Default trait. ```rust use landmass::{Character, XYZ}; let character = Character::::default(); ``` -------------------------------- ### Island3dBundle Spawn Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Spawns an island in a 3D environment. Requires `Transform` component. ```rust commands.spawn(Island3dBundle { island: Island, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), nav_mesh: NavMeshHandle(nav_mesh_handle), ..default() }); ``` -------------------------------- ### NotReachedAnimationLinkError Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/09-errors.md Shows an agent attempting to start an animation link before reaching one, causing NotReachedAnimationLinkError. Ensure the agent has reached a link first. ```rust let agent = archipelago.get_agent_mut(agent_id).unwrap(); agent.start_animation_link()?; ``` -------------------------------- ### Example: Find Path and Iterate Steps Source: https://github.com/andriydev/landmass/blob/main/_autodocs/01-archipelago-core.md Illustrates finding a path using default terrain costs and then iterating through the resulting path steps, handling waypoints and animation links. ```rust let path = archipelago.find_path( &start_sampled, &end_sampled, &HashMap::new(), PermittedAnimationLinks::All, )?; for step in path { match step { PathStep::Waypoint(point) => { // Move toward this point } PathStep::AnimationLink { start_point, end_point, link_id } => { // Use animation link } } } ``` -------------------------------- ### LandmassPlugin Setup Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Registers Bevy systems and assets for Landmass. Use `in_schedule` to specify the Bevy schedule for plugin execution. ```rust pub struct LandmassPlugin { schedule: Interned, } ``` ```rust pub fn in_schedule(mut self, schedule: impl ScheduleLabel) -> Self ``` ```rust use bevy::prelude::*; use bevy_landmass::{Landmass3dPlugin, LandmassSystems}; fn main() { App::new() .add_plugins(Landmass3dPlugin::default().in_schedule(FixedPreUpdate)) .run(); } ``` -------------------------------- ### Example: Sample Point Source: https://github.com/andriydev/landmass/blob/main/_autodocs/01-archipelago-core.md Demonstrates sampling a 3D world point onto the navigation mesh with specified distance constraints. Requires importing `PointSampleDistance3d`. ```rust use landmass::PointSampleDistance3d; let sampled = archipelago.sample_point( Vec3::new(10.0, 0.0, 5.0), &PointSampleDistance3d { horizontal_distance: 1.0, distance_above: 1.0, distance_below: 1.0, vertical_preference_ratio: 1.0, animation_link_max_vertical_distance: 0.5, } )?; ``` -------------------------------- ### Setup LandmassRerecastPlugin Source: https://github.com/andriydev/landmass/blob/main/_autodocs/11-rerecast-integration.md Add Landmass3dPlugin and LandmassRerecastPlugin to your Bevy application. This enables automatic conversion of Recast meshes. ```rust use bevy::prelude::*; use bevy_landmass::prelude::*; use bevy_landmass_rerecast::{LandmassRerecastPlugin, NavMeshHandle3d}; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(Landmass3dPlugin::default()) .add_plugins(LandmassRerecastPlugin::default()) .run(); } fn setup(commands: Commands, rerecast_meshes: Handle) { // Add island with Rerecast mesh commands.spawn(Island3dBundle { island: Island, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), nav_mesh: NavMeshHandle3d(rerecast_mesh_handle), // Auto-converted! }); } ``` -------------------------------- ### XYZ Coordinate System Archipelago Initialization Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md Example of initializing an Archipelago with the XYZ coordinate system. ```rust use landmass::{Archipelago, XYZ}; let mut archipelago = Archipelago::::new(options); ``` -------------------------------- ### NoPathFound Debugging Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/09-errors.md Shows how to debug a NoPathFound error from find_path. Verifies point sampling, region connectivity, and terrain costs. ```rust let path = archipelago.find_path(/* ... */)?; // If NoPathFound, verify: // 1. Both points sample successfully // 2. They're on connected mesh regions // 3. No terrain costs are prohibitive ``` -------------------------------- ### Basic Landmass Navigation Setup and Simulation Source: https://github.com/andriydev/landmass/blob/main/crates/landmass/README.md Demonstrates the initialization of an Archipelago, adding an Island with a navigation mesh, and setting up two agents with opposing targets. It then simulates agent movement over several frames, updating their positions based on desired velocities and verifying their final positions. ```rust use glam::Vec3; use landmass::* use std::{sync::Arc, collections::HashMap}; let mut archipelago = Archipelago::::new(ArchipelagoOptions::from_agent_radius(0.5)); let nav_mesh = NavigationMesh { vertices: vec![ Vec3::new(0.0, 0.0, 0.0), Vec3::new(15.0, 0.0, 0.0), Vec3::new(15.0, 15.0, 0.0), Vec3::new(0.0, 15.0, 0.0), ], polygons: vec![vec![0, 1, 2, 3]], polygon_type_indices: vec![0], height_mesh: None, }; let valid_nav_mesh = Arc::new( nav_mesh.validate().expect("Validation succeeds") ); let island_id = archipelago .add_island(Island::new( Transform { translation: Vec3::ZERO, rotation: 0.0 }, valid_nav_mesh, )); let agent_1 = archipelago.add_agent({ let mut agent = Agent::create( /* position= */ Vec3::new(1.0, 1.0, 0.0), /* velocity= */ Vec3::ZERO, /* radius= */ 1.0, /* desired_speed= */ 1.0, /* max_speed= */ 2.0, ); agent.current_target = Some(Vec3::new(11.0, 1.1, 0.0)); agent.target_reached_condition = TargetReachedCondition::Distance(Some(0.01)); agent }); let agent_2 = archipelago.add_agent({ let mut agent = Agent::create( /* position= */ Vec3::new(11.0, 1.1, 0.0), /* velocity= */ Vec3::ZERO, /* radius= */ 1.0, /* desired_speed= */ 1.0, /* max_speed= */ 2.0, ); agent.current_target = Some(Vec3::new(1.0, 1.0, 0.0)); agent.target_reached_condition = TargetReachedCondition::Distance(Some(0.01)); agent }); for i in 0..300 { let delta_time = 1.0 / 10.0; archipelago.update(delta_time); for agent_id in archipelago.get_agent_ids().collect::>() { let agent = archipelago.get_agent_mut(agent_id).unwrap(); agent.velocity = *agent.get_desired_velocity(); agent.position += agent.velocity * delta_time; } } assert!(archipelago .get_agent(agent_1) .unwrap() .position .abs_diff_eq(Vec3::new(11.0, 1.1, 0.0), 0.1)); assert!(archipelago .get_agent(agent_2) .unwrap() .position .abs_diff_eq(Vec3::new(1.0, 1.0, 0.0), 0.1)); ``` -------------------------------- ### Simple Island Creation Pattern Source: https://github.com/andriydev/landmass/blob/main/_autodocs/05-island.md A concise example demonstrating the creation of an Island with default transform and a validated navigation mesh, then adding it to an archipelago. ```rust let mesh = NavigationMesh { /* ... */ }.validate()?; let island = Island::new( Transform::default(), Arc::new(mesh), ); archipelago.add_island(island); ``` -------------------------------- ### Example: Sampling a Point and Accessing its Properties Source: https://github.com/andriydev/landmass/blob/main/_autodocs/08-queries-paths.md Demonstrates how to sample a point on the navigation mesh using `sample_point` and then retrieve its island ID and terrain type index. ```rust use landmass::PointSampleDistance3d; let sample_dist = PointSampleDistance3d { horizontal_distance: 1.0, distance_above: 1.0, distance_below: 1.0, vertical_preference_ratio: 1.0, animation_link_max_vertical_distance: 0.5, }; let sampled = archipelago.sample_point( Vec3::new(10.0, 5.0, 0.0), &sample_dist, )?; println!("Point is on island {:?}", sampled.island()); println!("Terrain type: {}", sampled.type_index()); ``` -------------------------------- ### Pathfinding Workflow: Step 1 - Sample Points Source: https://github.com/andriydev/landmass/blob/main/_autodocs/08-queries-paths.md Samples the start and end points onto the navigation mesh. Ensure the `PointSampleDistance3d` parameters are appropriate for the agent's size and movement capabilities. ```rust use landmass::PointSampleDistance3d; use glam::Vec3; let start_sampled = archipelago.sample_point( Vec3::new(0.0, 0.0, 0.0), &PointSampleDistance3d::from_agent_radius(0.5), )?; let end_sampled = archipelago.sample_point( Vec3::new(10.0, 0.0, 0.0), &PointSampleDistance3d::from_agent_radius(0.5), )?; ``` -------------------------------- ### Create Archipelago Options with FromAgentRadius Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md Example of creating `ArchipelagoOptions` with reasonable defaults for a given agent radius. ```rust let options = ArchipelagoOptions::::from_agent_radius(0.5); // Creates reasonable defaults for a 0.5 unit radius agent ``` -------------------------------- ### Agent3dBundle Spawn Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Spawns an agent in a 3D environment. Requires `Transform`, `Velocity`, `AgentTarget`, `AgentState`, and `AgentDesiredVelocity` components. ```rust commands.spawn(Agent3dBundle { agent: Agent::::default(), settings: AgentSettings { radius: 0.5, desired_speed: 3.0, max_speed: 5.0, }, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), ..default() }); ``` -------------------------------- ### Example: Using IslandMut for Modifications Source: https://github.com/andriydev/landmass/blob/main/_autodocs/05-island.md Shows how to obtain a mutable island reference via get_island_mut and then use its methods like set_transform. ```rust if let Some(mut island) = archipelago.get_island_mut(island_id) { // Can call set_transform(), set_nav_mesh(), get_transform(), get_nav_mesh() island.set_transform(new_transform); } ``` -------------------------------- ### Example: Replacing an Island's Navigation Mesh Source: https://github.com/andriydev/landmass/blob/main/_autodocs/05-island.md Demonstrates how to validate a new navigation mesh and update an existing island with it using set_nav_mesh. ```rust let new_mesh = modified_mesh.validate()?; if let Some(mut island) = archipelago.get_island_mut(island_id) { island.set_nav_mesh(Arc::new(new_mesh)); } ``` -------------------------------- ### Implement Custom CoordinateSystem Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md Example of implementing the `CoordinateSystem` trait for a custom coordinate convention, including conversion functions. ```rust pub struct MyCustomCoords; impl CoordinateSystem for MyCustomCoords { type Coordinate = MyVector; type SampleDistance = MyDistance; const FLIP_POLYGONS: bool = false; fn to_landmass(v: &MyVector) -> Vec3 { // Convert from your format to standard XYZ Vec3::new(v.x, -v.z, v.y) } fn from_landmass(v: &Vec3) -> MyVector { // Convert from standard XYZ back to your format MyVector { x: v.x, y: v.z, z: -v.y, } } } ``` -------------------------------- ### Complete Bevy Landmass Rerecast Setup Source: https://github.com/andriydev/landmass/blob/main/_autodocs/11-rerecast-integration.md Sets up a Bevy application with Landmass and Rerecast plugins, including systems for creating an archipelago, loading a Recast mesh, and spawning an island and agent. ```rust use bevy::prelude::*; use bevy_landmass::prelude::*; use bevy_landmass_rerecast::{LandmassRerecastPlugin, Island3dBundle, NavMeshHandle3d}; use bevy_rerecast::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(Landmass3dPlugin::default()) .add_plugins(LandmassRerecastPlugin::default()) .add_plugins(RerecastPlugin::default()) .add_systems(Startup, setup) .run(); } fn setup( mut commands: Commands, asset_server: Res, ) { // Create archipelago let archipelago = Archipelago3d::new( ArchipelagoOptions::from_agent_radius(0.5) ); let archipelago_entity = commands.spawn(archipelago).id(); // Load Recast mesh from file (example) let rerecast_mesh_handle: Handle = asset_server.load("meshes/arena.nav"); // Add island with Recast mesh (automatic conversion happens) commands.spawn(Island3dBundle { island: Island, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), nav_mesh: NavMeshHandle3d(rerecast_mesh_handle), }); // Add agent commands.spawn(Agent3dBundle { agent: Agent::::default(), settings: AgentSettings { radius: 0.5, desired_speed: 3.0, max_speed: 5.0, }, archipelago_ref: ArchipelagoRef::from_entity(archipelago_entity), ..default() }); } ``` -------------------------------- ### Start Using Animation Link Source: https://github.com/andriydev/landmass/blob/main/_autodocs/02-agent.md Initiates the use of a reached animation link. The agent will enter the 'UsingAnimationLink' state and stop pathfinding until the animation is complete. ```rust pub fn start_animation_link(&mut self) -> Result<(), NotReachedAnimationLinkError> ``` ```rust if agent.reached_animation_link().is_some() { agent.start_animation_link()?; // Play animation... } ``` -------------------------------- ### Custom System Scheduling After Landmass Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Example of how to schedule a custom Bevy system to run after Landmass systems have completed their output phase. This ensures custom logic operates on the latest navigation results. ```rust app.add_systems( FixedPreUpdate, my_custom_system .after(LandmassSystems::Output) .in_set(LandmassSystems::Output) ); ``` -------------------------------- ### XY Coordinate System Agent Creation Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md Example of creating an Agent with the XY coordinate system, specifying a 2D position. ```rust use landmass::{Archipelago, XY}; use glam::Vec2; let mut archipelago = Archipelago::::new(options); let agent = Agent::::create( Vec2::new(5.0, 5.0), // 2D position Vec2::ZERO, 0.5, 3.0, 5.0, ); ``` -------------------------------- ### AgentTarget Update Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Updates the target position for an agent to navigate toward. The target is an `Option`. ```rust fn set_target(mut targets: Query<&mut AgentTarget3d>) { for mut target in targets.iter_mut() { target.0 = Some(Vec3::new(10.0, 0.0, 5.0)); } } ``` -------------------------------- ### Sample Point with f32 Distance Source: https://github.com/andriydev/landmass/blob/main/_autodocs/07-coordinate-systems.md Example of sampling a point in an archipelago using a simple `f32` value for distance. ```rust let sampled = archipelago.sample_point( Vec2::new(5.0, 5.0), &1.0, // Simple f32 distance )?; ``` -------------------------------- ### Agent Using and Ending an Animation Link Source: https://github.com/andriydev/landmass/blob/main/_autodocs/06-animation-link.md Demonstrates the process of an agent starting and ending an animation link. This involves calling agent methods to transition states and updating the agent's position. ```rust agent.start_animation_link()?; // Agent enters UsingAnimationLink state // Play animation for ~1 second // Update agent position to reached_link.end_point // Once animation ends: agent.end_animation_link()?; // Agent resumes pathfinding ``` -------------------------------- ### Get Pathing Results Source: https://github.com/andriydev/landmass/blob/main/_autodocs/01-archipelago-core.md Retrieves the pathfinding results from the most recent `update()` call. This is useful for debugging and performance profiling. ```rust pub fn get_pathing_results(&self) -> &[PathingResult] ``` -------------------------------- ### Pathfinding Workflow: Step 2 - Find Path Source: https://github.com/andriydev/landmass/blob/main/_autodocs/08-queries-paths.md Finds a path between the sampled start and end points. This step uses `PermittedAnimationLinks::All` and an empty HashMap for terrain cost overrides, indicating default costs are used. ```rust use std::collections::HashMap; use landmass::PermittedAnimationLinks; let path = archipelago.find_path( &start_sampled, &end_sampled, &HashMap::new(), // No terrain cost overrides PermittedAnimationLinks::All, )?; ``` -------------------------------- ### Managing Multiple Characters in Archipelago Source: https://github.com/andriydev/landmass/blob/main/_autodocs/03-character.md Example of managing multiple characters within an archipelago, including adding them, updating their positions in a loop, and performing archipelago updates. ```rust use landmass::{Archipelago, Character, XYZ}; use glam::Vec3; use std::collections::HashMap; let mut archipelago = Archipelago::::new(/* options */); let mut characters = HashMap::new(); // Add characters (e.g., NPCs) for i in 0..5 { let character = Character { position: Vec3::new(i as f32 * 2.0, 0.0, 0.0), velocity: Vec3::new(1.0, 0.0, 0.0), radius: 0.5, }; let id = archipelago.add_character(character); characters.insert(i, id); } // Update loop for frame in 0..1000 { // Move characters for (&index, &char_id) in characters.iter() { if let Some(c) = archipelago.get_character_mut(char_id) { c.position.x += c.velocity.x * 0.016; // 60 FPS } } archipelago.update(0.016); // Agents now avoid all characters } ``` -------------------------------- ### Agent Reaching an Animation Link Source: https://github.com/andriydev/landmass/blob/main/_autodocs/06-animation-link.md Shows how to detect when an agent has reached the start edge of an animation link. The game logic should then play the appropriate animation based on the link ID. ```rust if let Some(reached_link) = agent.reached_animation_link() { match reached_link.link_id { jump_link_id => play_jump_animation(), climb_link_id => play_climb_animation(), _ => {} } } ``` -------------------------------- ### NotUsingAnimationLinkError Example Source: https://github.com/andriydev/landmass/blob/main/_autodocs/09-errors.md Illustrates an agent trying to end an animation link without having started one, resulting in NotUsingAnimationLinkError. Call start_animation_link() first. ```rust let agent = archipelago.get_agent_mut(agent_id).unwrap(); agent.end_animation_link()?; ``` -------------------------------- ### Apply AgentDesiredVelocity to Transform Source: https://github.com/andriydev/landmass/blob/main/_autodocs/10-bevy-integration.md Example system demonstrating how to apply the computed agent velocity to an entity's transform. Assumes the entity has both Transform and AgentDesiredVelocity3d components. ```rust fn apply_movement( mut transforms: Query<(&mut Transform, &AgentDesiredVelocity3d)>, ) { for (mut transform, velocity) in transforms.iter_mut() { transform.translation += velocity.0 * 0.016; // Apply velocity } } ``` -------------------------------- ### Get Animation Link Source: https://github.com/andriydev/landmass/blob/main/_autodocs/01-archipelago-core.md Retrieves a reference to an animation link by its identifier. ```rust pub fn get_animation_link(&self, link_id: AnimationLinkId) -> Option<&AnimationLink> ``` -------------------------------- ### Get All Island IDs Source: https://github.com/andriydev/landmass/blob/main/_autodocs/01-archipelago-core.md Returns an iterator over all island identifiers within the archipelago. ```rust pub fn get_island_ids(&self) -> impl ExactSizeIterator + '_ ```