💨

共通マスタ ScriptableObject

2024/03/17に公開

共通パラメータ管理、初期値の宣言にGameObject使うと大変になる

RPGで敵モンスターをGameObjectごとにHP,MPもたせるときに、MaxHP, MaxMPはReadOnlyで良い上にGameObjectにいちいち持たせていたらモンスターが1種1000体スポーンさせた時でも1000体分のパラメータをバラバラに持たせることになる。

ScriptableObject で共通の種ごとにパラメータ管理などをシンプルに行える。

ScriptableObject 概要

  • Object継承クラスであり、GameObjectではないのでエディタ内配置はできない
  • MonoBehaviourにあるUpdateメソッドは使えない
EnemyProfile.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// MyScriptable/Create EnemyData のメニュー作成
[CreateAssetMenu(menuName = "MyScriptable/Create EnemyData")]
[System.Serializable]
public class EnemyProfile : ScriptableObject {
    public string enemyName;
    public int defaultHp;
    public int defaultMp;

    public static LoadJSON()
    {
        Debug.Log("LoadJSON");

        // ScriptableObjectアセットのファイルパス
        var enemyProfile = AssetDatabase.LoadAssetAtPath<EnemyProfile>("");
        // JSONファイルのパス
        TextAsset localJsonFile = AssetDatabase.LoadAssetAtPath<TextAsset>("");

        try {
            JsonUtility.FromJsonOverwrite(localJsonFile.text, enemyProfile);
            AssetDatabase.SaveAssets();
        } catch (Exception e) {
            //例外を処理する場合
        }
        return enemyProfile;
    }

    public static SaveJSON()
    {
        Debug.Log("SaveJSON");

        // ScriptableObjectアセットのファイルパス
        string json = JsonUtility.ToJson (AssetDatabase.LoadAssetAtPath<TestScriptableObject>(""));

        try {
            // 書き出すファイルのパス
            using (StreamWriter writer = new StreamWriter(""))
            {
                writer.Write(json.ToString());
            }
            //import
            AssetDatabase.ImportAsset(jsonPath);
        } catch (Exception e) {
            //例外を処理する場合
        }
        return enemyProfile;
    }


    public string ToJSON()
    {
        // floatはToJsonで誤差が生じる
        return JsonUtility.ToJson(this);
    }
}
Enemy.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour {
    [SerializeField] private int iHP;
    [SerializeField] private int iMP;

    // カスタムクラスのフィールド
    [SerializeField] private EnemyProfile enemyProfile;

    void Start(){
        outputParam;
    }
	
    void Update(){
		
    }

    void outputParam(){
        iHP = enemyProfile.defaultHP;
        iMP = enemyProfile.defaultMP;
        Debug.Log("HP / MP : " + iHP + " , " + iMP );
        Debug.Log(enemyProfile.ToJSON);
    }

    public void OnButtonClickInInspectorLoadJSON()
    {
        // JSONを読込
        enemyProfile.LoadJSON;
    }

    public void OnButtonClickInInspectorSaveJSON()
    {
        // JSONを読込
        enemyProfile.SaveJSON;
    }

}

EnemyEditor.cs
/*
 * ./Editor/EnemyEditor.cs 
 */
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(Enemy), true)]
public class EnemyEditor : Editor
{
    [ContextMenu("SaveJSON")]
    private void SaveJSON () {
    	script.OnButtonClickInInspectorSaveJSON();
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        Enemy script = target as Enemy;

        if (GUILayout.Button("LoadJSON"))
        {
            script.OnButtonClickInInspectorLoadJSON();
        }

    }
}

Discussion