Save/Load dữ liệu trong Unity
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).
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;
}
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.
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);
}
}
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.
Mình sẽ dùng phím “Space” để gọi hàm Save sau đó load lại game.
Vây là hệ thống save/load dữ liệu của mình đã hoạt động ngon lành rồi.