我想模拟两个活塞来复制天平的行为。我使用弹簧接头执行此操作,并在调用 OnCollisionStay 时相互应用反向权重。这是我的活塞及其刚体和关节。两者完全相同。
这是我的 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 帧的每一帧中被调用。
任何人都可以解释一下这里发生了什么吗?
根据
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");
}
}
如果您在视频中包含注册“Enter”的部分,您的问题的答案就会变得显而易见。
现在为了解释正在发生的事情,让我展示一个训练球体上的示例。这是它的样子(一些三角形故意不可见)。
请记住,它是空心的,它本质上就是一堆形成三角形的点。现在说这是某个网格碰撞器组件的网格。如果任何其他碰撞体与此 sphere_mesh_collider 交互,unity 检测它的唯一方法是检查这两个碰撞体的三角形是否有相交。这就是说,不会检查三角形内未覆盖的任何其他区域。换句话说,我的球体的体积永远不会检测到碰撞(也不会调用碰撞停留,但对撞机也没有退出,所以它也不会调用退出)。
这就是我认为在你的情况下发生的情况,尽管我不能肯定地说,因为我没有看到碰撞器开始相互作用(进入)然后分开(退出)的整个过程。
编辑:如果您在编辑器窗口中启用统一线框(或着色线框),您可以轻松观察到这一点。
我自己刚刚解决了这个问题。这是因为你的刚体正在睡眠,尝试将刚体睡眠设置为“从不睡眠”,它会起作用。
就我而言,我遇到的问题是我正在使用碰撞保持来检查物体是否接地。当物体移动时它工作得很好,但是一旦它停下来,刚体就会进入睡眠状态并停止调用碰撞保持。
我的简单高性能解决方案(而不是阻止刚体休眠)是检查 rigindody.IsSleeping() ,如果为 true,则将 Grounded 设置为 True,因为如果对象正在休眠,那么它就不会掉落。
类似的替代选项可以是在调用 OnCollisionStay 时缓存碰撞对象的相对位置,如果 CollisionStay 停止被调用但相对位置没有改变,则假设碰撞仍然处于活动状态。