Unity Rigidbody.SweepTestAll()偶尔不检测碰撞器

问题描述 投票:0回答:1

这将是一篇很长的文章,所以请多多包涵。我很久以前第一次遇到这个问题。那时我发表了一篇关于它的文章,但无法解决。从那以后,我已经收集了更多的细节,希望这次我能有所进步。

我的游戏没有使用内置的物理系统,而是角色在给定方向执行SweepTest,然后使用transform.position + = moveVector;更新其位置。这使我可以使它们与网格空间很好地对齐,这对于我的益智游戏是必需的。有时,在玩游戏时,角色会掉到一块地板上。其他角色或对象可以在同一块地板上移动而没有任何问题,这似乎只是两个对象之间的特殊关系,似乎是随机选择的。它并不总是影响相同的角色,也不总是影响相同的地板。角色从哪个方向接近地板或相对于地板的放置位置都无关紧要。由于给定的地板(或墙壁或其他物体)的数量以及角色,我在蓝色的月亮中偶然跌倒了一次。碰巧之间可能要花费几个月的时间(我花了大量时间在开发上,但没有很多时间在玩)。通过菜单在应用程序中启动新游戏,重新启动应用程序(如果是内置版本)或退出播放模式(如果在编辑器中)都无法以相同方式重现该问题。同样,它似乎是随机发生的。

这意味着如果要进行调试,我需要在当前执行之前对所有代码进行编码,因为编辑任何脚本都会导致它们重新编译并在当前会话中导致错误。

我的游戏通过添加场景加载多个拼图室来构建拼图地图。我不知道这是否可能是一个因素,但是无论如何我都会提到它。

我的角色的缩放比例为(100,200,100),移动速度为20。他的框Collider的缩放比例设置为(0.99,0.99,0.99)。他还具有运动学Rigidbody。地板的顶部高度为0,其框Collider的等价比例为(1、1、1)。角色通常位于100的位置,其原点位于他的中心。这意味着他的底部应该始终比地板高1左右,这意味着他的底部永远不能与地板完美对齐,以防止浮点误差重叠。这也意味着SweepTest的幅度向下为20,应该可以毫无问题地拾起地板。

字符检查器:https://i.imgur.com/c4detlv.png楼层检查员:https://i.imgur.com/fQFotn7.png

使用一些调试,我记录了每个向下的结果SweepTest,这是代码和结果。

RaycastHit[] hitThings = GetComponent<Rigidbody>().SweepTestAll(moveVector, moveVector.magnitude, QueryTriggerInteraction.Ignore);
Debug.Log(gameObject.transform.position);
Debug.Log(moveVector);
Debug.Log(moveVector.magnitude);
Debug.Log(hitThings.Length);
foreach (RaycastHit hitThing in hitThings) {
    Debug.Log(hitThing.collider.name);
    Debug.Log(hitThing.collider.tag);
    Debug.Log(hitThing.collider.transform.parent.name);
    Debug.Log(hitThing.collider.transform.root.name);
    Debug.Log(hitThing.distance);
    Debug.Log(hitThing.collider.transform.position);
}
Debug.Log("--------");

(-2370.0, 100.0, -4050.0)
(0.0, -20.0, 0.0)
20
1
Piston
Piston
WalkwayExtendedEast
Tier1Room-
1.252515
(-2450.0, -50.0, -4000.0)
--------
(-2350.0, 100.0, -4050.0)
(0.0, -20.0, 0.0)
20
0
--------
(-2350.0, 80.0, -4050.0)
(0.0, -20.0, 0.0)
20
0
--------
(-2350.0, 60.0, -4050.0)
(0.0, -20.0, 0.0)
20
0
--------
(-2350.0, 40.0, -4050.0)
(0.0, -20.0, 0.0)
20
0
--------
(-2350.0, 20.0, -4050.0)
(0.0, -20.0, 0.0)
20
0
--------

角色从坚固的东西开始。一旦他向右移动20,他现在仅在相关楼层上。如您所见,SweepTest确实检测到任何命中。

在单独的调试中,我对角色进行了Physics.OverlapBox()测试,以确定角色是否开始在所涉及的地板内。这是这些结果。

Debug.Log(trasform.position);
Debug.Log(transform.scale * 0.99f);
Collider[] overlapping = Physics.OverlapBox(gameObject.transform.position, transform.scale * 0.99f / 2f);
foreach (Collider currentCollider in overlapping) {
    if (currentCollider.tag != "Character") {
        Debug.Log(currentCollider.tag);
        Debug.Log(currentCollider.transform.position);
        Debug.Log(currentCollider.transform.root.position);

    }
}
Debug.Log("--------")

