Save/Load dữ liệu trong Unity

25 Tháng sáu, 2024

Save/Load dữ liệu có lẽ là điều quá quen thuộc với những người đã từng chơi game. Bài viết này mình sẽ hướng dẫn các bạn cách dựng một cơ chế save/load cơ bản trong Unity.

Để xây dựng lên một cơ chế save/load dữ liệu mình thường sử dụng đến:

  • PlayerPrefs.
  • JsonDotNet.

PlayerPrefs và JsonDotNet

Như mình đã nói ở trên, mình sẽ cần đến PlayerPrefs và JsonDotNet. Vậy hai cái này là gì?

PlayerPrefs là một API được dựng sẵn trong Unity. Dùng để lưu trữ kiểu dữ liệu string, float, int.
JsonDotNet dùng để chuyển dữ liệu dạng object sang dạng byte để có thể lưu trữ được trong bộ nhớ và ngược lại ( Serialization và Deserialization).

PlayerPrefs và JsonDotNet
PlayerPrefs và JsonDotNet

Lưu ý: Các bạn có thể dùng JsonUtility có sẵn trong Unity để thay thế cho JsonDotNet. Các bạn có thể tải JsonDotNet tại đây.

Chắc hẳn sẽ có vài thắc mắc là tại sao có PlayerPrefs rồi mình phải sử dụng thêm JsonDotNet. Đó là vì PlayerPrefs chỉ lưu được đơn lẻ ba kiểu dữ liệu. Do đó, để có thể lưu được một lức nhiều giá trị của object thì mình phải dùng thêm JsonDotNet để convert nó về dạng string.

Save Dữ Liệu

Đầu tiên mình sẽ tạo một class MonoBehaviour mang những giá trị: hp,level,position và gán vào một GameObject.

public class BaseUnit : MonoBehaviour
{
    public float hp;
    public int level;
}
Tạo ra một class UnitData bao gồm: hp, level, position
Tạo ra một class UnitData bao gồm: hp, level, position

Tiếp là tạo một object chứa những giá trị bạn muốn lưu lại. Ở đây mình sẽ tạo ra một class UnitData bao gồm: hp, level, position. Và đặt các giá trị mặc định cho nó. Đồng thời mình sẽ viết hàm Save() trong đó luôn.

using Newtonsoft.Json; // Dùng JsonDotNet
public class UnitData
{
    public float hp;
    public int level;
    public Vector3 position;
    private string KEY_DATA = "unitdata";
// Đặt các giá trị mặc định
    public UnitData()
    {
        hp = 100f;
        level = 1;
        position = Vector3.zero;
    }
// Save dữ liệu
    public void Save(BaseUnit unit)
    {
        hp = unit.hp;
        level = unit.level;
        position = unit.transform.position;
        // Convert dữ liệu sang dạng string
        string s = JsonConvert.SerializeObject(this);
        // Dùng PlayerPrefs lưu dữ liệu lại
        PlayerPrefs.SetString(KEY_DATA, s);
    }
}

Load Dữ Liệu

Để tiện cho việc quản lý dữ liệu trong game, mình sẽ tạo class GameData để phục vụ việc đó. Sau đó khai báo UnitData ở đó.

public class GameData
{
    public static UnitData unitData;
}

Việc load đầy đủ dữ liệu trước khi bắt đầu trò chơi là rất quan trọng. Để tránh việc load thiếu dữ liệu dẫn đến crash game, mình sẽ tạo một Scene mới phục vụ cho công việc này.

Việc load đầy đủ rất quan trọng
Việc load đầy đủ rất quan trọng

Tại Scene Load, mình tạo một GameObject có chức năng load dữ liệu. Khi các dữ liệu đã được load đầy đủ thì sẽ tự động chuyển sang scene tiếp theo.

public class LoadData : MonoBehaviour
{
    public string nextScene;
    private string KEY_DATA = "unitdata";
    private void Awake()
    {
        LoadUnitData();
// Chuyển sang Scene khác sau khi load dữ liệu xong
        SceneManager.LoadScene(nextScene);
    }
    private void LoadUnitData()
    {
//Lấy dữ liệu dạng string ở PlayerPrefs
        string s = PlayerPrefs.GetString(KEY_DATA);
// Nếu chuỗi string null hoặc rỗng thì sẽ tạo một data mới với các giá trị mặc định
        if (string.IsNullOrEmpty(s))
        {
            GameData.unitData = new UnitData();
            return;
        }
// Dùng JsonDotNet convert dữ liệu từ string sang object
        GameData.unitData = JsonConvert.DeserializeObject<UnitData>(s);
    }
}
Tạo một GameObject có chức năng load dữ liệu
Tạo một GameObject có chức năng load dữ liệu

Sau khi load được dữ liệu, mình sẽ gán những giá trị vào giá trị của Unit.

public class BaseUnit : MonoBehaviour
{
    public float hp;
    public int level;
    private void Start()
    {
        LoadData();
    }
    private void LoadData()
    {
// Gán giá trị từ GameData
        hp = GameData.unitData.hp;
        level = GameData.unitData.level;
        transform.position = GameData.unitData.position;
    }
}

Chạy Thử

Hai phần trên mình đã xây dựng xong cơ chế save/load. Bây giờ mình sẽ chạy thử xem kết quả có như ý hay không.

Ở đây để cho tiết kiệm thời gian mình sẽ dùng phím “Space” để save dữ liệu.

public class BaseUnit : MonoBehaviour
{
    public float hp;
    public int level;
    private void Start()
    {
        LoadData();
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GameData.unitData.Save(this);
            Debug.Log("Saved");
        }
    }
    private void LoadData()
    {
        hp = GameData.unitData.hp;
        level = GameData.unitData.level;
        transform.position = GameData.unitData.position;
    }
}

Sau đó mình sẽ chạy game và thay đổi các giá trị của Unit. Lưu ý là luôn phải chạy game từ scene Load.

Giá trị mặc định
Giá trị mặc định
Giá trị sau khi thay đổi
Giá trị sau khi thay đổi

Mình sẽ dùng phím “Space” để gọi hàm Save sau đó load lại game.

Image 24
Save/Load dữ liệu trong Unity
Sau khi load lại

Vây là hệ thống save/load dữ liệu của mình đã hoạt động ngon lành rồi.

guest
0 Góp ý
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất
Phản hồi nội tuyến
Xem tất cả bình luận
Tin tức liên quan
Hướng dẫn xóa san-pham , danh-muc-san-pham trong đường dẫn sản phẩm Woocommerce
Với mặc định của Woocommerce, chi tiết sản phẩm sẽ có dạng domain/san-pham/ten-san-pham và danh mục sản phẩm sẽ ở dạng domain/danh-muc-san-pham/ten-danh-muc. Một phần đường dẫn như vậy sẽ...
Hướng dẫn tạo sản phẩm Woocommerce có biến thể đẹp mắt
Mình đọc bình luận thấy khá nhiều bạn kêu gặp khó khăn trong vấn đề tạo sản phẩm có biến thể, hay sản phẩm có biến thể không được...
Hướng dẫn lấy đường dẫn các page Woocommerce 3.x
Chắc hẳn ai dùng Woocommerce đều sẽ muốn hiển thị đường dẫn của trang tài khoản, cửa hàng, thanh toán, giỏ hàng,.. Có rất nhiều phương án xử lý...