210 lines
5.9 KiB
C#
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
|
|
|
|
}
|