Saya memiliki kode berikut untuk menghitung terjemahan yang diperlukan untuk memindahkan objek game di Unity, yang dipanggil masuk LateUpdate
. Dari apa yang saya mengerti, penggunaan saya Time.deltaTime
harus membuat frame rate terjemahan akhir independen (harap dicatat CollisionDetection.Move()
hanya melakukan raycast).
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);
}
Jika saya mengunci framerate game ke 60FPS, objek saya bergerak seperti yang diharapkan. Namun, jika saya membukanya ( Application.targetFrameRate = -1;
), beberapa objek akan bergerak pada tingkat yang jauh lebih lambat maka saya harapkan ketika mencapai ~ 200FPS pada monitor 144hz. Ini sepertinya hanya terjadi pada bangunan yang berdiri sendiri, dan bukan di dalam editor Unity.
GIF gerakan objek dalam editor, membuka kunci FPS
http://gfycat.com/SmugAnnualFugu
GIF pergerakan objek dalam build mandiri, FPS terbuka
sumber
Jawaban:
Simulasi berbasis bingkai akan mengalami kesalahan ketika pembaruan gagal mengkompensasi laju perubahan non-linear.
Sebagai contoh, pertimbangkan sebuah objek yang dimulai dengan nilai posisi dan kecepatan nol yang mengalami percepatan konstan satu.
Jika kami menerapkan logika pembaruan ini:
Kami dapat mengharapkan hasil ini di bawah frame rate yang berbeda:
Kesalahan ini disebabkan oleh memperlakukan kecepatan akhir seolah-olah itu diterapkan untuk seluruh frame. Ini mirip dengan Jumlah Riemann Kanan dan jumlah kesalahan bervariasi dengan frame rate (diilustrasikan pada fungsi yang berbeda):
Seperti yang ditunjukkan oleh MichaelS , kesalahan ini akan berkurang separuhnya saat durasi bingkai dibelah dua, dan mungkin menjadi tidak penting pada tingkat bingkai yang tinggi. Di sisi lain, game apa pun yang mengalami lonjakan kinerja atau frame yang berjalan lama mungkin menemukan ini menghasilkan perilaku yang tidak terduga.
Untungnya kinematika memungkinkan kita untuk menghitung perpindahan yang akurat akibat percepatan linier:
Jadi jika kita menerapkan logika pembaruan ini:
Kami akan memiliki hasil sebagai berikut:
sumber
if(velocity==vmax||velocity==-vmax){acceleration=0}
. Kemudian kesalahan menurun secara substansial, meskipun itu tidak sempurna karena kami tidak mengetahui dengan pasti bagian mana dari akselerasi frame yang berakhir.Itu tergantung di mana Anda memanggil langkah Anda. Jika Anda memanggilnya dari Pembaruan, gerakan Anda akan framerate independen jika Anda skala dengan Time.deltaTime, tetapi jika Anda memanggilnya dari FixedUpdate, Anda perlu skala dengan Time.fixedDeltaTime. Saya pikir Anda sedang memanggil langkah Anda dari FixedUpdate, tetapi melakukan penskalaan dengan Time.deltaTime, yang akan menghasilkan penurunan kecepatan nyata ketika langkah tetap Unity lebih lambat daripada loop utama, yang merupakan apa yang terjadi di build mandiri Anda. Ketika langkah tetap lambat, fixDeltaTime besar.
sumber
Time.deltaTime
masih akan menggunakan nilai yang benar terlepas dari mana namanya (jika digunakan dalam FixedUpdate, itu akan menggunakan fixedDeltaTime).