运动刚体自行移动的运动学解析

5
我在我的2D Unity游戏中遇到了一个非常奇怪的问题,我能将其简化为以下核心问题/最小重现测试用例。按照以下步骤复现(Unity 5.1.1f1):
创建一个位于位置(0,0,0)的玩家对象(Cube)。
删除BoxCollider组件。
附加以下C#脚本,Unity会自动添加所需的组件并使其成为刚体碰撞器。
设置isKinematic标志。
在场景中添加另一个Cube,位置为(2,0,0)。
删除BoxCollider组件并添加BoxCollider2D。这将使此立方体成为静态碰撞器。
设置isTrigger标志。
运行场景。
预期行为: 玩家方块加速向其他方块移动,并在触碰到其他方块时停止移动。
观察到的行为: 玩家方块加速向其他方块移动,然后以恒定速度继续移动。
附加实现细节: 我最初通过转换它们的变换来移动所有对象,并且根本没有使用Rigidbodies,因为我不需要碰撞检测。现在我需要,所以我想要Rigidbodies。我深入研究了在线资源,并发现我应该使用rigidbody.MovePosition()而不是transform.Translate()或transform.position。我更改了我的脚本,上述错误出现了。 回到transform.position可以解决问题,但这不是一个好的解决方案,因为它涉及不良实践,根据我所读到的,会产生显着的CPU负载。
未能解决的尝试:
切换到Update()和Time.deltaTime没有任何区别。
我尝试在Update()中不返回,而是在stop被设置时简单地重置timestep为0。没有变化。
在检查器中捣鼓并做一些诸如在刚体上冻结位置或将玩家对象也设置为触发器之类的事情根本没有效果。在游戏运行后更改刚体组件上的任何内容(在碰撞后)都会使立方体立即停止。真的是任何东西,甚至将其质量设置为0。
我还尝试将速度设置为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;
    }
}

1
玩家方块落在下面的方块上,然后缓慢地向上漂移......我正在使用自制物理引擎......它也能正常工作,不像Unity自带的物理引擎,总是出现奇怪的问题。考虑到你的“引擎”违反了牛顿定律,并似乎实现了反重力,这是一个相当大胆的声明。我的建议是回去找出你在Unity Physics中做错了什么,因为相当多的人在使用它而没有遇到问题。 - user585968
只要我使用静态碰撞器,它就能正常工作。自从我引入刚体后,物理引擎就会出现问题。移动也与使用Unity物理引擎时碰撞器相互碰撞时发生的移动相似。但是,正如您所看到的,没有这样的情况发生。我包含了整个相关代码(以及所有备用引擎)。请随意指出提供的代码中“违反牛顿定律的行”的行。引擎完全正常,问题在于这段代码中。 - scenia
请随意指出代码中“违反牛顿定律”的那一行。- 我不需要。这是你自己承认的:“玩家立方体落在下面的立方体上,然后缓慢地向上漂移...我正在处理重力和碰撞,就像你在代码中看到的那样。”我有误解吗?祝你好运。 - user585968
你这样做了。设置 busy = true 会禁用整个引擎。此时,对象应该完全静止,因为它不受任何影响。如果我的引擎有问题,立方体在受到影响时会表现异常,但是一旦关闭引擎并且 Unity 的引擎接管后,它就开始表现异常。正如我所说,我的整个引擎都在这段代码中,而且你可以很容易地看到,所有的事情都发生在 Update() 中,在设置 busy 后就立即返回。在检测到碰撞后发生的任何事情都是由 Unity 引起的(正确)。 - scenia
我成功将测试用例简化为更简单的版本。现在它不再改变方向,但是运动学刚体未经任何指示就移动的核心问题仍然存在。 - scenia
1个回答

3

解决方案

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

获取地址: http://unity3d.com/unity/qa/patch-releases?version=5.1

发生了什么?

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接