Menu
CoddyTech

Tự xử lý trọng lực

Thuộc phần Xây dựng trò chơi thực tế trong hành trình Unity của Coddy. Bài học 39 trên 60.

Một CharacterController chỉ rơi khi script khiến nó rơi, và khi rơi thật, tốc độ sẽ tăng dần: trọng lực cộng thêm khoảng 9.81 đơn vị mỗi giây vào tốc độ rơi sau mỗi giây. Vì vậy, script lưu tốc độ theo chiều dọc trong một trường, mỗi khung hình cộng thêm gravity * Time.deltaTime vào đó, rồi dùng tốc độ này để di chuyển trong cùng lệnh Move với bước đi:

public float gravity = -9.81f;
float verticalSpeed;

void Update()
{
    if (controller.isGrounded && verticalSpeed < 0f)
    {
        verticalSpeed = -2f;   // Khi chạm đất: dừng rơi, duy trì lực đẩy nhẹ xuống dưới
    }
    verticalSpeed += gravity * Time.deltaTime;

    Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
    move.y = verticalSpeed;
    controller.Move(move * Time.deltaTime);
}

Time.deltaTime xuất hiện hai lần cho hai việc: gravity * Time.deltaTime là lượng tốc độ tăng thêm trong khung hình này, còn tốc độ nhân với Time.deltaTime là quãng đường di chuyển trong khung hình này. Tốc độ được lưu trong một trường vì nó cần được giữ nguyên qua các khung hình; biến cục bộ sẽ bắt đầu lại từ 0 ở mỗi khung hình. Khi rơi từ trạng thái đứng yên, sau nửa giây, tốc độ của bộ điều khiển là -4.9 đơn vị mỗi giây, và sau một giây là -9.81.

Việc đặt lại cũng quan trọng như việc rơi. Khi ở trên sàn, Move dừng bộ điều khiển, nhưng không có gì dừng trường này: nếu không đặt lại, giá trị sẽ tiếp tục tăng khi người chơi đứng yên, và khi bước khỏi mép vực, người chơi sẽ rơi xuống với tốc độ tối đa. Giá trị được đặt lại thành một số âm nhỏ thay vì 0 để mỗi Move vẫn đẩy bộ điều khiển xuống sàn: ở tốc độ khung hình cao, lực đẩy do trọng lực trong một khung hình có thể ngắn hơn Min Move Distance, khiến Move không làm gì và isGrounded chuyển thành false. isGrounded được đọc trước Move, nên nó mô tả Move của khung hình trước.

challenge icon

Thử thách

Trung bình

Thêm trọng lực cho thợ lặn để tốc độ rơi tăng dần.

  1. Ở đầu Update(), khi controller.isGrounded và verticalSpeed < 0f, đặt verticalSpeed = -1f;.
  2. Cộng gravity * Time.deltaTime vào biến này, rồi giữ giá trị của nó ở mức -maxFall trở lên bằng Mathf.Max.
  3. Trước dòng controller.Move, đặt move.y = verticalSpeed;.

Nhấn Chơi rồi bước khỏi tòa tháp: tốc độ rơi tăng lên đến 10 đơn vị mỗi giây. Sau đó nhấn Kiểm tra.

Tự làm thử

using UnityEngine;

public class Diver : MonoBehaviour
{
    public float speed = 4f;
    public float gravity = -12f;
    public float maxFall = 10f;

    CharacterController controller;
    float verticalSpeed;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        // Trọng lực: đặt lại verticalSpeed khi chạm đất, cộng thêm gia tốc trọng trường, giới hạn tốc độ rơi rồi gán vào move.y

        Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
        controller.Move(move * Time.deltaTime);
    }
}

Tất cả bài học trong Xây dựng trò chơi thực tế

Tự luyện tập: Playground Unity