Camera following Rigidbody jitter every few seconds with background objects

坚强是说给别人听的谎言 提交于 2020-02-25 06:58:39

问题


Camera following Rigidbody2D jitter every few seconds with background (non rigidbody) objects (Obstacles). The FPS in profiler is fine it is near to 100. also Interpolate is also fine. Using Unity 2017.4.12 (LTS)

GIF GIF Video here

Camera Follow Script

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

Player Script :

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

}

Player Rigidbody

Project File Download


回答1:


The rate at which FixedUpdate is called is different than the frame rate which dictates the rate at which Update and LateUpdate are called.

FixedUpdate should be used to set velocities on rigidbodies. Setting positions in FixedUpdate always runs the risk of jitter as it is called out of synch with your frame rate. Setting position on a simulated Rigidbody also goes against the point of simulating it as you are overriding whatever impact the physics might have on the Rigidbody.

The Manual page for Ridgidbody 2D also states that:

The Rigidbody 2D component overrides the Transform and updates it to a position/rotation defined by the Rigidbody 2D. Note that while you can still override the Rigidbody 2D by modifying the Transform component yourself (because Unity exposes all properties on all components), doing so will cause problems such as GameObjects passing through or into each other, and unpredictable movement.

[...] A Collider 2D should never be moved directly using the Transform or any collider offset; the Rigidbody 2D should be moved instead. This offers the best performance and ensures correct collision detection.

For a Rigidbody that should be moving, you have the choice between using a Dynamic BodyType or a Kinematic one, depending on your usecase. If you want the plane to be pushed around by other non-static colliders, it should be Dynamic. If it should not be moved around, it should be Kinematic (which is also more performant).

Use-case 1: Dynamic Rigidbody 2D

This is the setup you have currently. However, the Manual page for Ridgidbody 2D also states that:

Do not use the Transform component to set the position or rotation of a Dynamic Rigidbody 2D. The simulation repositions a Dynamic Rigidbody 2D according to its velocity; you can change this directly via forces applied to it by scripts , or indirectly via collisions and gravity.

So you should change the Player script to use the Rigidbody2D method 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)
  }

}

Now this will just continuously add a force to the plane, propelling it forwards and accelerating it. So you'll likely want to figure out a way to stabilize the speed by reducing the added force as you approach a target velocity (you can check the current velocity with body.velocity.x) and by slowing the plane down using drag.

I won't go further into the details because I suspect that Kinematic is actually what you'd want to use:

Use-case 2: Kinematic Rigidbody 2D

A Ridgedbody2D with the Body Type set to Kinematic can safely be moved with the Ridgedbody2D components MovePosition method. So with that setup, you're player script would look like this: public class 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)
  }

}

Note: I'm using Time.deltaTime here because the value returned by this property will always be the correct delta time for the type of Update method it is used in.

Following Camera

Updating the position of the camera should always be in sync with the framerate. Doing so in FixedUpate can cause stutter. Instead it should be done in Update or (if you want to e.g. wait until position changes due to animations are applied before you set the position) in LateUpdate

Lastly

If the bombs in the game are also moving, and are Ridgidbodies where the position is updated similarly in their FixedUpate, you should change them to use a solution as described in either of the 2 use cases.

Note that Kinematic Rigidbodies wont cause any collision events (trigger events will still be caused) If you want to move both the bombs and the plane as Kinematic Ridigbodies but collision events to still be cause, you can set Use Full Kinematic Contacts on the rigidbodies which should receive these updates. I'm not sure if this would have any performance impacts (besides the one for generating these events) and you might still want to read the 1[full documentation on the Ridigbody2D component].

Overall TL;DR: what you're seeing is likely not a performance problem (or it would show up in the Profiler and you'd have fluttering and poorer FPS) but movement jitter due to using the wrong update methods and schemes to apply movement to physical bodies. This is a very common pitfall in Unity.

If there is a performance problem, please attach a screenshot of the profiler. With the FPS display method you are using, likely you are triggering a GC.Collect every so often for string manipulations in the FPS script (and GC.Allocs elsewhere).



来源:https://stackoverflow.com/questions/52700255/camera-following-rigidbody-jitter-every-few-seconds-with-background-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!