为啥扫描测试忽略碰撞(阅读编辑)?

Posted

技术标签:

【中文标题】为啥扫描测试忽略碰撞(阅读编辑)?【英文标题】:Why are sweeptests ignoring collisions (read the edit)?为什么扫描测试忽略碰撞(阅读编辑)? 【发布时间】:2020-04-12 16:05:45 【问题描述】:

我有一个根据键箭头移动的对象,例如角色控制器。每次移动的Update() 都会抛出一次扫描测试,但如果你一直按下按钮,它就会通过。顺便说一句,我没有使用 Unity 物理,所以任何暗示使用 OnCollision() voids 的解决方案都不起作用

void Update()

    float horizontal = Input.GetAxisRaw("Horizontal") * moveSpeed; 
    velocity.x = horizontal;//y axis adds gravity, but is omitted here to focus on the relevant

    Vector3 movement = velocity * Time.deltaTime;

    if (movement != Vector3.zero)
    
        RaycastHit hit;
        if (rb.SweepTest(movement, out hit, movement.magnitude))
        
            if (hit.collider)
            
                Vector3 moveToColl = movement / movement.magnitude * hit.distance;//gives hit.distance vector                 
                transform.position += moveToColl;

                movement = Vector3.zero;//because movement has already been done.
                velocity = movement;
            
        
    

    this.transform.Translate(movement, Space.World);

因为我认为问题是游戏对象与对撞机重叠,所以我尝试在进行扫描测试之前将游戏对象移动到后面(因为扫描测试,出于某种原因,不允许使用图层蒙版),然后增加它的长度以保持同样的碰撞。

Vector3 behindVector = movement / 100;

transform.position -= behindVector;
float maxDistance = movement.magnitude;
maxDistance += maxDistance / 100;// same as movement.magnitude + behindVector.magnitude

// 相同,但是 maxDistance 替换了扫描测试长度中的 motion.magnitude。 虽然这显着减少了问题,但仍然存在物体会穿过墙壁的框架,特别是如果距离很近或在改变方向和跳跃之后(对不起:我不太确定。我试图弄清楚什么是它,但我并没有真正明白。如果您靠近墙壁并尝试通过,然后向相反方向移动并重试,似乎更常见,特别是如果velocity.y也被修改,这使得我认为这与向量的大小有关)。 我尝试的另一个解决方案是:

if (hit.collider)

   Vector3 moveToColl = movement / movement.magnitude * hit.distance;//gives hit.distance vector
   moveToColl *= 0.9f;
   float minimum = 0.001f;
   if (moveToColl.magnitude > minimum)
   
       transform.position += moveToColl;
   
   movement = Vector3.zero;//these two are kept outside
   velocity = movement;

因此,将对象移动得比预期的要小可以防止重叠,但是如果 0.9f 更大,例如 0.999f,则碰撞基本上再次为零。如果我们改用 0.6f,它几乎可以完美运行,但这有两个问题。首先,我什至不完全确定我是否摆脱了这个问题,看起来就是这样。其次,这种移动是错误的,如果浮动更小(这同样可以改善碰撞),那么两个对象之间的差距会更加明显,即使不是那么大。 我什至同时尝试了这两种方法,但它给了我一个奇怪的物体振动,因为这两行修改了它的位置:transform.position -= behindVector;// 和 transform.position += moveToColl;

