Skip to main content

ゾンビを実装

主人公を追いかける「ゾンビ」を実現しましょう!

シーンの設定

ゲームオブジェクトと3Dモデル

Timmyと同様に、ゾンビのゲームオブジェクトを作成しましょう。空のゲームオブジェクトを作成し、その下に子オブジェクトとしてZombieのモデルを追加する:

image.png

ただし、ゾンビは物理的に動かないので、コライダーとリジッドボディが要らない。ゾンビの動かした方については、下記で説明する。

アニメーション

今回は、アニメーションは1つしかなくて、ずっと歩くようにしましょう。ただし、Timmy と同様に「アバター」の設定が必要。

image.png

image.png

そして、ゾンビのアニメーターコントローラーを作成し、「ZombieWalk」のアニメションをデフォルトにする

image.png

これで実行してみてください(ループを忘れずに~)

自動的に道を探し「自動的に道を探す「ナビゲーション」

人間を制御するキャラクターが、当たり判定を確認するだけで、動きの実装ができる。人間が勝手に障害物などを避けて動く。一方、CPUキャラクターがとても馬鹿であり、障害物を避けたらすることができない。

この問題を解決するには、Unityが「Navigation」(ナビゲーション)を提供する。ナビゲーションとは、自動車のナビと同じように、目的地を設定し、最適なルートを探す処理である。

ナビゲーションは以下の主なコンポーネントを組み合わせて、作成する

    ナビゲーションメッシュ(NavMesh Surface):ナビの「地図」歩けるところ、歩けないところを指定する エージェント(NavMesh Agent):地図の上に動くもの。一般的に、CPUキャラクターである

    その他にも、ナビゲーションの影響にあるコンポーネント(NavMesh Link、NavMesh Obstacle、など)もあるが、最低限でこの2つの組み合わせで十分。

    ナビゲーションメッシュ(NavMesh Surface)

    ナビの地図である。地図を作るのは、シーンを固定してから!シーンが変わったら(壁を増やした、障害物の位置を変えた)、地図も更新しないといけないので、ご注意ください。

    まず、地図に使うオブジェクトをグループ化にしないといけないので、シーンを整理し、ゾンビと主人公の間にいくつかの壁を作ってみましょう。空ゲームオブジェクト「Stage」を作成し、中には床面、ランプそして新しい壁を追加してください。

    image.png

    ここで「ナビゲーションメッシュ」を作りましょう。「Stage」を選択し、「NavMesh Surface」を追加してください

    image.png

    ここで地図を作る時に必要なパラメータを設定できるが、最も重要なのは、何を基づいて地図を作るのか。これは「Object Collection」から設定ができる。今回は「Stageとその子オブジェクトを使用」にしたいので「Current Object Hierarchy」(現在オブジェクトのヒエラルキー)を選択しましょう。

    そして、ナビゲーションメッシュを作成するには「Bake」(焼く)ボタンを押すだけ。このボタンを押すと、Stageとその子オブジェクトのすべてを処理し、歩ける「地図」を水色で表示される:

    image.png

    壁にあまり近づかないよう、周囲に「歩けない」領域が現れる。この地図が焼いているので、ステージが変わっても地図が変わらない! 1つの壁を削除しても、「歩けない」領域が残る:

    image.png

    ナビゲーションメッシュを焼いた後にシーンが変わったら、もう一度「Bake」してください。

    エージェント(NavMesh Agent)

    障害物(

    エージェントは、水色の「地図」(ナビゲーションメッシュ)上で歩くものである。目的地を設定すれば、現在地から最適な道を探し、自動的に動く。

    今回のゲームで、ゾンビが動いてほしいので、エージェントにしましょう。ゾンビ(親オブジェクト)に「NavMesh Obstacle)Agent」を追加してください。

    image.png

    ここでエージェントのパラメータを調整ができる。主なパラメータは:

    Base Offset(基礎オフセット) 足元からの「ずれ」 Speed(速度) 移動速度 Angular Speed(回転速度) 向きを変える速度 Acceleration(加速度) 加速と減速の速さ Stopping Distance(停止距離) 目的地までこの距離になったら止まる Radius(半径) エージェントの「太さ」 Height(高さ) エージェントの「身長」

    とりあえず、ゾンビの速度を「1」にし、残りのパラメータをそのままにしましょう。

    スクリプト

    プレーヤーを追いかける

    スクリプトは、プレーヤーの位置を求め、エージェントの目的地を設定するだけ。「PlayerChase」のスクリプトは以下の通りである:

    using UnityEngine;
    using UnityEngine.AI;
    
    // プレーヤーを追いかける
    public class PlayerChase : MonoBehaviour
    {
        // 追いかけるプレーヤー
        private GameObject player;
        
        // エージェントの目的地を設定するため
        private NavMeshAgent agent;
        
        private void Start()
        {
            // 後ほどプレハブにするので、Unityで紐づけせず、
            // 実行中にプレーヤーを探す
            player = GameObject.Find("Player");
    
            // NavMeshAgentのコンポネント取得
            agent = GetComponent<NavMeshAgent>();
        }
    
        private void Update()
        {
            // 追いかける
            // SetDestination はエージェントの目的地を設定するメソッド。
            // 引数はその位置である(プレーヤーの位置)
            agent.SetDestination(player.transform.position);
        }
    }
    

    このスクリプトを Zombie にアッタッチし、実行してみてください。

    体力スクリプトTimmyの体力

    これで、追いかけるようになったが、ゾンビが主人公を捕まっても、なにもならない。Timmyの体力を実装しましょう。「HitPoints」のスクリプトは以下の通りである:

    // 体力を管理するクラス
    public class HitPoints : MonoBehaviour
    {
        // 体力
        private int hp = 3;
    }

    当たり判定とダメージ

    ここでトリガーを活用ができる。もし、HitPoints がダメージの起源(ゾンビ、罠、炎など)と重なったら、ダメージを受ける。どれぐらい受けるのかをその「ダメージの起源」(DamageSource)で指定ができる

    image.png

    まず、ダメージの起源を作成しましょう:

    // ダメージの起源
    public class DamageSource : MonoBehaviour
    {
        // ダメージの量
        [SerializeField] 
        private int damage;
        
        // ダメージの量(読み込む専用)
        public int GetDamage()
        {
            return damage;
        }
    }

    そして、HitPoints スクリプトは:

    // 体力を管理するクラス
    public class HitPoints : MonoBehaviour
    {
        // 体力
        private int hp = 3;
    
        // トリガーに入ったら
        private void OnTriggerEnter(Collider other)
        {
            // ダメージの起源かどうかを確認
            DamageSource src = other.GetComponent<DamageSource>();
            if (src == null)
                return;
          
            // 体力を減らし、0 以下にならないように制限する
            hp = Mathf.Max(0, hp - src.GetDamage());
        }
    }

    確認

    確認するには、ゾンビにダメージの起源を追加しなければならない。Zombieに新しい子オブジェクトを追加し、トリガーと DamageSource を追加してください

    image.png

    そして、Player に HitPoints を追加し、Debug.Log で体力を表示してください。

    UIの更新(体力)

    アタッチ、紐づけ、確認