using UnityEngine; // 攻撃対象を探して近づき、攻撃距離で攻撃する [RequireComponent(typeof(DamageReceiver))] [RequireComponent(typeof(HitReaction))] public class EnemyController : MonoBehaviour { [Tooltip("敵の現在の状態")] [SerializeField] private EnemyState state = EnemyState.Idle; [Tooltip("敵自身の攻撃処理")] [SerializeField] private CharacterAttack characterAttack; [Tooltip("攻撃対象を探す範囲")] [SerializeField] private float searchRadius = 30f; [Tooltip("攻撃対象へ近づく速度")] [SerializeField] private float moveSpeed = 3f; [Tooltip("この距離以内に入ったら攻撃する")] [SerializeField] private float attackDistance = 1.5f; [Tooltip("攻撃を繰り返す間隔")] [SerializeField] private float attackInterval = 1f; [Tooltip("攻撃対象へ向きを変える速さ")] [SerializeField] private float rotateSpeed = 10f; private AttackTarget _target; private DamageReceiver _damageReceiver; private HitReaction _hitReaction; private float _lastAttackTime = -999f; public EnemyState State => state; private bool CanAct => state == EnemyState.Idle || state == EnemyState.Move; // 状態判定に必要なコンポーネントを取得する private void Awake() { _damageReceiver = GetComponent(); _hitReaction = GetComponent(); } // 優先度に従って状態を更新し、現在可能な行動を実行する private void Update() { if (_damageReceiver.IsDead) { SetState(EnemyState.Dead); return; } if (_hitReaction.IsReacting) { SetState(EnemyState.Damage); return; } if (state == EnemyState.Damage) SetState(EnemyState.Idle); if (state == EnemyState.Attack && !characterAttack.IsAttacking) SetState(EnemyState.Idle); if (!CanAct) return; if (characterAttack.IsAttacking) return; if (_target == null) _target = FindNearestTarget(); if (_target == null) { SetState(EnemyState.Idle); return; } var toTarget = _target.transform.position - transform.position; toTarget.y = 0f; if (toTarget.magnitude <= attackDistance) { TryAttack(); return; } SetState(EnemyState.Move); MoveToTarget(toTarget.normalized); } // 攻撃間隔を満たしていれば攻撃を開始する private void TryAttack() { if (Time.time < _lastAttackTime + attackInterval) { SetState(EnemyState.Idle); return; } SetState(EnemyState.Attack); characterAttack.Attack(); _lastAttackTime = Time.time; } // 現在の状態を指定された状態へ変更する private void SetState(EnemyState nextState) { if (state == nextState) return; state = nextState; } // 指定された方向へ移動しながら向きを変える private void MoveToTarget(Vector3 direction) { transform.position += direction * moveSpeed * Time.deltaTime; var targetRotation = Quaternion.LookRotation(direction); transform.rotation = Quaternion.Slerp( transform.rotation, targetRotation, rotateSpeed * Time.deltaTime); } // 探索範囲内から最も近い攻撃対象を取得する private AttackTarget FindNearestTarget() { var targets = FindObjectsByType(FindObjectsSortMode.None); AttackTarget nearest = null; var nearestDistance = searchRadius; foreach (var target in targets) { var distance = Vector3.Distance( transform.position, target.transform.position); if (distance >= nearestDistance) continue; nearest = target; nearestDistance = distance; } return nearest; } }