🙃

プロパティを作るとコードが長くなるがScriptableObjectで解決できるんじゃね?

に公開

こういうやつ

Unityでこんな風にプロパティを書くとしよう

public class Player : MonoBehaviour
{
    [SerializeField] private int health;
    [SerializeField] private int mana;
    [SerializeField] private float speed;
    [SerializeField] private string playerName;
    [SerializeField] private bool _isFarEnough;

    public int Health
    {
        get => health;
        private set
        {
            if (health != value)
            {
                health = value;
                // ここにイベント通知やUI更新などを追加できる
            }
        }
    }

    // 他のプロパティも同様、多分90行くらい必要
}

この時点で「うわ、わたしの年収低すぎ、書くこと多っ…」ってなる。

これくらいなら1行で済むのでちょっと大げさだが

とにかくLOGを書き込まなければならないケースなど、1行で済まないことがある。

さらにこれが増えていくと、ファイルの中身がプロパティで埋まっていく。

ScriptableObjectに変数が書けるんだからアクセサーもできる説

ScriptableObjectに書いてみよう

こういう値を書き込む程度の用途なら耐えられる

[CreateAssetMenu(fileName = "PlayerData", menuName = "Game/PlayerData")]
public class PlayerData : ScriptableObject
{
    // バッキングフィールド
    [SerializeField] private int _health;
    [SerializeField] private int _mana;
    [SerializeField] private float _speed;
    [SerializeField] private string _playerName;
    [SerializeField] private bool _isFarEnough;

    // プロパティ実装
    public int Health
    {
        get => _health;
        set
        {
            if (_health != value)
            {
                _health = value;
                Debug.Log($"Health changed to {value}");
                // その他の処理
            }
        }
    }

    public int Mana
    {
        get => _mana;
        set
        {
            if (_mana != value)
            {
                _mana = value;
                // 変更処理
            }
        }
    }

    // 他のプロパティも同様

    // 初期化メソッド
    public void Initialize(int health, int mana, float speed, string playerName)
    {
        _health = health;
        _mana = mana;
        _speed = speed;
        _playerName = playerName;
        _isFarEnough = false;
    }
}

そうすると、さっきのコードはこうなる

Playerから90行近いプロパティは消滅し、メンバ変数はPlayerData1つでオッケーになり

君のモニターはAwakeなどの実装を書くことに集中できるわけだ。

public class Player : MonoBehaviour
{
    [SerializeField] private PlayerData playerData;
    
    private void Awake()
    {
        // ゲーム開始時の初期化
        playerData.Initialize(100, 50, 5.0f, "Hero");
    }
    
    // ダメージ処理の例
    public void TakeDamage(int damage)
    {
        playerData.Health -= damage;
    }
    
    // プロパティへの直接アクセス
    public void AddMana(int amount)
    {
        playerData.Mana += amount;
    }
}

よくあること

Unityから変数を確認するのが面倒になる

なぜならPlayerクラスを実装したGameObjectにはScriptableObjectだけしか表示されない。

HPなどはScriptableObjectを探して確認する手間が増える。

データは保持される、初期化を忘れると意図しないデータでゲームが始まる

ScriptableObjectのデータは永続性

HP0でGameOverになった後とか、元に戻さないと、HP0のままで即死する。

// Playerクラスの中
void Start()
{
    // ゲーム開始時に必ず初期化
    playerData.Initialize(100, 50, 5.0f, "Player1");
}

GameObjectを複数用意すると1つのScriptableObjectの奪い合いが始まる

これはInstantiateなどで対処できる

void Awake()
{
    // ScriptableObjectのコピーを作成
    PlayerData originalData = playerData;
    playerData = Instantiate(originalData);
    
    // 初期化
    playerData.Initialize(100, 50, 5.0f, "Player" + gameObject.GetInstanceID());
}

発展的な

ScriptableObjectにEventを盛り込む、これは試してないので深くは書かないでおく。

[CreateAssetMenu(fileName = "PlayerData", menuName = "Game/PlayerData")]
public class PlayerData : ScriptableObject
{
    // バッキングフィールド
    [SerializeField] private int _health;
    [SerializeField] private int _mana;
    [SerializeField] private float _speed;
    [SerializeField] private string _playerName;
    [SerializeField] private bool _isFarEnough;

    // 変更通知用のイベント
    public event Action<int> OnHealthChanged;
    public event Action<int> OnManaChanged;
    public event Action<float> OnSpeedChanged;
    public event Action<string> OnPlayerNameChanged;
    public event Action<bool> OnIsFarEnoughChanged;

    // イベント発火機能を持つプロパティ
    public int Health
    {
        get => _health;
        set
        {
            if (_health != value)
            {
                int oldValue = _health;
                _health = value;
                OnHealthChanged?.Invoke(value);
                Debug.Log($"Health changed from {oldValue} to {value}");
            }
        }
    }

    // 他のプロパティも同様...
}

実用性はともかくScriptableObjectは便利

Discussion