编辑:由于问题是由于浮动缺乏精度和碰撞器重叠引起的,我想到了另一种解决方案,但我需要最后一部分的帮助。 它是关于从 moveToColl 向量中减去 Vector3 偏移量。首先,我们假设 X 轴为 0.1f(方向需要与 moveToColl.x 方向相反,所以如果为负,则为正)并使用此公式得到 Y 值:0.1f * moveToColl.y / moveToColl.x。所以我们以 Vector3 结束(0.1f,Y 值,weIgnoreZAxisInThisExample)。我们从 moveToColl 向量中减去它,我们得到一个保持相同方向的新向量,但不会在 X 和 Y 中移动那些额外的 0.1f 以保持该方向。如果我们想要另一个轴,公式是相同的,但我们反转所有轴。第一个例子适用于墙壁。因为无论 y 速度如何,它都减去 0.1f(假设该值足够)。扫描测试在跳跃时更频繁地错过碰撞的原因是 y 的变化减少了 x 偏移(因为我们将向量乘以 0.9f,所以 0.1f 减去了方向而不是 x 轴。现在是持续的)。但这仅适用于完美的垂直或水平线。如果是斜率,则偏移量错误。我发现偏移量需要垂直于表面,因为最近的距离总是垂直的。靠墙效果很好,因为 x 轴是垂直的,所以它就像直接减去偏移量并保持方向一样简单。但现在不是轴对齐的。 enter image description here

对不起,偏移量是-0.1,0.1。我忘记放置 - 并且它走向相反的方向。例如,该公式将给出紫色向量来获得偏移量(我知道我真的绘制了 x 和 y 偏移量,因为我真的想要那些)。正确的向量将从命中开始。指向和结束绿线和黑线相交的地方(这就是我要寻找的)。绿色偏移量内部还有一个橙色点,这是错误的,因为它与蓝线之间的距离明显小于预期的距离;因此,如果公式给出了这一点,那就太糟糕了(尽管我不完全确定这是否可能,所以如果你知道,请告诉我)。无论如何,距离越大,越容易看出没有碰撞。这就是为什么我想要尽可能近的距离。顺便说一句,0.1f 只是一个例子。有谁知道您可以安全检测到碰撞的最近距离是多少?

【问题讨论】:

使用 Unity Physics 会更好......话虽如此......你的对撞机是什么样的?你用的是什么类型的对撞机? 此外,当测试开始于已经“碰撞”的对象时,SweepTest 往往会失败......结合“浮动”舍入问题和计算问题......这意味着有时你的sweeptest 将从一个已经在碰撞盒内的对象开始,即使是很小的一部分....所以这会使 SeepTest 失败....所以你不能仅仅依赖 SweepTest 【参考方案1】:

尽管这可能不是对 OP 问题的确切答案,但它可能对那些在 Google 中搜索到这里的人有用。

这是一个难以调试的问题。但在某些情况下,这可能是由 SweepTest 的已知问题引起的。

当扫描测试开始于一个已经“碰撞”的对象时......意味着它从已经在碰撞器内部的对象开始,即使它只是一小部分,那么扫描测试将失败。

将其与“浮动”类型的精度问题结合起来,您的游戏中就会出现完美的错误。

这是一个可能有助于理解问题的讨论:SweepTest issue

使用ComputePenetration、ClosestPoint 或两者的组合可以解决或缓解问题。

可以通过更改刚体上的CollisionDetectionMode 来解决其他碰撞问题。

另一个想法(不确定这是否会有所帮助)是尝试在您的碰撞对象中设置 EdgeRadius ???值得一试。

【讨论】:

【参考方案2】:

实际上,我第一个向后移动对象的解决方案很好,但最好是这样:

void Update()

    if (movement != Vector3.zero)
    
        float maxDistance = movement.magnitude;
        Vector3 behindVector = movement * (0.003f / maxDistance);
        transform.position -= behindVector;
        maxDistance += 0.003f;//movement.magnitude + behindVector.magnitude
        //then do the sweepTest
    

但是,现在我发现在某些情况下我需要更多地增加 0.003f 偏移量。为了防止与玩家身后的物体发生碰撞,您需要检查 hit.distance 是否 > offset 并忽略其余的碰撞。

【讨论】:

以上是关于为啥扫描测试忽略碰撞(阅读编辑)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的碰撞测试总是返回“真”,为啥图像矩形的位置总是错误的 (0, 0)?

使用深度学习阅读和分类扫描文档

如何设置 SceneKit 碰撞检测

为啥PDF文件打开不能显示正常内容?

pdf文件可以用什么编辑

php swoole 和 websocket的初次碰撞