【Unity入門】Statusコンポーネントを作って、GameObjectにHPを持たせよう

2026年10月5日

広告

ゲームを作っていると、「プレイヤーにHPを持たせたい」「敵にも体力を持たせたい」という場面が必ず出てきます。

ゲームでいう「ステータス」とは、HPやMP、攻撃力など、そのキャラクターが持っている情報のことです。この記事では、その情報をまとめて持つ Status というコンポーネントを作ります。

Unityでは、こうした「性質」を コンポーネント として作り、GameObjectにアタッチすることで持たせます。この記事では、HPを持つ Status コンポーネントを作りながら、Unityらしい考え方を体験していきます。

Inspectorで、PlayerにStatusコンポーネントを付けるとHPを持たせられることを説明するイラスト

1. Statusスクリプトを作る

Projectウィンドウで C# スクリプトを作成し、名前を Status にします。中身は次のとおりです。

using UnityEngine;

public class Status : MonoBehaviour
{
    public int Hp = 100;
}

ポイントは3つです。

  • MonoBehaviour を継承しているので、GameObjectにアタッチできる
  • public を付けたので、Inspectorに表示され、数値を変更できる
  • = 100 は初期値

ファイル名とクラス名は必ず同じにしてください。違うとアタッチできません。

2. Playerにアタッチする

  1. Hierarchyで Player というGameObjectを用意する(2Dスプライトでも、3Dの立方体でもかまいません)
  2. 作成した Status スクリプトを、Inspectorにドラッグ&ドロップする
  3. Inspectorに Status コンポーネントが追加され、Hp の欄に 100 と表示される

これで、PlayerはHPを持つGameObjectになりました。Inspectorで数値を書き換えれば、ゲームを動かさなくてもHPを調整できます。

3. 「Statusを付けるとHPを持てる」のがコンポーネント

このとき、Playerの中身はこうなっています。

Player
 ├ Transform
 ├ SpriteRenderer
 ├ Rigidbody2D
 └ Status
      └ Hp = 100

ここで大切なのは、HPをPlayerクラスそのものに埋め込んでいない ことです。

  • 見た目を出すのは SpriteRenderer
  • 物理的な動きは Rigidbody2D
  • HPなどの数値は Status

というように、役割ごとに部品(コンポーネント)を組み合わせてGameObjectを作ります。「あの部品を付ければ、あの機能が使える」という考え方が、Unityの基本です。実際にどんな部品が付いているかは、GameObjectには何が付いている? GetComponentsでComponent一覧を表示してみよう【Unity】で確認できます。

4. Statusを増やしてみよう

HPだけでなく、攻撃力や防御力も持たせてみましょう。

using UnityEngine;

public class Status : MonoBehaviour
{
    public int Hp = 100;
    public int Attack = 10;
    public int Defense = 5;
}
HP・MP・こうげき・ぼうぎょ・すばやさ・レベルを表示したステータス画面のイラスト

こうしておくと、PlayerにもEnemyにも同じ Status を付けるだけで、同じ仕組みを持たせられます。

GameObjectHpAttackDefense
Player100105
Enemy3082

スクリプトは1つだけ。数値はGameObjectごとにInspectorで変えられます。「クラスを増やさなくても、部品の組み合わせと設定値でキャラクターを作り分けられる」ことが体感できます。

5. スクリプトからStatusを追加する(AddComponent)

ここまではInspectorで操作しましたが、スクリプトから同じことをする方法もあります。

using UnityEngine;

public class PlayerCreator : MonoBehaviour
{
    void Start()
    {
        GameObject obj = new GameObject("Player");

        Status status = obj.AddComponent<Status>();
        status.Hp = 100;

        Debug.Log(obj.name + "のHP:" + status.Hp);
    }
}
  • new GameObject("Player") で、空のGameObjectを作る
  • AddComponent<Status>() で、Statusコンポーネントを追加する。戻り値は追加されたStatusなので、変数に受け取れる
  • status.Hp = 100; で、外からHPの値を設定する

Inspectorでドラッグ&ドロップしていた操作が、「AddComponent を呼ぶ」というコードに対応していると分かります。new GameObject() からComponentを組み合わせる流れは、new GameObject()から作ってみよう ― UnityのComponentはどう組み合わさるのかで詳しく解説しています。

「new Status()」と書きたくなったら

これまでのC#では、クラスは new でオブジェクトを作りました。そのため、Status も new Status() と書きたくなるかもしれません。普通のクラスと比べてみましょう。

// 普通のC#クラスなら
StatusData data = new StatusData();
data.Hp = 100;

// MonoBehaviourなら(GameObjectに付けて存在させる)
Status status = gameObject.AddComponent<Status>();
status.Hp = 100;

「普通のクラスは new、MonoBehaviourは AddComponent」と覚えてください。MonoBehaviourは、GameObjectに付けて初めて存在するComponentです。

MonoBehaviourを new で作ろうとすると、Unityが警告を出します。作られたStatusはどのGameObjectにも付いておらず、Start や Update も呼ばれません。

6. publicのままで大丈夫?

public int Hp は手軽ですが、実は どのスクリプトからでも自由に書き換えられる という弱点があります。

// どこかのスクリプトで、うっかり書いてしまった例
status.Hp = -9999;

