今回はUnityで、クラロワのようなタワーディフェンスゲームを作る上で、一番近い敵に攻撃しにいくキャラクターの挙動の実装方法を載せます。
UnityのComponent、NavMeshAgentを使用します。
想定するゲーム
今回想定するゲームは、
・Player vs Enemy、相手の城を倒したら勝ち
・お互いのキャラは、一番近い敵(城含む)に攻撃しにいく
という感じです。イメージは以下のgif参照。
(上下にある赤い四角がそれぞれの城。丸がEnemy、四角がPlayer。近くの敵を攻撃して敵の城を目指しています。クラロワみたいな感じ)
実装方法
前提
・フィールドにNavMeshでBakeが行われていること
・キャラクター・城のオブジェクトにそれぞれPlayer、Enemyのタグがつけられていること
・キャラクターにNavMeshAgentコンポーネントをつけていること
以下のコードをキャラクターにアタッチする
以下のコード(Character.cs)をキャラクターとなるゲームオブジェクトにアタッチします
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を作って、
public int hp = xxx; //(数字を設定する)
という感じで城にアタッチする必要があります。
Character.csをアタッチした後は、Inspector上で
・攻撃力(Attack)
・体力(HP)
・攻撃するキャラのタグ(Enemy or Player)
を設定してください!
コード内の数値も自分の好きなようにいじってみると良いと思います。

ちゃんと近い敵に向かって動き、攻撃してくれると思います!
攻撃・移動アニメーションやデッキ機能、キャラ生成などを作ると見た目もしっかりとしたタワーディフェンスゲームができるのではと思います!是非役立ててください。
GitHub
コードだけだとよくわからなかった、という方のためにサンプルプロジェクトをあげておきます。(キャラクターは自動生成)
少しでも参考になれば嬉しいです。以上です!