相机跟随刚体抖动每隔几秒与背景对象

Posted

技术标签:

【中文标题】相机跟随刚体抖动每隔几秒与背景对象【英文标题】:Camera following Rigidbody jitter every few seconds with background objects 【发布时间】:2019-03-13 00:08:28 【问题描述】:

相机跟随 Rigidbody2D 抖动每隔几秒与背景(非刚体)对象(障碍物)。分析器中的 FPS 很好,接近 100。插值也很好。使用 Unity 2017.4.12 (LTS)

动图GIF Video here

相机跟随脚本

 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);
           
    

播放器脚本:

public class PlayerBall : MonoBehaviour 

    public float xSpeed = 10;

    // Update is called once per frame
    void FixedUpdate () 
        this.transform.position = new Vector3(this.transform.position.x + Time.fixedDeltaTime * xSpeed, 
            this.transform.position.y , transform.position.z);
    


玩家刚体

Project File Download

【问题讨论】:

您是否尝试将相机代码从FixedUpdate 移动到Update @Morasiu 是的,延迟更新的抖动比其他任何更新都低。 approvablejitter吗? 是的。我已经看到几个线程报告了这一点。只是一个简单的 2D 事物就会产生这样的抖动。我什至在 android Build 中进行了测试。到目前为止还没有运气。考虑使用 Unity3D 报告问题 请看附件中的项目文件。因为 Profiler 也有峰值。 Unity 的 2D 物理存在问题。 【参考方案1】:

FixedUpdate 的调用速率与帧速率不同,帧速率决定了 UpdateLateUpdate 的调用速率。

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

Manual page for Ridgidbody 2D 还声明:

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

[...] 2D 碰撞器不应直接使用变换 或任何碰撞器偏移量进行移动;应该移动 Rigidbody 2D。这提供了最佳性能并确保正确的碰撞 检测。

对于应该移动的刚体,您可以选择使用DynamicBodyTypeKinematic,具体取决于您的用例。如果您希望飞机被其他非静态对撞机推来推去,它应该是动态的。如果它不应该四处移动,它应该是 Kinematic(这也更高效)。

用例 1:2D 动态刚体

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

不要使用 Transform 组件来设置 Dynamic Rigidbody 2D 的位置或旋转。模拟根据其速度重新定位动态刚体 2D;您可以通过脚本对其施加的力直接更改它 ,或间接通过碰撞和重力。

所以你应该更改播放器脚本以使用 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 检查当前速度)并使用drag 减慢飞机速度。

我不会深入细节,因为我怀疑 Kinematic 实际上是您想要使用的:

用例 2:运动学刚体 2D

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

  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)
  


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

跟随相机

更新相机的位置应始终与帧速率同步。在 FixedUpate 中这样做会导致卡顿。相反,它应该在Update 中完成,或者(如果你想等到由于动画而导致的位置变化在你设置位置之前应用)在LateUpdate

最后

如果游戏中的炸弹也在移动,并且是 Ridgidbodies,其位置在其 FixedUpate 中类似地更新,您应该更改它们以使用 2 个用例中描述的解决方案。

请注意,运动刚体不会引起任何碰撞事件(触发事件仍然会引起)应该接收这些更新的刚体。 我不确定这是否会对性能产生任何影响(除了生成这些事件的影响),您可能仍想阅读1[有关 Ridigbody2D 组件的完整文档]。

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

如果有性能问题,请附上分析器的截图。使用您正在使用的 FPS 显示方法,您可能会经常触发 GC.Collect 以在 FPS 脚本(以及其他地方的 GC.Allocs)中进行字符串操作。

【讨论】:

以上是关于相机跟随刚体抖动每隔几秒与背景对象的主要内容,如果未能解决你的问题,请参考以下文章

由于 Time.deltaTime,C#/Unity 相机跟随抖动

CinemachineFreelook相机鬼畜抖动的解决方法

让PHP文件每隔几秒执行一次

sql数据库 获取当日时间并且让这个时间固定下来 不跟随系统时间变化

在 jupyter 中 [每隔几秒] 更新 plotly 图形

如何使用twisted每隔几秒发送一次IRC消息?