Table of Contents

重叠检测

中级 程序员

重叠检测(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;
}