Menu
CoddyTech

FixedUpdate cho vật lý

Thuộc phần Vật lý và lối chơi trong hành trình Unity của Coddy. Bài học 4 trên 71.

Unity di chuyển các vật thể theo từng bước vật lý cố định, mỗi bước dài 0.02 giây (Time.fixedDeltaTime), tức 50 lần mỗi giây, bất kể tốc độ khung hình. FixedUpdate() chạy ngay trước mỗi bước. Update() chạy một lần mỗi khung hình được vẽ, có thể là 30, 60 hoặc 144 lần mỗi giây: ở tốc độ 144, hầu hết các khung hình không có bước vật lý nào, còn trên máy tính chậm, một khung hình có thể chứa hai bước.

Từ đó có hai quy tắc. Lực được thêm trong Update() sẽ được thêm một lần mỗi khung hình, nên máy tính nhanh hơn sẽ đẩy mạnh hơn: hãy thêm các lực tác động theo thời gian trong FixedUpdate(). Còn GetKeyDown chỉ trả về true trong một khung hình; nếu khung hình đó không có bước vật lý, FixedUpdate() sẽ không nhận được thao tác nhấn và thao tác đó bị bỏ lỡ. Vì vậy, hãy đọc thao tác nhấn trong Update(), lưu lại trong một bool, rồi xử lý trong FixedUpdate(). Con thuyền này được gió đẩy đều và lướt nhanh sang bên khi nhấp chuột:

private bool dashQueued;

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        dashQueued = true;   // ghi nhớ lần nhấp chuột
    }
}

void FixedUpdate()
{
    rb.AddForce(Vector3.forward * wind);   // đẩy đều ở mỗi bước
    if (dashQueued)
    {
        rb.AddForce(Vector3.right * 4f, ForceMode.Impulse);
        dashQueued = false;   // mỗi lần nhấp chuột, một lần lướt
    }
}

Việc đặt lại bool sau khi dùng rất quan trọng: nếu để nguyên true, thuyền sẽ lướt nhanh ở mỗi bước. Bạn cũng có thể thêm một xung lực ngay trong Update(), như cú nhảy của chú ếch; dùng bool giúp gom mọi lực vào một chỗ, cạnh những lực mà nó phối hợp. Các phím được giữ (GetKey, GetAxis) biểu thị một trạng thái chứ không phải một thời điểm, nên FixedUpdate() có thể đọc chúng trực tiếp. Bên trong FixedUpdate(), Time.deltaTime trả về thời lượng của bước, là 0.02.

challenge icon

Thử thách

Dễ

Đặt hai nhiệm vụ của xe trượt tuyết vào đúng phương thức.

  1. Chuyển hai khối if điều khiển mũi tên từ Update() sang FixedUpdate().
  2. Thêm private bool hopPressed;. Trong Update(), đặt biến này thành true khi có Input.GetKeyDown(KeyCode.Space).
  3. Trong FixedUpdate(), khi hopPressed được đặt, hãy thêm lực đẩy tức thời, rồi đặt biến này thành false.

Nhấn Chơi: các phím mũi tên đẩy xe đều đặn và mỗi lần nhấn Space, xe sẽ nhảy. Sau đó nhấn Kiểm tra.

Tự làm thử

using UnityEngine;

public class Sled : MonoBehaviour
{
    public float push = 6f;
    public float hop = 5f;
    private Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.AddForce(Vector3.right * push);
        }
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.AddForce(Vector3.left * push);
        }
    }

    void FixedUpdate()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            rb.AddForce(Vector3.up * hop, ForceMode.Impulse);
        }
    }
}

Tất cả bài học trong Vật lý và lối chơi

Tự luyện tập: Playground Unity