(-2370.0, 100.0, -4050.0)
(99.0, 198.0, 99.0)
--------
(-2350.0, 100.0, -4050.0)
(99.0, 198.0, 99.0)
--------
(-2350.0, 80.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, 60.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, 40.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, 20.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, 0.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -20.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -40.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -60.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -80.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -100.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -120.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -140.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -160.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -180.0, -4050.0)
(99.0, 198.0, 99.0)
Fixture
(-2250.0, -75.0, -4000.0)
(-4000.0, 0.0, -4000.0)
--------
(-2350.0, -200.0, -4050.0)
(99.0, 198.0, 99.0)
--------
(-2350.0, -220.0, -4050.0)
(99.0, 198.0, 99.0)
--------

这些结果表明,在开始跌落之前,角色不会与地板重叠。

我的角色是运动学的。使它不运动并启用重力将导致角色停在有问题的地板上。结合Physics.OverlapBox()结果,结果表明物理系统正在检测地面,而不是SweepTest

我试图稍微上下移动地板,但角色仍然通过。我尝试将地板移动到胸部高度,以便角色可以从另一个角度接近地板。角色仍然可以在对象中移动,但其他对象或角色则不能。

通过对象的字符:https://imgur.com/VwbUfUx

我复制并粘贴了地板。我的角色无法逐步通过这个新对象,调试也显示了这一点。即使复制的对象具有完全相同的属性和值,现在也可以通过SweepTest。]检测到冲突。

在地板上添加另一个盒子Collider

也防止了我的角色掉进去。在我的角色中添加另一个框Collider也是如此。我认为这些Colliders的这两个特定实例有问题,添加新的[[Collider或复制对象正在创建新的Collider组件实例,并且新实例可能具有相同的出现这种故障的机会是“一旦出现在蓝月亮中。”>[最后,我尝试重置有问题的地板上的每个组件和我的角色。这没有产生任何结果,角色仍然能够通过它。

尽管这种情况很少发生,但这可能会在游戏中引起很大的问题。具有受影响角色的玩家可能被迫重新开始游戏。无法越过地板的某些区域会使许多游戏无法完成。如果没有每个玩家在场,其他玩家将无法完成游戏,因此他们也会被打断。

在我看来这是Unity的问题,而不是我的代码。如果有人在这些论坛上认识Unity员工,可以请他们标记该员工吗?我认为这对缩小这个问题有很大帮助。

我的理论:尽管我只是在一个角色和另一个对象之间经历了此问题,但我可能会猜测,在任何两个对象之间都可能发生此问题。看到我每两个月才发生一次,并且看到我的角色是最经常与其他对象接触的对象,因此我怀疑自己是否有可能经历过这种情况。这个问题似乎将两个

Colliders

实例链接在一起,并且我认为任何两个Colliders都有这种关系的可能性很小。Unity 2018.4.9f1个人LTS。物理设置:https://imgur.com/pKI7Q07

这将是一篇很长的文章,所以请多多包涵。我很久以前第一次遇到这个问题。那时我发表了一篇关于它的文章,但无法解决。此后,我收集了更多...

unity3d physics
1个回答
0
投票
老实说,我读起来就像前两段;但我可能知道答案,因为存在类似的问题,也根本没有使用Unity物理。您说过,并非总是使用SweepTestAll检测到冲突。这可能是由于float的精度不足,有时有时会检测到碰撞有些错误。由于该对象现在位于对撞机的顶部,因此该对象的移动比预期的要稍微多一点,sweepTest的下一帧不会在相同方向上检测到碰撞。您说它是在地板上发生的,这让我觉得您一直在移动。解决方案很简单,就是向后移动播放器,然后增加SweepTest长度(我正在做一个简单的扫描测试)。

if (movement != Vector3.zero) { float maxDistance = movement.magnitude; //this because magnitude * (offset / magnitud) = magnitude´s offset for behindVector (in this case 0.003 which I thought was a safe number) Vector3 behindVector = movement * (0.003f / maxDistance);//keeps movement´s direction. Since magnitude is always positive, behindVector keeps movement´s sign. transform.position -= behindVector; maxDistance += 0.003f;//movement.magnitude + behindVector.magnitude RaycastHit hit; if (rb.SweepTest(movement, out hit, maxDistance)) { if (hit.collider)//movement will become the vector of hit.distance { movement = movement / movement.magnitude * hit.distance; } } }

© www.soinside.com 2019 - 2024. All rights reserved.