【Unity2D】ライフ増減の仕組みを作る

Unity2D

Unity2D ARPG

このブログを始めて365日毎日更新を達成したからというものの、
現職とフリーランスの仕事が重なりゲームを作る余裕がなくなりました(笑)

ですが、忙しいを言い訳にゲーム作りを中段したくないのでめちゃくちゃ頑張って余裕を作り
ちょっとでもゲーム作りを進めていきます。

今回はライフシステムを作っていきます。

処理としては内部で数値を変更してその数値をHUDに反映させる感じですね。

Life_Managerを作り、それぞれのライフオブジェクトのスプライトを変更するように命令しましょう。

ライフ管理を作る

まずは司令塔となるLife_Managerクラスを作ります。

やることはすごく単純です。

  • 子オブジェクトである全てのライフオブジェクトのスクリプトを取得
  • プレイヤーのステートを取得して監視
  • ステートの数値を見て該当する子オブジェクトのスクリプトを操作

といった感じですね。

ライフのほかにも魔力ゲージやアイテム所持数等も操作しようと思ったのですが、
スクリプトが混雑になってしまうのを避けるためにそれぞれにマネージャーを設けるようにします。

もしそれが重い処理に繋がっていたらここに集約しようと思いますが、
一旦はそれぞれにマネージャーを持たせるという形をとりましょう。

それではLife_Managerクラスになります。

using UnityEngine;
using System.Collections;
public class Life_Manager : MonoBehaviour
{

    // プレイヤーのステータスを参照
    private State_Player _State;

    // 自身の子オブジェクト(ハート)の配列
    private Life_Children[] _Hearts;

    void Start()
    {
        // プレイヤーステートマネージャースクリプトを取得
        _State = GameObject.FindGameObjectsWithTag("State_Manager")[0].GetComponent<State_Player>();

        // ライフ分の配列初期化
        _Hearts = new Life_Children[20];

        // 子オブジェクトのスクリプトを取得
        _getChildObjScripts();


    }

    // 子オブジェクトを取得して格納
    private void _getChildObjScripts()
    {
        // ループ用変数
        int i = 0;
        foreach (Transform child in transform)
        {
            _Hearts[i] = child.GetComponent<Life_Children>();
        }
    }
}

今回はリストではなく純粋に配列クラスを使いました。

というのも、ライフオブジェクトは20個固定なのでリストにする必要はなくなりました。

微々たるさかもしれませんが可変のリストよりも固定の配列のほうが処理速度は速い(はず)なので
シンプルにわかりきっていて配列化できるところはリストを使わず配列にしておきましょう。

子オブジェクトの取得は親である自身のtransformをforeachで回すと子を取得できます。

あとはステートのライフをUpdateで監視しておき、数値が減ったら子のオブジェクトを指示するだけです。

とりあえず子を作るので親やここで一旦とめます。

子は数値を見てスプライトを変更するだけ

子オブジェクトの役割は親から渡された値をもとにスプライトを変更するだけの仕組みです。

簡単ですね!

イメージ的には指示されたプラカードを表示するだけの役目といった感じでしょうか。

  • 0はグラフィックなし
  • 1はハートが空
  • 2はハートが半分
  • 3はハートが満タン

といった具合に決めましょう。

ハートの数は20個ですが、ハート半分の概念があるので数値的には最大HP40となります。

40の時はハートマックスで39になったら最後のハートが半分になるような計算式にしておけば、
間違ったハートの減り方とかはしなくなるのでしっかりと作りこみましょう。

スプライトの変更はオブジェクト自体にスプライトを登録しておいて、
スクリプトで切り替えるというのが基本的な手法です。

宝箱の仕組みでやったことと同じすね。

using UnityEngine;

public class Life_Children : MonoBehaviour
{

    public Sprite[] m_sprite = new Sprite[4];
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }

}

Life_Childrenとなっていますが、Life_Managerの子クラスというわけではないです。

これ自体がスプライトを変更するだけの独立したスクリプトになるので、
親側からの指示で値を変更できれば良いです。

UnityEditorからいじられるようにpublicのSprite配列を作ってサイズを4としましょう。

