【问题标题】:Kinematic Rigidbody moves on its own运动学刚体自行移动
【发布时间】:2015-07-10 00:16:47
【问题描述】:

我的 2D Unity 游戏中有一个非常奇怪的问题,我能够将其简化为以下核心问题/最小再现测试用例。按照以下步骤重现(Unity 5.1.1f1):

  • 在位置 (0,0,0) 创建一个玩家对象(Cube)。
  • 删除BoxCollider 组件。
  • 附加以下C# 脚本,Unity 将自动添加所需的组件,从而使其成为刚体碰撞器。
  • 设置isKinematic 标志。
  • 在场景(2,0,0)处添加另一个Cube。
  • 删除BoxCollider 组件并添加BoxCollider2D。这使得这个立方体成为一个静态碰撞器。
  • 设置isTrigger 标志。
  • 运行场景。

预期行为:
玩家立方体向另一个立方体加速,一旦碰到它就停止移动。

观察到的行为:
玩家立方体向另一个立方体加速,然后继续以恒定速度移动。

其他实施细节:
我最初通过转换它们的变换来移动所有对象,并且根本没有使用刚体,因为我不需要碰撞检测。现在我这样做了,所以我想要刚体。我深入研究了在线资源,发现我应该使用rigidbody.MovePosition() 而不是transform.Translate()transform.position。我改了脚本,出现了上面的错误。
回到transform.position 解决了这个问题,但这不是一个好的解决方案,因为它涉及不良做法,根据我的阅读,会产生大量的 CPU 负载。

尝试解决失败:

  • 切换到Update()Time.deltaTime 没有任何区别。
  • 我尝试不返回Update(),而是在设置stop 时简单地将timestep 重置为0。没有变化。
  • 摆弄 Inspector 并执行诸如冻结刚体上的位置或将玩家对象设置为触发器之类的操作完全没有效果。 在游戏运行时(碰撞后)更改刚体组件上的任何内容会使立方体立即停止。从字面上看,任何东西,甚至将其质量设置为 0。
  • 我也尝试将velocity 设置为0,结果没有任何变化。这确实是有道理的,因为 Update() 被完全跳过(顺便说一下,我还检查了 Debug.Log())。

所以在这一点上,我只写了 30 行代码,但我仍然不知道是什么原因造成的。由于涉及的对象是静态触发对撞机和运动学刚体对撞机,两者都没有物理材料,因此一旦设置了标志,就不应该有任何东西可以让这个东西移动。但它确实会移动。


SimpleController2D.cs

using UnityEngine;
using System.Collections;

[RequireComponent (typeof (BoxCollider2D), typeof (Rigidbody2D))]
public class SimpleController2D : MonoBehaviour {

    public Vector3 velocity = Vector3.zero;

    private Transform thisTransform;
    private Rigidbody2D thisRigidbody;

    public bool stop = false;

    void Awake () {
        thisTransform = GetComponent<Transform> ();
        thisRigidbody = GetComponent<Rigidbody2D> ();
    }

    void FixedUpdate() {
        float timestep = Time.fixedDeltaTime; // temporarily stored for ease of access
        if (stop) {
            return; // freeze on hit
        }

        velocity.x += timestep; // accelerate
        /* add a second slash (/) to toggle between transform and rigidbody
        thisTransform.position += velocity * timestep; /*/
        thisRigidbody.MovePosition ((Vector3)thisRigidbody.position + velocity*timestep); //*/
    }

    void OnTriggerEnter2D(Collider2D col) {
        stop = true;
    }
}

【问题讨论】:

  • "玩家方块落到下方方块上,然后慢慢向上漂移...我正在使用自制的物理引擎.. . 它也可以工作,不像 Unity 自己的物理引擎,它一直在做奇怪的事情” - 这是一个非常大胆的声明,考虑到你的“引擎”违反了牛顿定律并且似乎有一个反-重力。考虑到很多人都在毫无问题地使用 Unity Physics,我的建议是回头看看你在 Unity Physics 上做错了什么
  • 只要我使用静态碰撞器,它就可以工作。自从我介绍刚体后,物理引擎就搞砸了。该运动也与使用 Unity 物理引擎的 Collider 与自身发生碰撞时发生的运动类似。但正如你所看到的,没有这样的事情发生。我包含了整个相关代码(以及所有替代引擎。请随时指出我提供的代码中“违反牛顿定律”的行)。引擎非常好,问题出在这段代码中。
  • “请随时指出我提供的代码中“违反牛顿定律”的那一行。” - 我不需要。这是你自己承认的“玩家立方体掉到较低的立方体上,然后慢慢向上漂移......我正在处理重力并碰撞你可以在代码中看到"。我误解了吗?祝你好运
  • 你做到了。设置busy = true 会禁用整个引擎。此时,该对象应该是完全不动的,因为它不受任何影响。如果我的引擎出现问题,立方体在受其影响时会出现异常行为,但一旦关闭引擎,它就会开始出现异常行为,并且大概是 Unity 的引擎接管。正如我所说,我的整个引擎都在这段代码中,你可以很容易地看到,一切都发生在Update() 中,它在设置busy 时立即返回。 (正确)检测到碰撞后发生的任何事情都是由 Unity 引起的。
  • 我能够将测试用例简化为更简单的版本。它不再改变方向,但运动学刚体在没有人告诉它的情况下移动的核心问题仍然存在。

标签: c# unity3d collision-detection rigid-bodies


【解决方案1】:

解决方案

这是 Unity 5.1.1f1 中的一个错误,已在补丁版本 5.1.1p2 及更高版本中修复。

在这里获取: http://unity3d.com/unity/qa/patch-releases?version=5.1

发生了什么?

您甚至可以将问题简化为一个 MovePosition 调用。 MovePosition 使用物理引擎移动对象。因此,Unity 会计算在下一次物理更新中到达目标位置所需的速度。 5.1.1f1版本无法在到达位置后将速度重置为零,因此对象将继续以计算出的速度移动。

【讨论】:

    猜你喜欢
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 2017-05-30
    • 1970-01-01
    相关资源
    最近更新 更多