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

広告

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

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の基本です。

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 を呼ぶ」というコードに対応していると分かります。

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で設定するか、必要に応じて設定用のメソッドを用意します。

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の減り方を確認しましょう
訪問数 2 回, 今日の訪問数 1回

広告

Unity

Posted by hidepon