问题
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