| Crates.io | landmass |
| lib.rs | landmass |
| version | 0.8.0 |
| created_at | 2023-06-22 03:36:03.041983+00 |
| updated_at | 2025-04-25 06:39:26.760169+00 |
| description | A navigation system for video game characters to walk around levels. |
| homepage | |
| repository | https://github.com/andriyDev/landmass |
| max_upload_size | |
| id | 896865 |
| size | 374,331 |
A Rust crate to provide a navigation system for video game characters to walk around levels.
A navigation system is essentially the collection of tools needed for robust agent movement in video games. This generally involves 4 things:
In addition, managing agents and the navigation meshes they walk on can be cumbersome, so a navigation system ideally will handle that for you.
Generally it is difficult to find a full, free system to handle all of these for
you, and the goal is for landmass to work relatively easily with other
languages so it can be used anywhere.
landmass has four major components: Archipelagos, Islands, Agents, and
Characters. An Archipelago is composed of several Islands, as well as the
Agents and Characters that travel across those Islands. Each Island
holds a single navigation mesh.
Each game character (controlled by AI) should correspond to one Agent. Player
characters or other characters not controlled by AI should correspond to one
Character. To start using landmass:
Archipelago.Island.Agents and Characters to the Archipelago.Each frame of the game:
Agent or Character.update on the Archipelago.Agent to inform the corresponding game
character where it should move.Note: landmass intentionally does not update the Agents position itself.
Generally, characters are moved using some other method (like a physics
simulation) rather than just moving the character, so moving the Agent would
be confusing.
use glam::Vec3;
use landmass::*;
use std::{sync::Arc, collections::HashMap};
let mut archipelago =
Archipelago::<XYZ>::new(AgentOptions::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],
};
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,
HashMap::new(),
));
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..200 {
let delta_time = 1.0 / 10.0;
archipelago.update(delta_time);
for agent_id in archipelago.get_agent_ids().collect::<Vec<_>>() {
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));
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.