【Unity】 タワーディフェンスゲームのキャラの挙動を実装する 

今回はUnityで、**クラロワのようなタワーディフェンスゲーム**を作る上で、**一番近い敵に攻撃しにいく**キャラクターの挙動の実装方法を載せます。

UnityのComponent、[NavMeshAgent](https://docs.unity3d.com/ja/2017.4/ScriptReference/AI.NavMeshAgent.html)を使用します。

#想定するゲーム

今回想定するゲームは、
・Player vs Enemy、相手の城を倒したら勝ち
・お互いのキャラは、一番近い敵（城含む）に攻撃しにいく

という感じです。イメージは以下のgif参照。

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.amazonaws.com/0/360619/50c8f6a6-bd43-5934-1b8b-7108f19edc86.gif)


（上下にある赤い四角がそれぞれの城。丸がEnemy、四角がPlayer。近くの敵を攻撃して敵の城を目指しています。クラロワみたいな感じ）

#実装方法

###前提

・フィールドにNavMeshでBakeが行われていること
・キャラクター・城のオブジェクトにそれぞれPlayer、Enemyのタグがつけられていること
・キャラクターにNavMeshAgentコンポーネントをつけていること

###以下のコードをキャラクターにアタッチする

以下のコード（Character.cs）をキャラクターとなるゲームオブジェクトにアタッチします

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]

public class Character : MonoBehaviour
{
    private GameObject target;
    private NavMeshAgent agent;
    [SerializeField] private GameObject[] enemies;
    [SerializeField] private string attackTag; //Inspectorで設定
    private float stopDistance;
    private float attackTimer;
    private bool isAttack;
    //ここから
    public int hp; 
    public int power;
    //ここまでInspectorで設定
    private enum targetType
    {
        normal,
        castle
    }
    private targetType currentTargetType;

    private void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
    }
    private void Start()
    {
        target = GameObject.Find(attackTag + "Castle");
        isAttack = false;
    }
    private void Update()
    {
        if (target == null)
        {
            target = GameObject.Find(attackTag + "Castle");
        }

        SetStopDistance();
        FintTarget();
        agent.SetDestination(target.transform.position);

        if (Vector3.Distance(transform.position, target.transform.position) <= stopDistance)
        {
            isAttack = true;
            agent.speed = 0;
        }

        if (isAttack)
        {
            CheckNearTarget(); 
            SetStopDistance(); //攻撃中にtargetが変わった時のためにここでも記述
            Attack();
        }
    }
    //targetが近くにいるのかどうか判定する
    private void CheckNearTarget()
    {
        if (Vector3.Distance(transform.position, target.transform.position) > stopDistance)
        {
            isAttack = false;
            agent.speed = 1;
        }
    }
    private void SetStopDistance()
    {
        if (target.gameObject.name.Contains("Castle"))
        {
            currentTargetType = targetType.castle;
            stopDistance = 2f;
        }
        else
        {
            currentTargetType = targetType.normal;
            stopDistance = 0.7f;
        }
    }
    private void FintTarget()
    {
        enemies = GameObject.FindGameObjectsWithTag(attackTag);

        float closestDistance = Vector3.Distance(transform.position, target.transform.position);

        foreach (GameObject enemy in enemies)
        {
            if (Vector3.Distance(transform.position, enemy.transform.position) < closestDistance)
            {
                target = enemy;
            }
        }
    }
    private void Attack()
    {
        attackTimer += Time.deltaTime;
        switch (currentTargetType)
        {
            case (targetType.normal):
                if (attackTimer > 1.0f)
                {
                    target.GetComponent<Character>().hp -= power;
                    attackTimer = 0f;
                }
                if (target.GetComponent<Character>().hp <= 0)
                {
                    isAttack = false;
                    Destroy(target.gameObject);
                    agent.speed = 1;
                }
                break;
            case (targetType.castle):
                if (attackTimer > 1.0f)
                {
                    target.GetComponent<Castle>().hp -= power;
                    attackTimer = 0f;
                }
                break;
        }
    }
}
```


また、このコード内で**Castleクラスのhpを減らす**という指示をしているので、

**Castle.csを作って、**

```C#
public int hp = xxx; //(数字を設定する)
```
という感じで城にアタッチする必要があります。

Character.csをアタッチした後は、Inspector上で

・攻撃力（Attack）
・体力（HP）
・攻撃するキャラのタグ（Enemy or Player）
を設定してください！
コード内の数値も自分の好きなようにいじってみると良いと思います。

<img width="355" alt="スクリーンショット 2019-02-23 3.03.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/360619/16da0260-cc32-f063-cc11-ce6942853bf2.png">
↑この３つです

ちゃんと近い敵に向かって動き、攻撃してくれると思います！

攻撃・移動アニメーションやデッキ機能、キャラ生成などを作ると見た目もしっかりとしたタワーディフェンスゲームができるのではと思います！是非役立ててください。


#GitHub

コードだけだとよくわからなかった、という方のためにサンプルプロジェクトをあげておきます。（キャラクターは自動生成）

[GitHub](https://github.com/kaku710/TowerDeffenseSample)



少しでも参考になれば嬉しいです。以上です！