载入中...
搜索中...
未找到
空间索引模块
空间索引模块
脚本入口: eve.Spatial()
提供四叉树、八叉树、空间哈希与空间二分树(及其二维/三维版本),用于快速判断元素是否落在视口、拾取区或邻近范围内。
基本用法
local spatial = eve.Spatial();
local tree = spatial.newQuadTree(0, 0, 2048, 2048);
tree.insert(1, 100, 100, 132, 132); // id + AABB
tree.insert(2, 400, 200, 432, 232);
local n = tree.queryRect(90, 90, 200, 200);
for (local i = 0; i < tree.getResultCount(); i++) {
local id = tree.getResultId(i);
// 用 id 查自己的实体 / 地图对象
}
对象关系与调用时机
Spatial 只做工厂;真正持有数据的是 QuadTree / Octree / SpatialHash2D / SpatialHash3D / BSPTree2D / BSPTree3D。
索引里只存整数 id 与包围盒,不拥有实体。物体移动时调用 update;销毁时 remove。查询结果写在该索引对象内部,下一次 query* 会覆盖。
目标导向指南
地图视口裁剪
用地图世界范围创建 QuadTree 或 SpatialHash2D,把可交互对象 / 装饰物 id 与 AABB 插入;每帧用相机可见矩形 queryRect,只更新或绘制命中 id。
3D 场景邻近查询
用场景包围盒创建 Octree 或 SpatialHash3D;用 querySphere 找玩家附近可交互体,再做精确逻辑。
结构怎么选
- 物体大小接近、移动多:优先
SpatialHash2D/SpatialHash3D(调好cellSize) - 大地图静态或半静态:
QuadTree/Octree - 需要沿轴二分剪枝:
BSPTree2D/BSPTree3D
常见问题
- 把
procgen的dungeon.bsp当成空间查询树——那是地牢生成,不是本模块。 - 忘记在物体移动后
update,导致查询仍命中旧位置。 getResultId在新的query*之后仍使用旧循环变量——结果缓冲已被覆盖。- 根包围盒过小:树/BSP 构造时给出的世界范围应覆盖所有可能插入的 AABB。
API 快查
- 模块:
getName()、newQuadTree()、newOctree()、newSpatialHash2D()、newSpatialHash3D()、newBSPTree2D()、newBSPTree3D() - 共用:
clear()、insert()、remove()、update()、contains()、getCount()、getResultCount()、getResultId() - 2D 查询:
queryPoint()、queryRect()、queryCircle() - 3D 查询:
queryPoint()、queryAABB()、querySphere() - 树/BSP:
getMinX/Y[/Z]、getMaxX/Y[/Z]、getMaxDepth()、getMaxPerNode() - 哈希:
setCellSize()、getCellSize()
使用要点
- 模块对象和索引对象应保存在全局或实体状态中,不要每帧重建整棵树(除非批量替换世界)。
id由脚本自定义,保持稳定即可;不要假设与 ECS 实体句柄自动同步。- 参数约束与默认值以头文件及
addFunc绑定为准。
源码: src/modules/spatial/
设计文档: `docs/dev/空间索引模块设计.md`
相关测试: test/spatial.cpp