Menu
CoddyTech

Giữ lại giữa các cảnh

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 20 trên 60.

Khi tải một cảnh, Unity hủy mọi đối tượng của cảnh cũ, nhưng một số thứ phải tồn tại suốt trò chơi, chẳng hạn như số xu người chơi mang theo từ màn này sang màn khác. DontDestroyOnLoad(gameObject) đưa một đối tượng ra khỏi cảnh của nó và đặt vào một cảnh riêng, có tên DontDestroyOnLoad trong Hierarchy khi nhấn Play. Cảnh này không bị ảnh hưởng bởi việc tải cảnh. Cách này chỉ hoạt động với đối tượng gốc: nếu gọi trên đối tượng con, Unity sẽ ghi cảnh báo và không giữ lại gì. Các đối tượng con của đối tượng được giữ lại cũng sẽ đi theo, nhưng những đối tượng mà nó chỉ trỏ đến thì không: sau khi tải cảnh, trường từng trỏ đến một đối tượng của cảnh cũ sẽ chứa một đối tượng đã bị hủy, và đối tượng này được so sánh bằng với null.

public class GameSession : MonoBehaviour
{
    public static GameSession Instance;
    public int coins;

    void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

GameSession này nằm trong cảnh Menu. Khi nhấn Play, trò chơi chuyển từ Menu sang Level1 rồi quay lại Menu. Menu tạo lại mọi đối tượng, kể cả một GameSession mới, trong khi GameSession được giữ lại vẫn còn đó. Nếu không có bước kiểm tra trong Awake thì sẽ có hai GameSession, và GameSession mới sẽ thay thế Instance với 0 xu. Nhờ bước kiểm tra đó, GameSession mới phát hiện Instance đã được gán, tự hủy rồi dừng lại, còn phiên chơi đã đi qua các màn vẫn tồn tại.

return rất quan trọng vì Destroy đợi đến cuối khung hình mới hủy đối tượng. Nếu không có nó, phần còn lại của Awake vẫn chạy trên GameSession mới: Instance = this; sẽ khiến mọi tập lệnh trỏ đến một đối tượng sắp bị hủy.

challenge icon

Thử thách

Dễ

Giữ đồng hồ chạy liên tục qua mỗi lần tải cảnh.

  1. Trong Awake(), nếu Instance != null, hãy gọi Destroy(gameObject); rồi return;. Nếu không, hãy đặt Instance và gọi DontDestroyOnLoad(gameObject);.
  2. Việc tải cảnh sẽ phá hủy dòng chữ của màn chơi cũ, vì vậy trong Update(), trước dòng chữ, khi clockText == null, hãy đặt clockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();.

Nhấn Chơi, vào Level2 rồi quay lại: một đồng hồ vẫn tiếp tục đếm. Sau đó nhấn Kiểm tra.

Tự làm thử

using UnityEngine;
using TMPro;

public class RunClock : MonoBehaviour
{
    public static RunClock Instance;
    public TMP_Text clockText;
    private float seconds;

    void Awake()
    {
        Instance = this;
    }

    void Update()
    {
        seconds += Time.deltaTime;
        clockText.text = "Time: " + seconds.ToString("0.0");
    }

    public void Split()
    {
        Debug.Log("Split: " + seconds.ToString("0.0"));
    }
}

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