【Unity 6】ScriptableObject入門|敵の設定データと現在HPを分けて理解しよう

「敵の種類を増やすたびに、スクリプトを複製しないといけないの?」――そんな疑問から、ゲームの設定データと実行中の状態を分ける設計を学びます。
この演習では、同じ Slime.asset を参照する2体のスライムを用意し、片方だけにダメージを与えます。最大HPは両方とも10のまま、現在HPだけが片方で減ることを、Gameビューで確かめましょう。
学習目標
MonoBehaviourとScriptableObjectの役割を説明できる。CreateAssetMenuを使って.assetファイルを作成できる。- 同じ設定データを複数のオブジェクトから参照できる。
- 最大HP(設定値)と現在HP(実行時の状態)を区別できる。
事前知識:
class、継承、フィールド、[SerializeField]、Unity Inspector、GameObject、Prefab。Unity 6(6000.x)を想定。画面上の文字表示はTextMeshProを使用します。初回導入時にTMP Essentialsのインポートを求められたら、インポートしてください。
1. なぜ設定データを分けるの?(10分)
次のように、敵の設定を MonoBehaviour に直接書く方法を考えましょう。
using UnityEngine;
public class SimpleMonster : MonoBehaviour
{
[SerializeField] private int maxHp = 10;
[SerializeField] private int attack = 3;
}
少数の敵だけなら、これでも問題ありません。ただし同じ種類の敵が増えていくと、どのオブジェクトに同じ設定を使うか、変更をどこで管理するかが気になるようになります。
ScriptableObjectを使うと、設定を .asset ファイルとして作り、複数のGameObjectから同じデータを参照できます。ScriptableObject はGameObjectにコンポーネントとして追加するのではなく、独立したアセットとして扱います。
注意:「ScriptableObjectを使えば必ず速くなる」「MonoBehaviourに値を持ってはいけない」という意味ではありません。小さなゲームでは直接設定した方が簡単な場合もあります。今回は共有する設定データを整理する使い方を学びます。
2. モンスター設定を作ろう(15分)
Projectウィンドウに次のフォルダーを作ります。
Assets/
Scripts/
MonsterData.cs
MonsterActor.cs
MonsterData/
Slime.asset
Goblin.asset ← 余裕があれば演習で作成
Assets/Scripts/MonsterData.cs を作成し、次のコードを入力します。
using UnityEngine;
[CreateAssetMenu(fileName = "NewMonsterData", menuName = "Game/Monster Data")]
public class MonsterData : ScriptableObject
{
[SerializeField] private string monsterName = "モンスター";
[SerializeField, Min(1)] private int maxHp = 10;
[SerializeField, Min(0)] private int attack = 3;
public string MonsterName => monsterName;
public int MaxHp => maxHp;
public int Attack => attack;
}
ここで押さえるポイント
: ScriptableObject:設定データの型を定義する。[CreateAssetMenu(...)]:Projectウィンドウの右クリック→ Create > Game > Monster Data に項目を追加する。[SerializeField]:privateフィールドをInspectorに表示・保存する。MonsterName、MaxHp、Attack:外部から設定値を読み取るためのプロパティ。今回は外部から直接代入できない。[Min]:Inspectorでの値の入力補助。ゲームルールの完全な検証の代わりではありません。
アセットの作成手順
- Unityに戻り、Consoleにコンパイルエラーがないか確認します。
- Projectウィンドウで
Assets/MonsterDataを右クリックします。 - Create > Game > Monster Data をクリックします。
- 作成されたファイルを
Slime.assetに変更します。 Slime.assetを選択し、Inspectorに次の値を入れます。
| 項目 | 値 |
|---|---|
| Monster Name | スライム |
| Max Hp | 10 |
| Attack | 3 |
.csは「データの型」、.assetは「実際の設定データ」です。C#のクラス定義とオブジェクトの関係を思い出しましょう。
3. 同じ設定を使う2体を作ろう(20分)
次に Assets/Scripts/MonsterActor.cs を作成します。
using TMPro;
using UnityEngine;
public class MonsterActor : MonoBehaviour
{
[SerializeField] private MonsterData monsterData;
[SerializeField] private TMP_Text statusText;
private int currentHp;
private void Start()
{
if (monsterData == null || statusText == null)
{
Debug.LogError("MonsterData または StatusText が未設定です。", this);
enabled = false;
return;
}
currentHp = monsterData.MaxHp;
RefreshView();
}
// UI Button の On Click() から呼び出す
public void TakeDamage()
{
if (monsterData == null || statusText == null || !enabled)
{
return;
}
currentHp = Mathf.Max(0, currentHp - 3);
RefreshView();
}
private void RefreshView()
{
statusText.text =
$"{monsterData.MonsterName}\n" +
$"現在HP:{currentHp} / 最大HP:{monsterData.MaxHp}\n" +
$"攻撃力:{monsterData.Attack}";
}
}
Unityでの画面づくり
ここでは複雑な画像素材を使いません。UIだけで2体の独立した状態を確認します。
- Hierarchyで Canvas を作ります。Canvasがなければ自動生成されることもあります。
- Canvasの下に Text – TextMeshPro を2つ作成し、名前を
SlimeTextAとSlimeTextBにします。文字が見えるよう左右に配置し、RectTransformの幅・高さを適宜調整します。 - Canvasの下に Button – TextMeshPro を2つ作成します。左右に配置し、表示文字をそれぞれ「Aにダメージ」「Bにダメージ」にします。
- Hierarchyに空のGameObject
SlimeA、SlimeBを2つ作り、両方にMonsterActorコンポーネントを追加します。 SlimeAの Monster Data にSlime.asset、Status Text にSlimeTextAを割り当てます。SlimeBにも同じSlime.assetとSlimeTextBを割り当てます。- 「Aにダメージ」Buttonの On Click() で
+を押し、SlimeAをドラッグし、MonsterActor > TakeDamage()を選択します。「Bにダメージ」も同様にSlimeBを指定します。 - Playを押してGameビューの文字を確認します。文字が表示されない場合は、TextMeshProのフォントアセットが日本語の文字を含むかも確認してください。環境によっては日本語対応フォントの準備が必要です。
予想してから実行しよう: 最初はどちらも 10 / 10。Aのボタンだけを押すと、BのHPはどうなるでしょうか?
| 操作 | スライムA | スライムB |
|---|---|---|
| 開始時 | 10 / 10 | 10 / 10 |
| Aを1回押す | 7 / 10 | 10 / 10 |
| Aをもう1回押す | 4 / 10 | 10 / 10 |
| Bを1回押す | 4 / 10 | 7 / 10 |
結果の読み方: AとBは同じ Slime.asset にある最大HPを参照しています。一方、currentHp は各 MonsterActor コンポーネントが持つ別々のフィールドです。だから、片方へのダメージはもう片方の現在HPに影響しません。
4. 自分で考える演習(10分)
演習A:ゴブリンを追加する
Assets/MonsterData で Create > Game > Monster Data から Goblin.asset を作りましょう。
| 項目 | 値 |
|---|---|
| Monster Name | ゴブリン |
| Max Hp | 30 |
| Attack | 8 |
SlimeB の Monster Data だけを Goblin.asset に変更してPlayします。C#のコードを変更せず、Bがゴブリンになり、最大HPが30になることを確認します。
演習B:共有してはいけない状態を考える
次のコードを MonsterData に書いて、ダメージのたびに変更したら何が問題でしょうか?
// これは今回の設計では採用しない例
// monsterData に currentHp があり、そこへ書き込むと仮定
// monsterData.currentHp -= 3;
考える観点: 同じアセットを参照する2体が、状態まで共有してしまう可能性があります。さらにエディター上のPlay中にScriptableObjectアセットを変更すると、テスト後に意図しない値が残ることがあります。設定値は参照し、実行時の状態は個々のMonoBehaviourが持つという分け方を基本にしましょう。
補足:ScriptableObjectそのものに処理(メソッド)を書くこともできます。「ScriptableObjectはメソッドを持てない」という説明は誤りです。今回は入門として設定データの管理に用途を絞っています。
5. 振り返り(5分)
| 種類 | 役割 | 今回の例 |
|---|---|---|
MonoBehaviour | GameObjectに付けて、実行中のふるまい・状態を扱う | MonsterActor と currentHp |
ScriptableObject | GameObjectから独立した共有設定データを扱う | MonsterData |
.asset ファイル | 設定データの実体 | Slime.asset、Goblin.asset |
| Prefab | GameObjectとコンポーネント構成を再利用するひな形 | SlimeA をPrefab化する場合 |
確認問題(3問)
Q1. 同じ Slime.asset を参照するスライムが2体います。Aの currentHp を3減らしたら、Bの currentHp も減りますか?
Q2.
MonsterData.cs と Slime.asset の違いを説明してください。
Q3. 敵の「最大HP」と「現在HP」は、それぞれどこで管理するのが適切ですか?
解答例を表示
1. 減らない。`currentHp` はそれぞれの `MonsterActor` が持つ。 2. `.cs` はデータの型を定義し、`.asset` はその型に基づく設定値を保存する。 3. 最大HPは `MonsterData` の設定値、現在HPは各 `MonsterActor` のフィールドで管理する。よくあるトラブル
| 症状 | 確認すること |
|---|---|
Game/Monster Data がメニューにない | MonsterData.cs のコンパイルエラー、ファイル名・クラス名、CreateAssetMenu を確認 |
| Gameビューに文字が出ない | TMP Essentials、テキスト参照、Canvas配置、フォントの日本語対応を確認 |
| ボタンを押しても変化しない | Buttonの On Click() の対象GameObjectと TakeDamage() を確認 |
| エラーが出る | Monster Data、Status Text の参照が両方セットされているか確認 |
| Bの種類を変えたのにAも変わる | SlimeA と SlimeB の Monster Data の割り当てを個別に確認 |
発展:Prefabやチーム開発とのつながり
この演習の SlimeA をPrefabにすれば、同じ構成の敵を増やせます。PrefabはGameObjectのひな形、ScriptableObjectは設定データの共有先です。この2つは競合する機能ではなく、一緒に利用できます。
GitHubで共同作業する場合は、MonsterData.cs に加え、Slime.asset や Goblin.asset および対応する .meta ファイルをコミット対象に含めます。プロジェクトで運用中の「Git操作時はUnityを閉じる」ルールにも従いましょう。
次に読む記事
参考資料(公式)
- Unity 6.0 Manual — ScriptableObject data assets
- Unity 6.0 Scripting API — ScriptableObject
- Unity 6.0 Manual — Unityのシリアル化









ディスカッション
コメント一覧
まだ、コメントがありません