NPCの移動と武器【UnityでRTSを作る 3】
今日はNPCの移動及び武器を実装しました。
NPCの移動処理
これは前回の記事で紹介したCubeKunクラスを継承させてMoveTo(移動のための汎用関数)にターゲットの位置を渡してあげるだけなので簡単でした。
NPC.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { public class NPC : CubeKun { private new void Update () { if (target) MoveTo(target.position); } } }
武器
弾の処理
武器から発射する弾のコードです。
弾のステータスと単純な移動処理だけです。
Bullet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { [RequireComponent(typeof(BoxCollider))] public class Bullet : MonoBehaviour { public Transform Tr { get { return _Tr ? _Tr : (_Tr = transform); } } private Transform _Tr; public int power = 20; public float speed = 10; private void Update () { Tr.Translate(Tr.forward * speed * Time.deltaTime,Space.World); } } }
武器による弾の発射
武器には弾の発射と、その処理を一定間隔でループさせるためのコルーチンを実装します。
Weapon.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { public class Weapon : MonoBehaviour { public Transform[] firingPoints; public float interval = 0.5f; [Header("Bullet Settings")] public Bullet bullet; public int power = 20; public float speed = 5; public float time = 5; private Coroutine shootCoroutine = null; private void Start () { ShootStart(); } public void ShootStart () { if (shootCoroutine == null) shootCoroutine = StartCoroutine(ShootCoroutine()); } public void ShootStop () { if (shootCoroutine == null) return; shootCoroutine = null; StopCoroutine(shootCoroutine); } public void Shoot () { for (int i = 0;firingPoints.Length > i;i++) { var ins = Instantiate(bullet); ins.Tr.position = firingPoints[i].position; ins.Tr.rotation = firingPoints[i].rotation; ins.power = power; ins.speed = speed; Destroy(ins.gameObject,time); } } private IEnumerator ShootCoroutine () { while (true) { Shoot(); yield return new WaitForSeconds(interval); } } } }
体力
武器があっても減る体力が無いと意味がないので、体力を実装するHealthクラスを用意します。
Health.cs
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace MackySoft.CubeKunWars { [Serializable] public class OnValueChangedEvent : UnityEvent<int> { } public class Health : MonoBehaviour { [SerializeField] private int _Value = 100; [Header("Events")] public OnValueChangedEvent onValueChanged; public UnityEvent onDie; public int Value { get { return _Value; } set { _Value = value > 0 ? value : 0; onValueChanged.Invoke(Value); if (IsDead) onDie.Invoke(); } } public bool IsDead { get { return Value == 0; } } private void OnValidate () { Value = _Value; } } }
それに従ってCubeKunクラスに「弾に当たった時にダメージを受ける」処理を追加しました。
CubeKun.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Pathfinding; namespace MackySoft.CubeKunWars { [RequireComponent(typeof(Health))] [RequireComponent(typeof(Rigidbody))] public abstract class CubeKun : AIPath { public float sleepVelocity = 0.4F; public Transform Tr { get; private set; } public Rigidbody Rigid { get; private set; } public Health Health { get; private set; } protected override void Awake () { base.Awake(); Tr = transform; Rigid = GetComponent<Rigidbody>(); Rigid.constraints = RigidbodyConstraints.FreezeAll; Health = GetComponent<Health>(); Health.onDie.AddListener(() => Destroy(gameObject)); } protected virtual void OnCollisionEnter (Collision collision) { var bullet = collision.gameObject.GetComponent<Bullet>(); if (bullet) { Health.Value -= bullet.power; Destroy(bullet.gameObject); } } public void MoveTo (Vector3 position) { if (canMove) { var dir = CalculateVelocity(GetFeetPosition()); RotateTowards(targetDirection); dir.y = 0; if (dir.sqrMagnitude > sleepVelocity * sleepVelocity) { } else { dir = Vector3.zero; } Tr.Translate(dir * Time.deltaTime,Space.World); } } public override Vector3 GetFeetPosition () { return Tr.position; } } }