Menu
CoddyTech

Rung máy quay

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 50 trên 71.

Rung lắc là một đợt dịch chuyển ngẫu nhiên ngắn: trong vài phần mười giây, camera ở một vị trí ngẫu nhiên gần vị trí nghỉ, mỗi khung hình lại có một vị trí mới, rồi trở về. Coroutine rất phù hợp vì nó chạy qua nhiều khung hình và tự kết thúc. Camera này rung lắc khi một tảng đá rơi xuống, một script khác gọi BoulderLanded(); tệp bắt đầu bằng using System.Collections; để dùng IEnumerator:

public float strength = 0.2f;
public float duration = 0.4f;
Vector3 rest;

void Start()
{
    rest = transform.localPosition;
}

public void BoulderLanded()
{
    StartCoroutine(Shake());
}

IEnumerator Shake()
{
    float elapsed = 0f;
    while (elapsed < duration)
    {
        transform.localPosition = rest + Random.insideUnitSphere * strength;
        elapsed += Time.deltaTime;
        yield return null;
    }
    transform.localPosition = rest;
}

Random.insideUnitSphere * strength là một độ lệch ngẫu nhiên có độ dài tối đa bằng strength theo mọi hướng, còn yield return null chọn một độ lệch mới ở khung hình tiếp theo. Cộng Time.deltaTime ở mỗi lượt sẽ tính thời gian thực bằng giây, nên hiệu ứng rung lắc kéo dài duration bất kể tốc độ khung hình. Dòng cuối đưa camera trở lại vị trí cũ; nếu thiếu dòng này, camera sẽ nằm yên tại vị trí mà độ lệch cuối cùng đưa nó đến.

Ở mỗi khung hình, Unity chạy mọi Update(), sau đó chạy các coroutine đang chờ yield return null, rồi chạy mọi LateUpdate(). Vì vậy, camera bám theo đặt vị trí trong LateUpdate() sẽ ghi đè mọi thay đổi do hiệu ứng rung lắc tạo ra. Rung lắc localPosition sẽ tránh được điều này nếu camera là con của một đối tượng rỗng đảm nhiệm việc bám theo: đối tượng cha di chuyển, còn camera rung lắc quanh vị trí của nó bên dưới đối tượng cha.

challenge icon

Thử thách

Trung bình

Làm camera rung khi nhấn Space.

  1. Thêm trường Vector3 shake; và đặt transform.position = player.position + offset + shake; trong LateUpdate().
  2. Trong Shake(), khi elapsed < duration: shake = Random.insideUnitSphere * strength;, cộng Time.deltaTime vào elapsed, rồi dùng yield return null;.
  3. Sau vòng lặp, đặt shake = Vector3.zero;.

Nhấn Chơi, chạy và nhấn Space: góc nhìn rung khi bám theo. Sau đó nhấn Kiểm tra.

Tự làm thử

using System.Collections;
using UnityEngine;

public class ShakeFollow : MonoBehaviour
{
    public Transform player;
    public Vector3 offset = new Vector3(0, 4, -8);
    public float strength = 0.3f;
    public float duration = 0.4f;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            StartCoroutine(Shake());
        }
    }

    void LateUpdate()
    {
        transform.position = player.position + offset;
    }

    IEnumerator Shake()
    {
        // Rung camera trong duration giây, lệch tối đa strength so với vị trí bám theo.
        yield return null;
    }
}

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

Tự luyện tập: Playground Unity