运动学刚体自行移动
Kinematic Rigidbody moves on its own
我的 2D Unity 游戏中有一个非常奇怪的问题,我可以将其简化为以下核心 problem/minimal 重现测试用例。按照以下步骤重现(Unity 5.1.1f1):
- 在位置
(0,0,0)
创建一个玩家对象(立方体)。
- 删除
BoxCollider
组件。
- 附上下面的
C#
脚本,Unity会自动添加所需的组件,从而使其成为刚体碰撞器。
- 设置
isKinematic
标志。
- 在场景
(2,0,0)
处添加另一个立方体。
- 删除
BoxCollider
组件并添加 BoxCollider2D
。这使这个立方体成为静态碰撞体。
- 设置
isTrigger
标志。
- 运行现场.
预期行为:
玩家立方体向另一个立方体加速,一旦碰到它就停止移动。
观察到的行为:
玩家立方体向另一个立方体加速,然后继续以恒定速度移动。
其他实施细节:
我最初通过平移它们的变换来移动所有对象,并且根本没有使用刚体,因为我不需要碰撞检测。现在我这样做了,所以我想要刚体。我深入研究了在线资源,发现我应该使用 rigidbody.MovePosition()
而不是 transform.Translate()
或 transform.position
。我改了脚本,出现了上面的错误。
回到 transform.position
解决了这个问题,但这不是一个好的解决方案,因为它涉及不良做法,根据我读到的内容,它会产生显着的 CPU 负载。
尝试解决失败:
- 切换到
Update()
和 Time.deltaTime
没有任何区别。
- 我尝试不在
Update()
中返回,而只是在设置 stop
时将 timestep
重置为 0
。没有变化。
- 摆弄 Inspector 以及在刚体上冻结位置或将玩家对象设置为触发器等操作都没有任何效果。在游戏 运行(碰撞后)时更改 Rigidbody 组件 上的任何内容都会使立方体立即停止。从字面上看任何东西,甚至将其质量设置为 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 5.1.1f1 中的错误,已在补丁版本 5.1.1p2 及更高版本中修复。
在这里获取:
http://unity3d.com/unity/qa/patch-releases?version=5.1
发生了什么事?
您甚至可以将问题减少到单个 MovePosition
调用。 MovePosition
使用物理引擎移动对象。因此,Unity 会计算在下一次物理更新中到达目标位置所需的速度。 5.1.1f1版本在到达位置后无法将速度归零,因此物体将继续以计算出的速度移动。
我的 2D Unity 游戏中有一个非常奇怪的问题,我可以将其简化为以下核心 problem/minimal 重现测试用例。按照以下步骤重现(Unity 5.1.1f1):
- 在位置
(0,0,0)
创建一个玩家对象(立方体)。 - 删除
BoxCollider
组件。 - 附上下面的
C#
脚本,Unity会自动添加所需的组件,从而使其成为刚体碰撞器。 - 设置
isKinematic
标志。 - 在场景
(2,0,0)
处添加另一个立方体。 - 删除
BoxCollider
组件并添加BoxCollider2D
。这使这个立方体成为静态碰撞体。 - 设置
isTrigger
标志。 - 运行现场.
预期行为:
玩家立方体向另一个立方体加速,一旦碰到它就停止移动。
观察到的行为:
玩家立方体向另一个立方体加速,然后继续以恒定速度移动。
其他实施细节:
我最初通过平移它们的变换来移动所有对象,并且根本没有使用刚体,因为我不需要碰撞检测。现在我这样做了,所以我想要刚体。我深入研究了在线资源,发现我应该使用 rigidbody.MovePosition()
而不是 transform.Translate()
或 transform.position
。我改了脚本,出现了上面的错误。
回到 transform.position
解决了这个问题,但这不是一个好的解决方案,因为它涉及不良做法,根据我读到的内容,它会产生显着的 CPU 负载。
尝试解决失败:
- 切换到
Update()
和Time.deltaTime
没有任何区别。 - 我尝试不在
Update()
中返回,而只是在设置stop
时将timestep
重置为0
。没有变化。 - 摆弄 Inspector 以及在刚体上冻结位置或将玩家对象设置为触发器等操作都没有任何效果。在游戏 运行(碰撞后)时更改 Rigidbody 组件 上的任何内容都会使立方体立即停止。从字面上看任何东西,甚至将其质量设置为 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 5.1.1f1 中的错误,已在补丁版本 5.1.1p2 及更高版本中修复。
在这里获取: http://unity3d.com/unity/qa/patch-releases?version=5.1
发生了什么事?
您甚至可以将问题减少到单个 MovePosition
调用。 MovePosition
使用物理引擎移动对象。因此,Unity 会计算在下一次物理更新中到达目标位置所需的速度。 5.1.1f1版本在到达位置后无法将速度归零,因此物体将继续以计算出的速度移动。