前回までの作業で敵キャラ制作の下準備ができました。ここではC#スクリプトを書き、実際にゾンビが動くようにしていきます。
ゾンビの動きの仕様
まず、スクリプトを作る前にゾンビの動きの仕様を整理しておきます。今回のFPSでの敵キャラクターの動きは次のようになっています。
- ターゲットに向かって、障害物を避けながら歩く
- プレイヤーと接触した場合は攻撃を行う。攻撃されると残弾数が減る
- 弾が当たるとダメージ。HPが0になると倒れ、指定した時間が経つと消滅する
ではこれをスクリプトに落とし込んでいきましょう。
敵キャラクター用のC#スクリプト
今回私が書いたC#スクリプトは次の通りです。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody))] [RequireComponent(typeof(NavMeshAgent))] public class EnemyController : MonoBehaviour { public bool moveEnabled = true; [SerializeField] int maxHp = 3; [SerializeField] int ammoDamage = 5; [SerializeField] int attackInterval = 1; [SerializeField] int score = 100; [SerializeField] string targetTag = "Player"; [SerializeField] float deadTime = 3; bool attacking = false; int hp; float moveSpeed; Animator animator; BoxCollider boxCollider; Rigidbody rigidBody; NavMeshAgent agent; Transform target; GameManager gameManager; FirstPersonGunController player; public int Hp { set { hp = Mathf.Clamp(value, 0, maxHp); if(hp <= 0) { StartCoroutine(Dead()); } } get { return hp; } } void Start() { animator = GetComponent<Animator>(); boxCollider = GetComponent<BoxCollider>(); rigidBody = GetComponent<Rigidbody>(); agent = GetComponent<NavMeshAgent>(); target = GameObject.FindGameObjectWithTag(targetTag).transform; gameManager = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameManager>(); player = GameObject.FindGameObjectWithTag("Player").GetComponentInChildren<FirstPersonGunController>(); InitCharacter(); } void Update() { if (moveEnabled) { Move(); } else { Stop(); } } void InitCharacter() { Hp = maxHp; moveSpeed = agent.speed; } void Move() { agent.speed = moveSpeed; animator.SetFloat("Speed", agent.speed, 0.1f, Time.deltaTime); agent.SetDestination(target.position); rigidBody.velocity = agent.desiredVelocity; } void Stop() { agent.speed = 0; animator.SetFloat("Speed", agent.speed, 0.1f, Time.deltaTime); } IEnumerator Dead() { moveEnabled = false; Stop(); gameManager.Score += score; animator.SetTrigger("Dead"); boxCollider.enabled = false; rigidBody.isKinematic = true; yield return new WaitForSeconds(deadTime); Destroy(gameObject); } private void OnCollisionEnter(Collision collision) { if(collision.gameObject.tag == "Player") { StartCoroutine(AttackTimer()); } } IEnumerator AttackTimer() { if (!attacking) { attacking = true; moveEnabled = false; animator.SetTrigger("Attack"); player.Ammo -= ammoDamage; yield return new WaitForSeconds(attackInterval); attacking = false; moveEnabled = true; } yield return null; } }
書けたらこれをゾンビにアタッチしてください。
スクリプトの解説
Move()メソッド
敵キャラクターを動かします。ナビメッシュエージェントのSetDestination()メソッドで目標地点を設定し、そちらへの速度を計算するようにしています。そしてナビメッシュエージェントのdesiredVelocityから計算済みの速度を取得できるので、これをリジッドボディのvelocityに代入して移動処理を行っています。
Stop()メソッド
敵キャラクターの動きを止めます。
Dead()メソッド
死亡時の処理を行います。キャラクターの動きを止めたり、コライダーを無効化したり、倒れるアニメーションを設定したりします。
AttackTimer()メソッド
攻撃間隔を制御するコルーチンです。これがないとプレイヤーがゾンビに接触している間はモリモリ弾が減ることになりプレイヤーが不利になりすぎます。
実際の動き
これで敵キャラクターができました。テストプレイして下の動画のようにきちんと動いていればOKです。
※まだ与ダメージ処理を作っていないので現時点ではゾンビを撃っても倒すことができません。その辺の処理はこの後のページ「クリア・ゲームオーバー条件の設定&敵へのダメージ処理の追加」で追加します。
次のページ→敵キャラ生成オブジェクトの作り方