そして先ほども言いましたが

  • 0はグラフィックなし
  • 1はハートが空
  • 2はハートが半分
  • 3はハートが満タン

でスプライトを登録しましょう。

0の時は非表示ですがSpriteがnoneだとエラーが起きそうなので、透明のスプライトを入れておくと安全かもしれません。

0なら非表示っていう仕組みにしてしまってもいいですが、スプライトを変更するだけのほうが楽なのでそうしました。

これで準備が整いましたので早速ダメージの増減をしてみましょう。

ダメージを受ける仕組みを作る

ダメージの仕組みを作るのは結構面倒くさいです。

フローチャートを考えてみましょう。

  • 判定にぶつかる
  • ダメージを受ける
  • ノックバックする
  • 点滅させる(任意)
  • 点滅中は無敵時間にする
  • 点滅を解除する

といった感じにダメージを受ける期間の制御してやる必要があります。

でないとダメージを受けた瞬間連続してダメージを受けてしまうので速攻クソゲーになります。

1つずつ作っていきましょう。

判定にぶつかる

まずは判定を作らないとどうしようもありません。

これは何度もやってきているので簡単ですね。

判定を記述するのはプレイヤーが持つスクリプトでよいかなと思ったのですが、
移動判定で使ってしまっているのでここにダメージ処理を書くと見づらくなってしまいます。

なので専用のDamage_Playerスクリプトを作りましょう。

using UnityEngine;

public class Damage_Player : MonoBehaviour
{
    // プレイヤーステートスクリプトの取得
    private State_Player _State;

    // Start is called before the first frame update
    void Start()
    {
        _State = GameObject.FindGameObjectsWithTag("State_Manager")[0].GetComponent<State_Player>();
    }

    // Update is called once per frame
    void Update()
    {
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        switch (other.tag)
        {
            case "DamageTrap":
                Debug.Log("おはようダメージ!");
                break;
        }
    }
}

モンスターや壁の出っ張りなんかの場合はOnCollision~を使いますが、
ダメージ床等の乗ることができるものはOnTrigger~を使います。

とりあえずシンプルにダメージ床を作ることにしました。

例によってドット絵はご自身でご用意ください。

シンプルに2DスプライトにBoxCollider2Dをアタッチして、
OnTriggerにチェックを入れただけのオブジェクトです。

タグは「DamageTrap」というものを作って与えています。

そこでDamage_Playerをアタッチしたプレイヤーがぶつかると、ログが出るようにしました。

Unity2D ダメージトラップ

あとはこれにダメージ処理やらノックバック処理やらを加えていく感じですね。

ダメージの仕組みを作る

今回はタイトルの通りダメージの増減を作るのが目的なのでノックバックは次回に回しましょう。

ダメージ床であればノックバック無しでその場でダメージを受けるゲームは多いので
それにならって作ってみましょう。

onTriggerEnterは入った瞬間だけ関数が動くので都合がいいですね。

プレイヤーステートはすでにStart関数で取得しているので、
判定に触れたらプレイヤーのHPを1つ減らしてみましょう。

using UnityEngine;

public class Damage_Player : MonoBehaviour
{
    // プレイヤーステートスクリプトの取得
    private State_Player _State;

    // Start is called before the first frame update
    void Start()
    {
        _State = GameObject.FindGameObjectsWithTag("State_Manager")[0].GetComponent<State_Player>();
    }

    // Update is called once per frame
    void Update()
    {
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        switch (other.tag)
        {
            case "DamageTrap":
                _State.setPlayerStatus(_State.getPlayerStatus(0) - 1, 0);
                Debug.Log("HP残り");
                Debug.Log(_State.getPlayerStatus(0));
                break;
        }
    }
}

入りなおすたびにダメージが減っていっていますね。

あとはこの数値が変化したらHUDに通知がいくようにしてLife_Managerが子のスプライトを変更させてハートの減少を実現します。

今回はここまでにしておきましょう。

次回は無敵時間とノックバックの実装をしてみましょう。

Unity2D ダメージトラップ2

それでは!