相机每隔几秒钟就会跟随刚体抖动,并带有背景对象

时间:2018-10-08 10:26:23

标签: c# unity3d game-physics unity3d-2dtools

具有背景(非刚体)对象(障碍物)的Rigidbody2D抖动每几秒钟跟随一次相机。探查器中的FPS很好,接近100。插值也很好。使用Unity 2017.4.12(LTS)

GIF GIF Video here

相机跟随脚本

componentDidUpdate

玩家脚本:

 public class CameraFollow : MonoBehaviour {
        public float followRange = 0.5f;
        public float cameraZ;
        public Transform Player;
        public Vector3 newPos;
        void Start () {
            cameraZ = transform.position.z;
        }
        void FixedUpdate() {
            newPos = new Vector3(Player.position.x + followRange, 0, cameraZ);
            transform.position = Vector3.Lerp(transform.position, newPos, 0.5f);
        }   
    }

玩家刚体

enter image description here

Project File Download

1 个答案:

答案 0 :(得分:1)

调用FixedUpdate的速率与指示UpdateLateUpdate的速率的帧速率不同。

FixedUpdate应该用于设置刚体的速度。在FixedUpdate中设置位置始终会产生抖动的风险,因为它会与帧速率不同步。在模拟的刚体上设置位置也违背了模拟它的要点,因为您要覆盖物理对刚体的任何影响。

Manual page for Ridgidbody 2D还指出:

  

刚体2D组件将覆盖变换并将其更新为刚体2D定义的位置/旋转。请注意,尽管您仍然可以自己修改Transform组件来覆盖Rigidbody 2D(因为Unity公开了所有组件上的所有属性),但这样做会导致诸如GameObjects彼此穿行或相互进入以及不可预测的运动等问题。

     

[...]切勿使用Transform 或任何对撞机偏移量直接移动Collider 2D 。应改为移动刚体2D。这可提供最佳性能并确保正确的碰撞   检测。

对于应该移动的刚体,您可以根据自己的使用情况,选择使用Dynamic BodyType还是Kinematic。如果要使飞机被其他非静态对撞机推动,则应为“动态”。如果不应该四处移动,则应该是运动学的(也更有效)。

用例1:动态刚体2D

这是您当前的设置。但是,Manual page for Ridgidbody 2D也指出:

  

请勿使用Transform组件设置Dynamic Rigidbody 2D的位置或旋转。仿真根据其速度重新定位了动态刚体2D。您可以通过脚本施加的力直接更改它   ,或通过碰撞和重力间接产生。

因此,您应该更改Player脚本以使用Rigidbody2D方法AddForce

public class PlayerBall : MonoBehaviour {

  public float thrust = 10;
  Rigidbody2D body;
  Vector2 forwardDirection = Vector2.right;

  void Awake() {
    body = GetComponent<Ridigbody2d>();
  }

  // FixedUpdate is called once per physics update
  void FixedUpdate () {
    body.AddForce(forwardDirection * thrust)
  }

}

现在,这将不断向飞机施加力,推动飞机前进并使其加速。因此,您可能会想出一种方法来稳定速度,方法是在接近目标速度时减小附加力(可以使用body.velocity.x检查当前速度),并通过使用{{1 }}。

由于我怀疑Kinematic实际上是您要使用的内容,因此我不会进一步详述:

用例2:2D运动刚体

已将drag设置为Kinematic的Ridgedbody2D可以使用Ridgedbody2D组件MovePosition方法安全地移动。 因此,使用该设置,您的播放器脚本将如下所示: 公共类PlayerBall:MonoBehaviour {

Body Type

注意:我在这里使用Time.deltaTime是因为此属性返回的值对于使用它的Update方法类型始终是正确的增量时间。

跟随摄像机

更新相机的位置应始终与帧速率同步。在FixedUpate中这样做会导致结结。相反,应该在 public float xSpeed = 10; Rigidbody2D body; Vector2 forwardDirection = Vector2.right; void Awake() { body = GetComponent<Ridigbody2d>(); } // FixedUpdate is called once per physics update void FixedUpdate () { body.MovePosition(forwardDirection + xSpeed * Time.deltaTime) } } Update

中完成(或者,例如,如果要等到由于动画而应用位置变化后再设置位置)

最后

如果游戏中的炸弹也在移动,并且是Ridgidbody,其FixedUpate中的位置也进行了类似的更新,则应更改它们以使用2个用例之一所述的解决方案。

请注意,运动刚体不会引起任何碰撞事件(仍然会触发事件)。如果要将炸弹和飞机都移动为运动刚体,但仍会引起碰撞事件,则可以设置LateUpdate关于应该接收这些更新的僵尸。 我不确定这是否会对性能产生影响(除了产生这些事件的影响之外),您可能仍想阅读1 [有关Ridigbody2D组件的完整文档]。

总体TL; DR :您所看到的可能不是性能问题(否则它会显示在Profiler中,并且会出现抖动和较差的情况FPS),但由于使用错误的更新方法和方案将运动应用于身体而导致运动抖动。这是Unity中非常常见的陷阱。

如果存在性能问题,请附加探查器的屏幕截图。使用FPS显示方法时,很可能会触发GC。经常收集FPS脚本(以及其他地方的GC.Allocs)中的字符串操作。