为啥扫描测试忽略碰撞(阅读编辑)?
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 并忽略其余的碰撞。
【讨论】:
以上是关于为啥扫描测试忽略碰撞(阅读编辑)?的主要内容,如果未能解决你的问题,请参考以下文章