Tại sao nên tránh dùng biến toàn cục trong Unity?

2 min read

1. Tổng quan

Biến toàn cục (Global Variables) là những biến có thể được truy cập từ bất kỳ đâu trong chương trình. Trong Unity, chúng thường được định nghĩa trong các lớp hoặc các đối tượng tĩnh (static) và có phạm vi tồn tại xuyên suốt vòng đời của ứng dụng.

2. Vấn đề khi sử dụng biến toàn cục (GlobalVariables)

Nhiều khi bạn muốn truyền một giá trị giá trị giữa các cảnh(Scene) trong Unity, Một cách đơn giản nhưng tiềm ẩn nhiều rủi ro để chuyển giá trị giữa các cảnh trong Unity là sử dụng các biến toàn cục (GlobalVariables). Ví dụ: chuyển thông tin điểm số từ cảnh(Scene) trò chơi sang cảnh(Scene) kết quả:

  • GlobalVariables.cs (Đây là script khởi tạo các biến toàn cục)
public class GlobalVariables
{
    public static int point;
}
  • GameView.cs (Đây là script được dùng trong Game Scene)
public class GameView : MonoBehaviour
{
    private void GoToSceneResult()
    {
        GlobalVariables.point = 100;
        SceneManager.LoadScene("Result");
    }
}
  • ResultView.cs (Đây là script được dùng trong Result Scene)
public class ResultView : MonoBehaviour
{
    private void Start()
    {
        Debug.Log($"Point: {GlobalVariables.point}");
    }
}
  • Nếu viết như trên, biến point có thể được tham chiếu và thay đổi từ bất cứ đâu. Khi trò chơi mở rộng quy mô hoặc số lượng người chơi tăng lên, việc quản lý những biến này sẽ trở nên khó khăn và dễ gây lỗi.
  • Các biến toàn cục, giống như singletons hoặc PlayerPrefs, đều là những biến có thể truy cập từ mọi nơi trong dự án. Vì vậy, bạn nên tránh sử dụng chúng để truyền giá trị giữa các cảnh(Scene).

2. Giải Pháp

Để giải quyết vấn đề trên, chúng ta sẽ sử dụng SceneViewBase.csSceneManagerController.cs để xử lý chuyển cảnh(Scene) và truyền tham số đến từng cảnh(Scene) cần sử dụng

  • SceneViewBase.cs (Đây là script quản lý và khởi tạo các cảnh trong Unity với khả năng truyền tham số giữa các cảnh(Scene) một cách linh hoạt và dễ dàng. Đây là một cách tiếp cận để thay thế việc sử dụng các biến toàn cục hoặc phụ thuộc trực tiếp vào các cảnh khi cần truyền giá trị giữa các cảnh.)
   public class SceneParameter { }

    public class SceneViewBase : MonoBehaviour
    {
        public virtual async UniTask Initialize()
        {
            await Initialize(null);
        }

        public virtual async UniTask Initialize(SceneParameter param)
        {
            await UniTask.CompletedTask;
        }
    }

    public abstract class SceneViewBase<T> : SceneViewBase where T : SceneParameter, new()
    {
        public sealed override async UniTask Initialize(SceneParameter param)
        {
            if (param == null)
                await Initialize(new T());
            else
                await Initialize(param as T);
        }

        public virtual async UniTask Initialize(T param)
        {
            await UniTask.CompletedTask;
        }
    }
  • SceneManager.cs (Đây là script quản lý việc tải cảnh bất đồng bộ và khởi tạo cảnh với tham số truyền vào)
public class SceneManagerController : MonoBehaviour
{
    public static async void LoadSceneAsync<TParam>(string sceneName, TParam param) where TParam : SceneParameter
    {
        try
        {                
           await SceneManager.LoadSceneAsync(sceneName);
           var scene = GameObject.FindObjectOfType<SceneViewBase>();
           if (scene != null)
               await scene.Initialize(param as TParam);
        }
        catch (OperationCanceledException e)
        {
           Debug.LogWarning("Scene Initialize was cancelled");
           Debug.LogWarning(e.StackTrace);
        }
        catch (Exception e)
        {
          Debug.LogError("Scene Loading Error Happened");
          Debug.LogError(e.Message);
          Debug.LogError(e.StackTrace);
        } 
    }
}
  • GameView.cs (Đây là script được dùng trong Game Scene)
public class GameView : MonoBehaviour
{
    private async void GoToSceneResult()
    {
      await SceneManagerController.LoadSceneAsync<ResultView.ResultParameter>("Result", new()
      {
        Point = 1000,
      });
    }
}
  • ResultView.cs (Đây là script được dùng trong Result Scene)
public class ResultParameter : SceneParameter
{
    public int Point { get; set; }
}
public class ResultView : : SceneViewBase<ResultView.ResultParameter>
{
    public override async UniTask Initialize(ResultParameter param)
    {
      Debug.Log($"Point: {param.Point}");
    }
}

Tham khảo

https://qiita.com/Arihi/items/4242dcbd07de76a60f3a

Avatar photo

Unity IAP: Triển khai Mua Hàng Consumable

Giới Thiệu Việc tích hợp tính năng mua hàng trong ứng dụng Unity là không thể tránh khỏi. Mua hàng trong ứng dụng có...
Avatar photo Tam Canh Le Chi
6 min read

Leave a Reply

Your email address will not be published. Required fields are marked *