| Crates.io | landmass_rerecast |
| lib.rs | landmass_rerecast |
| version | 0.1.0 |
| created_at | 2025-10-03 03:24:33.38765+00 |
| updated_at | 2025-10-03 03:24:33.38765+00 |
| description | An integration to allow use of rerecast navigation meshes in landmass. |
| homepage | |
| repository | https://github.com/andriyDev/landmass |
| max_upload_size | |
| id | 1866040 |
| size | 840,255 |
A plugin for Bevy to help using bevy_landmass and bevy_rerecast together.
landmass_rerecast allows you to use bevy_rerecast::Navmesh as the
navigation mesh in a landmass island! To use it:
bevy_landmass and bevy_rerecast up as normal.LandmassRerecastPlugin to your app.bevy_landmass::Island3dBundle,
bevy_landmass::NavMeshHandle3d, and bevy_landmass::NavMeshHandle, with
landmass_rerecast::Island3dBundle, landmass_rerecast::NavMeshHandle3d, and
landmass_rerecast::NavMeshHandle, respectively.
bevy_landmass prelude, you can just import these symbols manually.bevy_rerecast::Navmesh handles in your
landmass_rerecast::NavMeshHandle3ds!use bevy::prelude::*;
use bevy_landmass::{Agent, PointSampleDistance3d, prelude::*};
use bevy_rerecast::{Mesh3dBackendPlugin, prelude::*};
use landmass_rerecast::LandmassRerecastPlugin;
use landmass_rerecast::{Island3dBundle, NavMeshHandle3d};
fn main() {
App::new()
.add_plugins((
MinimalPlugins,
AssetPlugin::default(),
TransformPlugin,
NavmeshPlugins::default(),
Mesh3dBackendPlugin::default(),
Landmass3dPlugin::default(),
LandmassRerecastPlugin::default(),
))
.init_asset::<Mesh>()
.init_asset::<StandardMaterial>()
.add_systems(Startup, setup)
.add_systems(
Update,
check_for_path_and_exit.run_if(resource_exists::<CheckCounter>),
)
.add_observer(check_after_navmesh_ready)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
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(_: Trigger<NavmeshReady>, 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<CheckCounter>,
mut exit: EventWriter<AppExit>,
) {
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:?}");
}
}
License under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.