+ CombatPlayer 기능별 분리 + Combat, CombatUi 전용 input action map 추가 + 스킬 시스템 로직 수정 + 전투플레이어 스킬(검의 왈츠) 로직 변경
267 lines
9.9 KiB
C#
267 lines
9.9 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
namespace BlueWaterProject
|
|
{
|
|
public class CombatAttacker : MonoBehaviour, IMeleeComboAttackable
|
|
{
|
|
// Components
|
|
private Rigidbody rb;
|
|
|
|
// Interfaces
|
|
private IAnimationStateController iAnimationStateController;
|
|
private IRigidMovable iRigidMovable;
|
|
|
|
// ComboAttack
|
|
[field: Range(1, 21), Tooltip("한 번에 공격 가능한 개체 수")]
|
|
[field: SerializeField] public int MaxHitCount { get; set; } = 10;
|
|
[field: SerializeField] public ComboAttack[] ComboAttacks { get; set; } = new ComboAttack[2];
|
|
|
|
public bool UsedMouseAttack { get; set; }
|
|
private int currentComboAttackCount;
|
|
|
|
public int CurrentComboAttackCount
|
|
{
|
|
get => currentComboAttackCount;
|
|
set
|
|
{
|
|
currentComboAttackCount = value;
|
|
iAnimationStateController.SetAnimationParameter(CombatPlayerAnimatorParameter.COMBO_ATTACK_COUNT, CurrentComboAttackCount);
|
|
}
|
|
}
|
|
public bool IsComboAttackPossible { get; set; }
|
|
public bool IsComboAttacking { get; set; }
|
|
public Collider[] HitColliders { get; set; }
|
|
private bool enableAttack = true;
|
|
|
|
[field: SerializeField] public LayerMask TargetLayer { get; set; }
|
|
[SerializeField] private LayerMask groundLayer;
|
|
|
|
// Particles
|
|
[SerializeField] private ParticleSystem swordHit;
|
|
|
|
// Camera effects
|
|
[SerializeField] private float comboAttackHitStopDuration = 0.15f;
|
|
|
|
// Variables
|
|
private Coroutine firstComboAttackCoroutine;
|
|
private Coroutine secondComboAttackCoroutine;
|
|
|
|
// Events
|
|
public delegate void AttackInDashEvent();
|
|
public event AttackInDashEvent OnAttackInDashing;
|
|
|
|
public delegate void StartAttackEvent();
|
|
public event StartAttackEvent OnStartAttack;
|
|
|
|
public delegate void EndAttackEvent();
|
|
public event EndAttackEvent OnEndAttack;
|
|
|
|
// Unity events
|
|
private void Start()
|
|
{
|
|
iAnimationStateController = GetComponent<IAnimationStateController>();
|
|
iRigidMovable = GetComponent<IRigidMovable>();
|
|
|
|
HitColliders = new Collider[MaxHitCount];
|
|
}
|
|
|
|
// Init
|
|
public void InitComponent(Rigidbody rigidbody)
|
|
{
|
|
rb = rigidbody;
|
|
}
|
|
|
|
// Event methods
|
|
public void HandleEnableAttack() => enableAttack = true;
|
|
public void HandleDisableAttack() => enableAttack = false;
|
|
|
|
public void HandleAttack(bool usedMouseAttack)
|
|
{
|
|
if (!enableAttack) return;
|
|
|
|
if (CurrentComboAttackCount == 1 && IsComboAttackPossible)
|
|
{
|
|
IsComboAttacking = true;
|
|
if (usedMouseAttack)
|
|
{
|
|
UseMouseAttack();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (CurrentComboAttackCount >= 1) return;
|
|
|
|
OnAttackInDashing?.Invoke();
|
|
|
|
if (usedMouseAttack)
|
|
{
|
|
UseMouseAttack();
|
|
}
|
|
|
|
firstComboAttackCoroutine = StartCoroutine(nameof(FirstComboAttackCoroutine));
|
|
}
|
|
|
|
// Methods
|
|
private void UseMouseAttack()
|
|
{
|
|
var mousePos = Mouse.current.position.ReadValue();
|
|
var ray = CameraManager.Inst.MainCam.ScreenPointToRay(mousePos);
|
|
|
|
if (!Physics.Raycast(ray, out var hit, float.MaxValue, groundLayer))
|
|
{
|
|
EndComboAttack();
|
|
return;
|
|
}
|
|
|
|
var attackDirection = (hit.point - rb.position).normalized;
|
|
attackDirection.y = 0f;
|
|
iRigidMovable.PreviousMoveDirection = attackDirection;
|
|
}
|
|
|
|
private IEnumerator FirstComboAttackCoroutine()
|
|
{
|
|
OnStartAttack?.Invoke();
|
|
CurrentComboAttackCount = 1;
|
|
|
|
var animationStarted = false;
|
|
yield return StartCoroutine(iAnimationStateController.WaitForAnimationToRun(CombatPlayerAnimationName.COMBO_ATTACK1,
|
|
success => animationStarted = success));
|
|
|
|
if (!animationStarted)
|
|
{
|
|
EndComboAttack();
|
|
yield break;
|
|
}
|
|
|
|
iAnimationStateController.SetCurrentAnimationSpeed(ComboAttacks[CurrentComboAttackCount - 1].Speed);
|
|
IsComboAttackPossible = true;
|
|
var doDamage = false;
|
|
|
|
while (iAnimationStateController.IsComparingCurrentAnimation(CombatPlayerAnimationName.COMBO_ATTACK1) &&
|
|
iAnimationStateController.GetCurrentAnimationNormalizedTime() < 1f)
|
|
{
|
|
if (!doDamage && iAnimationStateController.GetCurrentAnimationNormalizedTime() >= 0.28f)
|
|
{
|
|
var moveSpeed = ComboAttacks[CurrentComboAttackCount - 1].MovePower;
|
|
var finalVelocity = iRigidMovable.PreviousMoveDirection * moveSpeed;
|
|
//rb.velocity = finalVelocity;
|
|
rb.AddForce(finalVelocity, ForceMode.Impulse);
|
|
rb.velocity = Vector3.zero;
|
|
doDamage = true;
|
|
DoDamage(CurrentComboAttackCount, iRigidMovable.PreviousMoveDirection);
|
|
}
|
|
yield return new WaitForFixedUpdate();
|
|
}
|
|
|
|
if (IsComboAttacking)
|
|
{
|
|
secondComboAttackCoroutine = StartCoroutine(nameof(SecondComboAttackCoroutine));
|
|
}
|
|
else
|
|
{
|
|
EndComboAttack();
|
|
}
|
|
}
|
|
|
|
private IEnumerator SecondComboAttackCoroutine()
|
|
{
|
|
IsComboAttackPossible = false;
|
|
CurrentComboAttackCount = 2;
|
|
|
|
var animationStarted = false;
|
|
yield return StartCoroutine(iAnimationStateController.WaitForAnimationToRun(CombatPlayerAnimationName.COMBO_ATTACK2,
|
|
success => animationStarted = success));
|
|
|
|
if (!animationStarted)
|
|
{
|
|
EndComboAttack();
|
|
yield break;
|
|
}
|
|
|
|
iAnimationStateController.SetCurrentAnimationSpeed(ComboAttacks[CurrentComboAttackCount - 1].Speed);
|
|
var doDamage = false;
|
|
|
|
while (iAnimationStateController.IsComparingCurrentAnimation(CombatPlayerAnimationName.COMBO_ATTACK2) &&
|
|
iAnimationStateController.GetCurrentAnimationNormalizedTime() < 1f)
|
|
{
|
|
if (!doDamage && iAnimationStateController.GetCurrentAnimationNormalizedTime() >= 0.3f)
|
|
{
|
|
var moveSpeed = ComboAttacks[CurrentComboAttackCount - 1].MovePower;
|
|
var finalVelocity = iRigidMovable.PreviousMoveDirection * moveSpeed;
|
|
//rb.velocity = finalVelocity;
|
|
rb.AddForce(finalVelocity, ForceMode.Impulse);
|
|
rb.velocity = Vector3.zero;
|
|
doDamage = true;
|
|
DoDamage(CurrentComboAttackCount, iRigidMovable.PreviousMoveDirection);
|
|
}
|
|
yield return new WaitForFixedUpdate();
|
|
}
|
|
|
|
EndComboAttack();
|
|
}
|
|
|
|
private void DoDamage(int comboAttackCount, Vector3 attackDirection)
|
|
{
|
|
var size = Physics.OverlapSphereNonAlloc(transform.position, ComboAttacks[comboAttackCount - 1].Range, HitColliders,
|
|
TargetLayer, QueryTriggerInteraction.Collide);
|
|
|
|
for (var i = 0; i < size; i++)
|
|
{
|
|
var targetDirection = (HitColliders[i].transform.position - transform.position).normalized;
|
|
var angleBetween = Vector3.Angle(attackDirection, targetDirection);
|
|
|
|
if (angleBetween >= ComboAttacks[comboAttackCount - 1].Angle * 0.5f) continue;
|
|
|
|
if (HitColliders[i].gameObject.layer == LayerMask.NameToLayer("Enemy"))
|
|
{
|
|
var iDamageable = HitColliders[i].transform.GetComponent<IDamageable>();
|
|
if (iDamageable != null)
|
|
{
|
|
iDamageable.TakeDamage(ComboAttacks[comboAttackCount - 1].Damage);
|
|
var closestPoint = HitColliders[i].ClosestPoint(transform.position);
|
|
//var spawnPosition = closestPoint + Random.insideUnitSphere * 0.2f;
|
|
Instantiate(swordHit, closestPoint, Quaternion.identity);
|
|
}
|
|
|
|
if (comboAttackCount == 2)
|
|
{
|
|
VisualFeedbackManager.Inst.TriggerHitStop(comboAttackHitStopDuration);
|
|
}
|
|
}
|
|
else if (HitColliders[i].gameObject.layer == LayerMask.NameToLayer("Skill") &&
|
|
HitColliders[i].CompareTag("DestructiveSkill"))
|
|
{
|
|
var iDamageable = HitColliders[i].transform.GetComponent<IDamageable>();
|
|
iDamageable?.TakeDamage(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void EndComboAttack()
|
|
{
|
|
if (firstComboAttackCoroutine != null)
|
|
{
|
|
StopCoroutine(firstComboAttackCoroutine);
|
|
firstComboAttackCoroutine = null;
|
|
}
|
|
|
|
if (secondComboAttackCoroutine != null)
|
|
{
|
|
StopCoroutine(secondComboAttackCoroutine);
|
|
secondComboAttackCoroutine = null;
|
|
}
|
|
|
|
rb.velocity = Vector3.zero;
|
|
IsComboAttacking = false;
|
|
IsComboAttackPossible = false;
|
|
|
|
iAnimationStateController.ResetAnimationSpeed();
|
|
CurrentComboAttackCount = 0;
|
|
|
|
OnEndAttack?.Invoke();
|
|
}
|
|
}
|
|
} |