# ゾンビを実装

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

## シーンの設定

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

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

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/yPcimage.png)

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

#### アニメーション

今回は、アニメーションは１つしかなくて、ずっと歩くようにしましょう。ただし、Timmy と同様に「[アバター](https://class.illogic.games/books/b9228/page/8cb22#bkmrk-avatar-%E3%81%A8%E3%81%AF)」の設定が必要。

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/o61image.png)

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/dFAimage.png)

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

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/Tmgimage.png)

これで実行してみてください（ループを忘れずに～）

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

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

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

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

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

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

#### ナビゲーションメッシュ（NavMesh Surface）

ナビの地図である。<span style="color: rgb(186, 55, 42);">**地図を作るのは、シーンを固定してから**</span>！シーンが変わったら（壁を増やした、障害物の位置を変えた）、地図も更新しないといけないので、ご注意ください。

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

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/6Ywimage.png)

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

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/ywVimage.png)

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

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

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/7aDimage.png)

壁にあまり近づかないよう、周囲に「歩けない」領域が現れる。この地図が焼いているので、<span style="color: rgb(186, 55, 42);">**ステージが変わっても地図が変わらない！** </span>１つの壁を削除しても、「歩けない」領域が残る：

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/LCPimage.png)

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

#### エージェント（NavMesh Agent）

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

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

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/E0Oimage.png)

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

<table border="1" class="align-center" id="bkmrk-base-offset%EF%BC%88%E5%9F%BA%E7%A4%8E%E3%82%AA%E3%83%95%E3%82%BB%E3%83%83%E3%83%88%EF%BC%89" style="border-collapse: collapse; width: 72.8571%; border-width: 1px;"><colgroup><col style="width: 41.8666%;"></col><col style="width: 58.0789%;"></col></colgroup><tbody><tr><td class="align-left">Base Offset（基礎オフセット）</td><td class="align-left">足元からの「ずれ」</td></tr><tr><td class="align-left">Speed（速度）</td><td class="align-left">移動速度</td></tr><tr><td class="align-left">Angular Speed（回転速度）</td><td class="align-left">向きを変える速度</td></tr><tr><td class="align-left">Acceleration（加速度）</td><td class="align-left">加速と減速の速さ</td></tr><tr><td class="align-left">Stopping Distance（停止距離）</td><td class="align-left">目的地までこの距離になったら止まる</td></tr><tr><td class="align-left">Radius（半径）</td><td class="align-left">エージェントの「太さ」</td></tr><tr><td class="align-left">Height（高さ）</td><td class="align-left">エージェントの「身長」</td></tr></tbody></table>

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

## スクリプト

### プレーヤーを追いかける

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

```c#
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」のスクリプトは以下の通りである：

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

### 当たり判定とダメージ

ここでトリガーを活用ができる。もし、`HitPoints` がダメージの<span class="HwtZe" lang="ja"><span class="jCAhz ChMk0b"><span class="ryNqvb">起源（ゾンビ、罠、炎など）と重なったら、ダメージを受ける。どれぐらい受けるのかをその「ダメージの起源」（`DamageSource`）で指定ができる</span></span></span>

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/kcDimage.png)

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

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

そして、`HitPoints` スクリプトは：

```c#
// 体力を管理するクラス
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](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/KPTimage.png)

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

## UIの更新（体力）

`Debug.Log`でカッコ悪いので、UIも作成しましょう。画面の左に、3つのハート画像をグループとして配置しましょう

![image.png](https://class.illogic.games/uploads/images/gallery/2026-06/scaled-1680-/nuXimage.png)

そして、`UIManager` を更新し、ハートの表示・非表示しましょう。

```c#
// UIを管理する
public class UIManager : MonoBehaviour
{
    // コインのテキスト
    [SerializeField] 
    private TextMeshProUGUI coinText;
    
    // 鍵のテキスト
    [SerializeField] 
    private TextMeshProUGUI keyText;

    // ハートの配列
    [SerializeField] 
    private GameObject [] hearts;

    // 表示したいハートの数
    public void SetHearts(int count)
    {
        for(int i = 0; i < hearts.Length; i++)
            hearts[i].SetActive(i < count);
    }

    // （省略）
}

```

`SetHearts` は[ブロック崩しゲームの「SetLives」](https://class.illogic.games/link/24#bkmrk-%E6%AE%8B%E6%A9%9F-1)と同じ処理であるが、書き方を短くしただけである。後は、`HitPoints` の体力が変わったら、UI を更新するにで、 `HitPoints` を修正しましょう：

```c#
using UnityEngine;

// 体力を管理するクラス
public class HitPoints : MonoBehaviour
{
    // 体力を表示するため
    [SerializeField] 
    private UIManager uiManager;
    
    // 体力
    private int hp = 3;

    private void Start()
    {
        uiManager.SetHearts(hp);
    }

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