🙃
プロパティを作るとコードが長くなるが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