重叠检测
中级 程序员
重叠检测(Overlap) 检查某个形状边界内的相交碰撞。更通俗地说,它检查哪些碰撞体位于形状内部或部分位于形状内部。
重叠检测查询
要查询重叠,请使用 Simulation.Overlap。
形状
重叠检测需要一个形状,它可以是以下之一:Box、Capsule、ConvexHull、Sphere、Triangle。
姿态
姿态(pose) 描述了形状在世界中的位置方式。
创建 RigidPose 的新实例需要两个参数:位置和旋转。
如果你想使用场景中某个实体的位置和旋转,可以使用 Transform.GetWorldTransform。
Entity.Transform.GetWorldTransformation(out var position, out var rotation, out _);
var pose = new RigidPose(position, rotation);
集合
集合(collection) 用于从重叠检测中获取相交的可碰撞体。
你可以使用的最基本集合是列表。
var collection = new List<OverlapInfo>();
重叠检测查询(使用 stackalloc)
在重复执行重叠检测时,它必须不断为结果在堆上分配内存,这会给垃圾回收器(GC)带来更大压力(意味着更多的内存占用)。更优的解决方案是使用 stackalloc。
使用栈时,该方法将不再需要集合,而是返回一个可枚举对象。
public void Overlap()
{
// 分配一个最多可容纳 16 个元素的缓冲区
Span<CollidableStack> buffer = stackalloc CollidableStack[16];
// 遍历所有结果
foreach (var collidable in simulation.Overlap(shape, pose, buffer))
{
// 处理成功命中
}
}
Note
span 能容纳的元素数量是有限的。如果命中数量超过缓冲区大小,则只会返回最近的那些命中。
OverlapInfo 查询
此查询的工作方式与其他查询几乎相同。主要区别在于它将复合碰撞体的每个形状分开处理。这可能导致同一个可碰撞体被返回多次。
public void Overlap()
{
// 分配一个最多可容纳 16 个元素的缓冲区
Span<CollidableStack> buffer = stackalloc CollidableStack[16];
// 遍历所有结果
foreach (var info in simulation.OverlapInfo(shape, pose, buffer))
{
// 处理成功命中
}
}
使用碰撞层遮罩
每个查询都有一个可选参数,用于指定应在哪些碰撞层上执行该查询。
有关如何使用碰撞层遮罩的更多信息,请访问物理查询主页。
示例
以下是游戏中使用重叠检测的几个示例。
检查玩家是否在地面上
此示例将在玩家下方稍低处使用球体重叠检测,检查它是否接触地面。
我们假设玩家使用高度为 2 的胶囊体进行碰撞。因此,重叠检测需要从中心偏移 -0.5,以便将胶囊体的底部与球体完美匹配,然后再额外偏移一个小值 -0.01,以便能够检测地面。
public bool CheckGrounded(BodyComponent body)
{
var sim = body.Simulation;
// 球体的半径需要与胶囊体的半径匹配
var shape = new Sphere(0.5f);
var pose = new RigidPose(Entity.Transform.WorldMatrix.TranslationVector - 0.51f, Vector3.Zero);
// 检查除玩家所在层之外的所有层
var mask = ~body.CollisionLayer.ToMask();
Span<CollidableStack> buffer = stackalloc CollidableStack[1];
// 如果玩家下方有任何碰撞,玩家就在地面上
foreach (var item in sim.Overlap(sphere, pose, buffer, mask))
return true;
return false;
}