18
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-02-22

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

UnityのComponent、NavMeshAgentを使用します。

想定するゲーム

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

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

ezgif.com-video-to-gif.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)
を設定してください!
コード内の数値も自分の好きなようにいじってみると良いと思います。

スクリーンショット 2019-02-23 3.03.48.png ↑この3つです

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

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

GitHub

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

GitHub

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

18
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?