Degulleo3D/Assets/JAY/Scripts/WeaponController.cs
2025-04-28 13:29:19 +09:00

210 lines
5.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponController : MonoBehaviour, IObservable<GameObject>
{
[Serializable]
public class WeaponTriggerZone
{
public Vector3 position;
public float radius;
}
[SerializeField] private WeaponTriggerZone[] _triggerZones;
[SerializeField] private LayerMask targetLayerMask;
private List<IObserver<GameObject>> _observers = new List<IObserver<GameObject>>();
// 공격 데미지 처리
private int attackPower = 1;
private int _comboStep = 1;
public int AttackPower // 플레이어 공격 데미지
{
get
{
// 마지막 콤보일 경우 공격력 증가
return _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 (_triggerZones == null || _triggerZones.Length == 0)
{
Debug.LogWarning("Trigger Zones이 설정되지 않았습니다.");
return;
}
_playerController = GetComponent<PlayerController>();
if (_playerController == null)
{
var player = GameObject.FindGameObjectWithTag("Player");
if (player != null)
{
_playerController = player.GetComponent<PlayerController>();
}
}
_previousPositions = new Vector3[_triggerZones.Length];
_hitColliders = new HashSet<Collider>();
}
public void AttackStart()
{
if (_hitColliders == null)
{
Debug.LogError("_hitColliders가 null입니다. 무기를 들고 있는지 확인해 주세요!");
return;
}
_isAttacking = true;
_hitColliders.Clear();
StopAllCoroutines();
StartCoroutine(AutoEndAttack()); // 자동 공격 종료
for (int i = 0; i < _triggerZones.Length; i++)
{
_previousPositions[i] = transform.position + transform.TransformVector(_triggerZones[i].position);
}
}
private IEnumerator AutoEndAttack()
{
yield return new WaitForSeconds(0.6f); // 0.6초 가량 대기
if (_isAttacking) // 아직 공격 중이면
{
Debug.Log("공격 자동 종료 - 타임아웃");
AttackEnd();
}
}
public void AttackEnd()
{
_isAttacking = false;
}
private void FixedUpdate()
{
if (_isAttacking)
{
for (int i = 0; i < _triggerZones.Length; i++)
{
var worldPosition = transform.position +
transform.TransformVector(_triggerZones[i].position);
var direction = worldPosition - _previousPositions[i];
_ray.origin = _previousPositions[i];
_ray.direction = direction;
if (direction.magnitude < 0.01f) return;
var hitCount = Physics.SphereCastNonAlloc(_ray,
_triggerZones[i].radius, _hits,
direction.magnitude, targetLayerMask,
QueryTriggerInteraction.UseGlobal);
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] = worldPosition;
}
}
}
private IEnumerator ResumeTimeScale()
{
yield return new WaitForSecondsRealtime(10f);
Time.timeScale = 1f;
}
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 observer in _observers)
{
observer.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 (_triggerZones == null) return;
if (_isAttacking && _previousPositions != null)
{
for (int i = 0; i < _triggerZones.Length; i++)
{
if (_triggerZones[i] == null) continue;
var worldPosition = transform.position +
transform.TransformVector(_triggerZones[i].position);
var direction = worldPosition - _previousPositions[i];
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(worldPosition, _triggerZones[i].radius);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(worldPosition + direction, _triggerZones[i].radius);
}
}
else
{
foreach (var triggerZone in _triggerZones)
{
if (triggerZone == null) continue;
Gizmos.color = Color.green;
Gizmos.DrawSphere(triggerZone.position, triggerZone.radius);
}
}
}
#endif
}