跳到主要内容

detour

简介

寻路和空间推理工具包

重塑导航

组件接口

detour.gs

函数原型函数作用
object load_navigation(string path)加载导航网格

导航数据

函数原型函数作用
share_value get_lock()获取操作锁
map navmesh_info()获取地图信息
object create_query(int max_nodes = 2048)创建查询对象
int add_cylinder_obstacle(Vec3 center, float radius = 1.0, float height = 1.0, bool force_update = false)添加圆柱体障碍物
int add_box_obstacle(Vec3 bounding_min, Vec3 bounding_max, bool force_update = false)添加箱体障碍物
void remove_obstacle(int obstacle_id, bool force_update = false)移除障碍物
bool update(float delta_time)提交障碍物并更新到导航网格

查询对象

@note 内部通过读写锁保证并发安全性。

函数原型函数作用
bool is_walkable(Vec3 pos, map opt_args = nil)判断给定位置是否可行走
array find_straight_path(Vec3 spos, Vec3 epos, map opt_args = nil)获取起始位置到目标位置的路径

样例

void dump_result(Vec3 spos, Vec3 epos, map info, array path)
{
printf("(%6.2f, %6.2f, %6.2f) -> (%6.2f, %6.2f, %6.2f):", spos.x, spos.y, spos.z, epos.x, epos.y, epos.z);
if (info == nil || path == nil)
{
printf(" failed due to either spos or epos is invalid.\n");
}
else
{
if (info.out_of_nodes)
printf(" [out of nodes]");
if (info.buffer_too_small)
printf(" [buffer too small]");
if (info.partial_result)
printf(" [partial result]");
printf(" %d vertices\n", path.length());
for (int i = 0; i < path.length(); ++i)
{
printf(" [%2d] (%6.2f, %6.2f, %6.2f)\n", i, path[i].x, path[i].y, path[i].z);
}
}
}

void naive_sample()
{
// 加载导航数据
object nav = detour.load_navigation("/maps/scene_data.bin");
defer nav.close();

printf("Naive navmesh: %O\n", nav.navmesh_info());

// 创建查询对象(通常,可以为每个玩家绑定一个查询对象,该对象不是线程安全的,不能同时被多个线程访问)
NavMeshQuery query = nav.create_query();
defer query.close();

map info = nil;
array path = nil;

Vec3 spos = Vec3(647.595703, 0.00000000, 432.997498);
Vec3 epos = Vec3(520.134644, 0.00000000, 700.356812);

// 寻路,返回路径和相关信息
let info, path = query.find_straight_path(spos, epos);
dump_result(spos, epos, info, path);


spos = Vec3(523.156128, 0.00000000, 521.997314);
epos = Vec3(520.134644, 0.00000000, 700.356812);

// 寻路(由于存在阻挡,两个点不可达)
let info, path = query.find_straight_path(spos, epos);
dump_result(spos, epos, info, path);

// 寻路,通过walkable_bits忽略特定的阻挡类型,这意味着可以通过相应的地块
let info, path = query.find_straight_path(spos, epos, {
"walkable_bits": 0x0001
});
dump_result(spos, epos, info, path);
}

void obstacle_sample()
{
// 加载导航数据,该网格支持动态障碍物(导航对象内部通过读写锁确保并发安全性)
object nav = detour.load_navigation("/maps/scene_data.obstacle.bin");
defer nav.close();

printf("Obstacle navmesh: %O\n", nav.navmesh_info());

// 创建查询对象(通常,可以为每个玩家绑定一个查询对象,该对象不是线程安全的,不能同时被多个线程访问)
NavMeshQuery query = nav.create_query();
defer query.close();

map info = nil;
array path = nil;

Vec3 spos = Vec3(694.590820, 0.00000000, 577.246033);
Vec3 epos = Vec3(574.161011, 0.00000000, 708.750977);

// 在原始网格上寻路
let info, path = query.find_straight_path(spos, epos);
dump_result(spos, epos, info, path);

// 在路径上添加障碍物
int obstacle_id = nav.add_cylinder_obstacle(Vec3(575.5, -0.5, 705.1), 1.0, 2.0);

// 调用update提交障碍物更新操作(可以创建一个协程来提交修改)
while (!nav.update(0.0))
;

// 添加障碍物后再次寻路,可以看到路径变化
let info, path = query.find_straight_path(spos, epos);
dump_result(spos, epos, info, path);

// 移除障碍物(这里force_update设置为true以立即提交修改)
nav.remove_obstacle(obstacle_id, true);

// 再次寻路,与原始网格寻路结果相同
let info, path = query.find_straight_path(spos, epos);
dump_result(spos, epos, info, path);
}

void main()
{
naive_sample();
obstacle_sample();
}