HPがマイナスになったり、意図せず全回復したりするバグの原因になります。そこで、次のように書き換えます。

using UnityEngine;

public class Status : MonoBehaviour
{
    [SerializeField]
    private int hp = 100;

    public int Hp => hp;

    public void TakeDamage(int damage)
    {
        hp -= damage;
        if (hp < 0)
        {
            hp = 0;
        }
    }
}
  • [SerializeField] を付けると、private でもInspectorに表示され、数値を設定できる
  • private なので、外のスクリプトから直接書き換えられない
  • public int Hp => hp; は「読み取り専用」の窓口。外からはHPを読めるが、書き換えはできない
  • HPを減らすときは TakeDamage を呼ぶ。0未満にならないよう、Status自身が守る

使う側は次のようになります。

Status status = GetComponent<Status>();
status.TakeDamage(20);
Debug.Log(status.Hp); // 80

注意点として、private にしたあとは、5章の status.Hp = 100; のような書き方はできなくなります(読み取り専用のため、エラーになります)。初期値を変えたいときは、Inspectorで設定するか、必要に応じて設定用のメソッドを用意します。publicとprivateの考え方(カプセル化)は、C#のカプセル化とは?Studentクラスのpublicをprivateに変えて理解しようで、イラスト付きの解説は【イラストでわかる】C#のカプセル化を初心者向けに徹底解説で確認できます。

7. まとめ

  • Status のような自作コンポーネントを作り、アタッチすることで、GameObjectに性質を持たせられる
  • まずは public int Hp で、「Inspectorに出して数値を変えられる」ことを体験する
  • 同じ Status をPlayerにもEnemyにも付けて使い回せる
  • AddComponent<Status>() で、スクリプトからもコンポーネントを追加できる
  • 慣れてきたら [SerializeField] private と TakeDamage のようなメソッドで、安全に値を守る

「何でも1つのクラスに詰め込む」のではなく、「部品を組み合わせる」という感覚を、ぜひ身につけてください。

あわせて読みたい

練習問題

  1. Status に Mp を追加し、Inspectorに表示されることを確認してみましょう
  2. Enemyを作り、Hp = 30 の Status を付けてみましょう
  3. Status に回復用の Heal(int amount) メソッドを追加してみましょう。ただし、最大HPを超えないようにしてください(ヒント:maxHp を別に用意します)
  4. キーを押したらPlayerの TakeDamage(10) が呼ばれるスクリプトを書き、ConsoleでHPの減り方を確認しましょう

解答例

まず自分で考えて、コードを書いてから開いてみてください。書き方は1つではありません。動いていれば、違う書き方でも正解です。

問題1の解答例(Mpを追加する)

4章までの public 版の Status に、1行足すだけです。

using UnityEngine;

public class Status : MonoBehaviour
{
    public int Hp = 100;
    public int Mp = 50;
    public int Attack = 10;
    public int Defense = 5;
}

保存してUnityに戻ると、Inspectorの Status に Mp の欄が増えています。

問題2の解答例(EnemyにHp = 30のStatusを付ける)

新しいスクリプトは作りません。Playerと同じ Status を使い回します。

  1. Hierarchyで右クリックし、新しいGameObjectを作って、名前を Enemy にする
  2. Status スクリプトを、Enemy のInspectorにドラッグ&ドロップする
  3. Status の Hp を 30 に書き換える

PlayerとEnemyで、同じスクリプトなのに値が違うことを確認してください。

問題3の解答例(Healメソッドを追加する)

6章の private 版の Status に、maxHp と Heal を足します。

using UnityEngine;

public class Status : MonoBehaviour
{
    [SerializeField]
    private int maxHp = 100;

    [SerializeField]
    private int hp = 100;

    public int Hp => hp;

    public void TakeDamage(int damage)
    {
        hp -= damage;
        if (hp < 0)
        {
            hp = 0;
        }
    }

    public void Heal(int amount)
    {
        hp += amount;
        if (hp > maxHp)
        {
            hp = maxHp;
        }
    }
}

回復したあとにHPが最大HPを超えていたら、最大HPに戻します。TakeDamage で0未満にならないようにしたのと、同じ考え方です。

1行で書くなら、hp = Mathf.Min(hp + amount, maxHp); でも同じ結果になります。

問題4の解答例(キーを押したらダメージを受ける)

Playerに Status と、次の DamageTest スクリプトを付けます。キー入力には、このシリーズで使っているInput Systemを使います。

using UnityEngine;
using UnityEngine.InputSystem;

public class DamageTest : MonoBehaviour
{
    private Status status;

    void Start()
    {
        status = GetComponent<Status>();
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            status.TakeDamage(10);
            Debug.Log("HP:" + status.Hp);
        }
    }
}

ゲームを再生してスペースキーを押すと、Consoleに HP:90、HP:80 と表示されます。HPが0より下がらないことも確かめてみましょう。

注意:古い Input.GetKeyDown は、Input Systemだけを有効にしたプロジェクトではエラーになります。エラーが出たら、Project Settingsの Player にある「Active Input Handling」の設定を確認してください。

訪問数 22 回, 今日の訪問数 1回

広告

Unity

Posted by hidepon