// Anchor 방식 리팩토링 using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class WeaponController : MonoBehaviour, IObservable { [SerializeField] private Transform[] triggerAnchors; [SerializeField] private float triggerRadius = 0.5f; [SerializeField] private LayerMask targetLayerMask; private List> _observers = new List>(); private int attackPower = 1; private int _comboStep = 1; public int AttackPower => _comboStep == 4 ? attackPower * 4 : attackPower; private PlayerController _playerController; private bool _isAttacking = false; public bool IsAttacking => _isAttacking; private Vector3[] _previousPositions; private HashSet _hitColliders; private Ray _ray = new Ray(); private RaycastHit[] _hits = new RaycastHit[10]; private void Start() { if (triggerAnchors == null || triggerAnchors.Length == 0) { Debug.LogWarning("Trigger Anchors가 비어있습니다."); return; } _playerController = GetComponent(); if (_playerController == null) { var player = GameObject.FindGameObjectWithTag("Player"); if (player != null) { _playerController = player.GetComponent(); } } _previousPositions = new Vector3[triggerAnchors.Length]; _hitColliders = new HashSet(); } public void AttackStart() { _isAttacking = true; _hitColliders.Clear(); StopAllCoroutines(); StartCoroutine(AutoEndAttack()); for (int i = 0; i < triggerAnchors.Length; i++) { _previousPositions[i] = triggerAnchors[i].position; } } private IEnumerator AutoEndAttack() { yield return new WaitForSeconds(0.6f); if (_isAttacking) AttackEnd(); } public void AttackEnd() => _isAttacking = false; private void FixedUpdate() { if (!_isAttacking) return; for (int i = 0; i < triggerAnchors.Length; i++) { var current = triggerAnchors[i].position; var direction = current - _previousPositions[i]; if (direction.magnitude < 0.01f) continue; _ray.origin = _previousPositions[i]; _ray.direction = direction; int hitCount = Physics.SphereCastNonAlloc(_ray, triggerRadius, _hits, direction.magnitude, targetLayerMask); for (int j = 0; j < hitCount; j++) { var hit = _hits[j]; if (!_hitColliders.Contains(hit.collider)) { _hitColliders.Add(hit.collider); Notify(hit.collider.gameObject); } } _previousPositions[i] = current; } } public void Subscribe(IObserver observer) { if (!_observers.Contains(observer)) _observers.Add(observer); } public void Unsubscribe(IObserver observer) => _observers.Remove(observer); public void Notify(GameObject value) { foreach (var o in _observers) o.OnNext(value); } private void OnDestroy() { var copyObservers = new List>(_observers); foreach (var observer in copyObservers) { observer.OnCompleted(); } _observers.Clear(); } public void SetComboStep(int step) => _comboStep = step; #if UNITY_EDITOR private void OnDrawGizmos() { if (triggerAnchors == null) return; Gizmos.color = Color.green; foreach (var anchor in triggerAnchors) { if (anchor != null) Gizmos.DrawWireSphere(anchor.position, triggerRadius); } } #endif }