Ich habe den folgenden Code, um die Übersetzung zu berechnen, die erforderlich ist, um ein Spielobjekt in Unity zu verschieben, das aufgerufen wird LateUpdate
. Soweit ich weiß , sollte meine Verwendung von Time.deltaTime
die endgültige CollisionDetection.Move()
Framerate der Übersetzung unabhängig machen (bitte beachten Sie, dass nur Raycasts ausgeführt werden).
public IMovementModel Move(IMovementModel model) {
this.model = model;
targetSpeed = (model.HorizontalInput + model.VerticalInput) * model.Speed;
model.CurrentSpeed = accelerateSpeed(model.CurrentSpeed, targetSpeed,
model.Accel);
if (model.IsJumping) {
model.AmountToMove = new Vector3(model.AmountToMove.x,
model.AmountToMove.y);
} else if (CollisionDetection.OnGround) {
model.AmountToMove = new Vector3(model.AmountToMove.x, 0);
}
model.FlipAnim = flipAnimation(targetSpeed);
// If we're ignoring gravity, then just use the vertical input.
// if it's 0, then we'll just float.
gravity = model.IgnoreGravity ? model.VerticalInput : 40f;
model.AmountToMove = new Vector3(model.CurrentSpeed, model.AmountToMove.y - gravity * Time.deltaTime);
model.FinalTransform =
CollisionDetection.Move(model.AmountToMove * Time.deltaTime,
model.BoxCollider.gameObject, model.IgnorePlayerLayer);
// Prevent the entity from moving too fast on the y-axis.
model.FinalTransform = new Vector3(model.FinalTransform.x,
Mathf.Clamp(model.FinalTransform.y, -1.0f, 1.0f),
model.FinalTransform.z);
return model;
}
private float accelerateSpeed(float currSpeed, float target, float accel) {
if (currSpeed == target) {
return currSpeed;
}
// Must currSpeed be increased or decreased to get closer to target
float dir = Mathf.Sign(target - currSpeed);
currSpeed += accel * Time.deltaTime * dir;
// If currSpeed has now passed Target then return Target, otherwise return currSpeed
return (dir == Mathf.Sign(target - currSpeed)) ? currSpeed : target;
}
private void OnMovementCalculated(IMovementModel model) {
transform.Translate(model.FinalTransform);
}
Wenn ich die Bildrate des Spiels auf 60 FPS sperre, bewegen sich meine Objekte wie erwartet. Wenn ich es jedoch entsperre ( Application.targetFrameRate = -1;
), bewegen sich einige Objekte viel langsamer als erwartet, wenn auf einem 144-Hz-Monitor ~ 200 FPS erreicht werden. Dies scheint nur in einem Standalone-Build und nicht im Unity-Editor zu geschehen.
GIF der Objektbewegung im Editor, FPS freigeschaltet
http://gfycat.com/SmugAnnualFugu
GIF der Objektbewegung im Standalone-Build, FPS freigeschaltet
quelle
Antworten:
Bei rahmenbasierten Simulationen treten Fehler auf, wenn Aktualisierungen nicht lineare Änderungsraten nicht ausgleichen können.
Angenommen, ein Objekt beginnt mit Positions- und Geschwindigkeitswerten von Null und erfährt eine konstante Beschleunigung von Eins.
Wenn wir diese Aktualisierungslogik anwenden:
Wir können diese Ergebnisse bei unterschiedlichen Frameraten erwarten:
Der Fehler wird dadurch verursacht, dass die Endgeschwindigkeit so behandelt wird, als würde sie für den gesamten Frame gelten. Dies ähnelt einer rechten Riemann-Summe und die Fehlermenge variiert mit der Bildrate (auf einer anderen Funktion dargestellt):
Wie MichaelS hervorhebt , wird dieser Fehler halbiert, wenn die Bilddauer halbiert wird, und kann bei hohen Bildraten belanglos werden. Bei Spielen mit Leistungsspitzen oder langen Frames kann dies zu unvorhersehbarem Verhalten führen.
Glücklicherweise erlaubt uns die Kinematik , die Verschiebung, die durch die lineare Beschleunigung verursacht wird, genau zu berechnen:
Wenn wir also diese Aktualisierungslogik anwenden:
Wir werden die folgenden Ergebnisse haben:
quelle
if(velocity==vmax||velocity==-vmax){acceleration=0}
. Dann sinkt der Fehler erheblich, obwohl er nicht perfekt ist, da wir nicht genau herausfinden, welcher Teil der Frame-Beschleunigung beendet wurde.Es kommt darauf an, von wo aus Sie Ihren Schritt anrufen. Wenn Sie es über Update aufrufen, ist Ihre Bewegung zwar unabhängig von der Bildrate, wenn Sie mit Time.deltaTime skalieren. Wenn Sie es jedoch über FixedUpdate aufrufen, müssen Sie mit Time.fixedDeltaTime skalieren. Ich nehme an, Sie rufen Ihren Schritt von FixedUpdate aus auf, skalieren jedoch mit Time.deltaTime, was zu einer verminderten scheinbaren Geschwindigkeit führen würde, wenn der feste Schritt von Unity langsamer als die Hauptschleife ist, was in Ihrem Standalone-Build geschieht. Wenn der feste Schritt langsam ist, ist fixedDeltaTime groß.
quelle
Time.deltaTime
dass immer noch der richtige Wert verwendet wird, unabhängig davon, wo er aufgerufen wird (wenn er in FixedUpdate verwendet wird, verwendet er fixedDeltaTime).