using System.Collections.Generic; using UnityEngine; // キャラクターの攻撃判定を管理する public class CharacterAttack : MonoBehaviour { [Tooltip("攻撃時に再生する見た目の演出")] [SerializeField] private AttackEffect attackEffect; [Tooltip("攻撃中だけ有効にする当たり判定")] [SerializeField] private Collider attackCollider; [Tooltip("攻撃が命中した相手に与えるダメージ")] [SerializeField] private int damage = 1; [Tooltip("攻撃全体の時間")] [SerializeField] private float attackDuration = 0.5f; [Tooltip("攻撃開始から当たり判定を有効にするまでの時間")] [SerializeField] private float hitStartTime = 0.15f; [Tooltip("攻撃開始から当たり判定を無効にするまでの時間")] [SerializeField] private float hitEndTime = 0.3f; private readonly List _hitReceivers = new(); private bool _isAttacking; private bool _isHitActive; private float _attackElapsedTime; public bool IsAttacking => _isAttacking; private void Awake() { attackCollider.enabled = false; } private void Update() { if (!_isAttacking) return; _attackElapsedTime += Time.deltaTime; if (!_isHitActive && _attackElapsedTime >= hitStartTime) StartHit(); if (_isHitActive && _attackElapsedTime >= hitEndTime) EndHit(); if (_attackElapsedTime >= attackDuration) EndAttack(); } // 攻撃の呼び出し public void Attack() { if (_isAttacking) return; attackEffect?.Play(); // 前回命中した相手の記録をクリアしてから攻撃を開始する _hitReceivers.Clear(); _isAttacking = true; _isHitActive = false; _attackElapsedTime = 0f; } // 進行中の攻撃判定と攻撃演出を中断する public void CancelAttack() { if (!_isAttacking) return; EndAttack(); attackEffect?.Stop(); } private void OnTriggerEnter(Collider other) { var receiver = other.GetComponentInParent(); // 攻撃の命中対象しか扱わない if (receiver == null) return; // 1回の攻撃で同じ相手に何度もダメージを与えない if (_hitReceivers.Contains(receiver)) return; // 被弾済みの相手の登録 _hitReceivers.Add(receiver); // 攻撃の効果をAttackResolverに任せて解決 var attackContext = new AttackContext(gameObject, damage); AttackResolver.Resolve(attackContext, receiver); } private void EndAttack() { _isAttacking = false; EndHit(); } private void StartHit() { _isHitActive = true; attackCollider.enabled = true; } private void EndHit() { _isHitActive = false; attackCollider.enabled = false; } }