Degulleo3D/Assets/JAY/Scripts/WeaponController.cs

137 lines
3.9 KiB
C#

// Anchor 방식 리팩토링
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponController : MonoBehaviour, IObservable<GameObject>
{
[SerializeField] private Transform[] triggerAnchors;
[SerializeField] private float triggerRadius = 0.5f;
[SerializeField] private LayerMask targetLayerMask;
private List<IObserver<GameObject>> _observers = new List<IObserver<GameObject>>();
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<Collider> _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<PlayerController>();
if (_playerController == null)
{
var player = GameObject.FindGameObjectWithTag("Player");
if (player != null)
{
_playerController = player.GetComponent<PlayerController>();
}
}
_previousPositions = new Vector3[triggerAnchors.Length];
_hitColliders = new HashSet<Collider>();
}
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<GameObject> observer)
{
if (!_observers.Contains(observer)) _observers.Add(observer);
}
public void Unsubscribe(IObserver<GameObject> observer) => _observers.Remove(observer);
public void Notify(GameObject value)
{
foreach (var o in _observers) o.OnNext(value);
}
private void OnDestroy()
{
var copyObservers = new List<IObserver<GameObject>>(_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
}