Thiết lập mối quan hệ cha-con giữa các ScriptableObject trong Unity

Để xây dựng cấu trúc phân cấp giữa các đối tượng ScriptableObject trong Unity, cần thực hiện một số bước chính xác để đảm bảo dữ liệu được lưu đúng cách và duy trì liên kết giữa các phần tử.

1. Tạo đối tượng cha (parent)

Khởi tạo một thể hiện mới của ScriptableObject cha, sau đó gán nó vào một đường dẫn tài nguyên cụ thể.

var parent = ScriptableObject.CreateInstance<ParentScriptableObject>();
AssetDatabase.CreateAsset(parent, "Assets/Scripts/Data/ParentData.asset");
AssetDatabase.SaveAssets();

2. Tạo đối tượng con (child)

Tạo các đối tượng con bằng cách sử dụng ScriptableObject.CreateInstance, đồng thời gán giá trị ban đầu cho chúng.

var child1 = ScriptableObject.CreateInstance<ChildScriptableObject>();
child1.value = "Giá trị từ child 1";

var child2 = ScriptableObject.CreateInstance<ChildScriptableObject>();
child2.value = "Giá trị từ child 2";

3. Gắn đối tượng con vào đối tượng cha

Sử dụng AssetDatabase.AddObjectToAsset để đưa đối tượng con vào cùng một tệp tài nguyên với đối tượng cha. Đồng thời cập nhật danh sách trong đối tượng cha.

AssetDatabase.AddObjectToAsset(child1, "Assets/Scripts/Data/ParentData.asset");
AssetDatabase.AddObjectToAsset(child2, "Assets/Scripts/Data/ParentData.asset");

parent.children.Add(child1);
parent.children.Add(child2);

4. Đặt đối tượng chính (main object)

Dù không bắt buộc, việc thiết lập đối tượng chính giúp Unity quản lý tốt hơn khi thao tác với tài nguyên.

AssetDatabase.SetMainObject(parent);

5. Lưu và làm mới tài nguyên

Các thay đổi cần được lưu lại và bộ nhớ đệm tài nguyên cần được làm mới để phản ánh đúng trạng thái.

AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset("Assets/Scripts/Data/ParentData.asset");
AssetDatabase.Refresh();

6. Xóa các đối tượng con

Khi cần xóa các đối tượng con, phải hủy bỏ từng phần tử và làm sạch danh sách, đồng thời cập nhật lại tài nguyên.

foreach (var child in parent.children)
{
    Object.DestroyImmediate(child, true);
}
parent.children.Clear();

AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset("Assets/Scripts/Data/ParentData.asset");
AssetDatabase.Refresh();

7. Ví dụ đầy đủ

Dưới đây là định nghĩa các lớp ScriptableObject mẫu:

ChildScriptableObject.cs

using UnityEngine;

[CreateAssetMenu(fileName = "NewChild", menuName = "ScriptableObjects/Child")]
public class ChildScriptableObject : ScriptableObject
{
    public string value;
    
    private void OnEnable()
    {
        name = "Child_" + System.DateTime.Now.Ticks;
    }
}

ParentScriptableObject.cs

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class ParentScriptableObject : ScriptableObject
{
    [SerializeField] public List<ChildScriptableObject> children = new List<ChildScriptableObject>();

    const string ASSET_PATH = "Assets/Scripts/Data/ParentData.asset";

    [MenuItem("Assets/Create/Parent Data")]
    static void CreateParent()
    {
        var parent = ScriptableObject.CreateInstance<ParentScriptableObject>();
        AssetDatabase.CreateAsset(parent, ASSET_PATH);
        AssetDatabase.SaveAssets();

        var child1 = ScriptableObject.CreateInstance<ChildScriptableObject>();
        child1.value = "Test child 1";

        var child2 = ScriptableObject.CreateInstance<ChildScriptableObject>();
        child2.value = "Test child 2";

        AssetDatabase.AddObjectToAsset(child1, ASSET_PATH);
        AssetDatabase.AddObjectToAsset(child2, ASSET_PATH);

        parent.children.Add(child1);
        parent.children.Add(child2);

        AssetDatabase.SetMainObject(parent);
        AssetDatabase.SaveAssets();
        AssetDatabase.ImportAsset(ASSET_PATH);
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/Create/Child Data")]
    static void CreateChild()
    {
        var parent = AssetDatabase.LoadAssetAtPath<ParentScriptableObject>(ASSET_PATH);
        if (parent == null) return;

        var newChild = ScriptableObject.CreateInstance<ChildScriptableObject>();
        newChild.value = "New Dynamic Child";

        AssetDatabase.AddObjectToAsset(newChild, ASSET_PATH);
        parent.children.Add(newChild);

        AssetDatabase.SaveAssets();
        AssetDatabase.ImportAsset(ASSET_PATH);
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/Delete Children")]
    static void RemoveChildren()
    {
        var parent = AssetDatabase.LoadAssetAtPath<ParentScriptableObject>(ASSET_PATH);
        if (parent == null) return;

        foreach (var child in parent.children)
        {
            Object.DestroyImmediate(child, true);
        }
        parent.children.Clear();

        AssetDatabase.SaveAssets();
        AssetDatabase.ImportAsset(ASSET_PATH);
        AssetDatabase.Refresh();
    }
}

Thẻ: Unity ScriptableObject AssetDatabase C# dữ liệu cấu hình

Đăng vào ngày 8 tháng 10 lúc 08:39