刚体接触但 OnCollisionStay 停止被调用 (Unity3D)

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

我想模拟两个活塞来复制天平的行为。我使用弹簧接头执行此操作,并在调用 OnCollisionStay 时相互应用反向权重。这是我的活塞及其刚体和关节。两者完全相同。

two pistons

这是我的 SpringForceTransmisor.cs 代码: 使用UnityEngine;

public Rigidbody InverseJoint;

private void OnCollisionEnter(Collision collision) {
    Debug.Log("Enter");
}

private void OnCollisionExit(Collision collision) {
    Debug.Log("Exit");
}

private void OnCollisionStay(Collision collision) {
    InverseJoint.AddForce(-(collision.rigidbody.mass * Physics.gravity));
    Debug.Log("Stay");
}

并且这是正在发生的事情的视频

因此,根据视频中显示的日志,即使 OnCollisionExit() 从未被调用过,OnCollisionStay() 也会停止被调用。这怎么可能?我一直认为 OnCollisionStay() 会在 OnCollisionEnter 帧和 OnCollisionExit 帧的每一帧中被调用。

任何人都可以解释一下这里发生了什么吗?

c# unity-game-engine collision-detection collision rigid-bodies
5个回答
2
投票

根据

OnCollisionStay
的文档,它说:

每个碰撞体/刚体每帧调用一次 OnCollisionStay 正在接触刚体/碰撞体。

不幸的是,有时这是真的。在某些情况下,

OnCollisionStay
函数会被调用几次,然后调用就会停止。 这要么是一个多年未修复的长期错误,要么是文档错误。

我通常对人们的建议是放弃

OnCollisionStay
函数,只需在
OnCollisionEnter
函数中将布尔变量设置为 true,然后在
OnCollisionExit
函数中将其设置为 false。然后,您可以通过检查
Update
函数中的布尔变量,将
OnCollisionStay
函数用作
Update
函数。

public Rigidbody InverseJoint;

bool collisionStay = false;
Collision collision = null;

private void OnCollisionEnter(Collision collision)
{
    Debug.Log("Enter");
    collisionStay = true;
    this.collision = collision;
}

private void OnCollisionExit(Collision collision)
{
    Debug.Log("Exit");
    collisionStay = false;
    this.collision = collision;
}

void Update()
{
    if (collisionStay)
    {
        InverseJoint.AddForce(-(collision.rigidbody.mass * Physics.gravity));
        Debug.Log("Stay");
    }
}

0
投票

如果您在视频中包含注册“Enter”的部分,您的问题的答案就会变得显而易见。

现在为了解释正在发生的事情,让我展示一个训练球体上的示例。这是它的样子(一些三角形故意不可见)。

(primitive sphere mesh in unity)

请记住,它是空心的,它本质上就是一堆形成三角形的点。现在说这是某个网格碰撞器组件的网格。如果任何其他碰撞体与此 sphere_mesh_collider 交互,unity 检测它的唯一方法是检查这两个碰撞体的三角形是否有相交。这就是说,不会检查三角形内未覆盖的任何其他区域。换句话说,我的球体的体积永远不会检测到碰撞(也不会调用碰撞停留,但对撞机也没有退出,所以它也不会调用退出)。

这就是我认为在你的情况下发生的情况,尽管我不能肯定地说,因为我没有看到碰撞器开始相互作用(进入)然后分开(退出)的整个过程。

编辑:如果您在编辑器窗口中启用统一线框(或着色线框),您可以轻松观察到这一点。


0
投票

来自 Unity 文档的另一条注释:

注意: [...] 不会为休眠的刚体发送碰撞停留事件。

您可以尝试将

Rigidbody.SleepThreshold
设置为零,看看是否可以解决您的问题。


0
投票

我自己刚刚解决了这个问题。这是因为你的刚体正在睡眠,尝试将刚体睡眠设置为“从不睡眠”,它会起作用。


0
投票

就我而言,我遇到的问题是我正在使用碰撞保持来检查物体是否接地。当物体移动时它工作得很好,但是一旦它停下来,刚体就会进入睡眠状态并停止调用碰撞保持。

我的简单高性能解决方案(而不是阻止刚体休眠)是检查 rigindody.IsSleeping() ,如果为 true,则将 Grounded 设置为 True,因为如果对象正在休眠,那么它就不会掉落。

类似的替代选项可以是在调用 OnCollisionStay 时缓存碰撞对象的相对位置,如果 CollisionStay 停止被调用但相对位置没有改变,则假设碰撞仍然处于活动状态。

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