10 个版本 (5 个破坏性更新)
0.6.0 | 2024年7月23日 |
---|---|
0.5.0 | 2024年7月6日 |
0.4.0 | 2024年2月18日 |
0.3.3 | 2024年1月13日 |
0.1.1 | 2023年6月22日 |
#79 in 游戏开发
每月222次下载
在 2 个工具箱中使用(通过 bevy_landmass)
335KB
9K SLoC
landmass
一个Rust工具箱,提供视频游戏角色在关卡中行走的导航系统。
什么是导航系统?
导航系统基本上是一系列用于视频游戏中强大代理移动的工具。这通常包括4个方面
- 路径查找(例如 A*)
- 路径简化(例如 SSFA)
- 转向(例如鸟群算法)
- 局部碰撞避免
此外,管理代理和他们行走的导航网格可能很麻烦,因此导航系统最好为您处理这些。
通常很难找到一个完整的、免费的系统来处理所有这些,目标是让 landmass
能够与其他语言相对容易地工作,以便在各个地方使用。
概述
landmass
有四个主要组件:Archipelago
、Island
、Agent
和 Character
。一个 Archipelago
由几个 Island
组成,以及在这些 Island
上旅行的 Agent
和 Character
。每个 Island
包含一个单独的 导航网格。每个游戏角色(由AI控制)应对应一个 Agent
。玩家角色或其他非AI控制的角色应对应一个 Character
。要开始使用 landmass
- 创建一个
Archipelago
。 - 创建一个
Island
。 - 将
Agent
和Character
添加到Archipelago
。
游戏的每一帧
- 将每个游戏角色的位置和速度设置为相应的
Agent
或Character
。 - 在
Archipelago
上调用update
。 - 使用每个
Agent
的期望移动来通知相应的游戏角色它应该移动到哪里。
注意:landmass
有意不更新 Agent
的位置。通常,角色是通过其他方法(如物理模拟)移动,而不是仅仅移动角色,因此移动 Agent
会让人困惑。
示例
use glam::Vec3;
use landmass::*;
use std::{sync::Arc, collections::HashMap};
let mut archipelago = Archipelago::<XYZ>::new();
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));
许可证
以下任一许可证下
- Apache License, Version 2.0 (LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
供您选择。
贡献
除非您明确声明,否则任何您有意提交以包含在作品中的贡献(根据 Apache-2.0 许可证定义),均应按上述方式双许可,无需任何附加条款或条件。
依赖项
约 11MB
约 228K SLoC