CapersProject/Assets/02.Scripts/Character/Player/Combat/CombatMovement.cs

378 lines
12 KiB
C#

using System;
using System.Collections;
using BlueWater.Audios;
using BlueWater.Interfaces;
using BlueWater.Utility;
using DG.Tweening;
using Sirenix.OdinInspector;
using UnityEngine;
namespace BlueWater.Players.Combat
{
public class CombatMovement : MonoBehaviour, IDashable, IPhysicMovable
{
// Variables
#region Variables
// Components
[field: SerializeField]
public Rigidbody Rigidbody { get; private set; }
[SerializeField]
private Transform _visualLook;
[SerializeField]
private AnimationController _animationController;
[SerializeField]
private ParticleSystem _movementParticle;
[SerializeField]
private ParticleSystem _dashParticle;
private IComboAttackable _comboAttackable;
private ISkillHandler _skillHandler;
private IStunnable _stunnable;
// Move
[field: SerializeField, Range(1f, 10f), Tooltip("이동 속도")]
public float MoveSpeed { get; private set; } = 7f;
public float MoveSpeedCoefficient { get; private set; } = 1f;
public bool IsMoveEnabled { get; private set; } = true;
private bool _isMoving;
public bool IsMoving
{
get => _isMoving;
private set
{
if (_isMoving == value) return;
_isMoving = value;
_animationController.SetAnimationParameter("isMoving", _isMoving);
if (!_movementParticle) return;
switch (_isMoving)
{
case true:
_movementParticle.Play();
break;
case false:
_movementParticle.Stop();
break;
}
}
}
private Vector3 _inputDirection;
private Vector3 _currentDirection = Vector3.back;
public Vector3 CurrentDirection
{
get => _currentDirection;
private set
{
if (value == Vector3.zero) return;
_currentDirection = value;
_animationController.SetAnimationParameter("xDirection", _currentDirection.x);
_animationController.SetAnimationParameter("zDirection", _currentDirection.z);
}
}
[field: SerializeField, DisableIf("@true")]
public Vector3 PushDirection { get; private set; }
[field: SerializeField, DisableIf("@true")]
public float PushPower { get; private set; }
[field: SerializeField]
public float PushPowerReduction { get; private set; } = 20f;
private Vector3 _finalVelocity;
// Dash
[field: Title("대쉬")]
[field: SerializeField, Range(1f, 50f), Tooltip("대쉬 속도")]
public float DashSpeed { get; private set; } = 20f;
[field: SerializeField, Range(0.1f, 1f), Tooltip("대쉬 시간")]
public float DashTime { get; private set; } = 0.2f;
[field: SerializeField, Range(0f, 5f), Tooltip("대쉬 쿨타임")]
public float DashCooldown { get; private set; } = 0.5f;
[field: SerializeField, Tooltip("대쉬가 쿨타임일 때 이펙트 사용 여부")]
public bool EnableDashCooldownEffect { get; private set; } = true;
[SerializeField]
private DOTweenAnimation _dashCooldownEffect;
public bool IsDashEnabled { get; private set; } = true;
private bool _isDashing;
public bool IsDashing
{
get => _isDashing;
private set
{
_isDashing = value;
_animationController.SetAnimationParameter("isDashing", _isDashing);
}
}
public bool IsDashCoolDownActive { get; private set; }
private Coroutine _dashCoroutine;
private bool _isQuitting;
#endregion
// Unity events
#region Unity events
private void Awake()
{
InitializeComponents();
}
private void Update()
{
FlipVisualLook();
}
private void FixedUpdate()
{
if (!CanMove()) return;
Move();
}
private void OnApplicationQuit()
{
_isQuitting = true;
}
private void OnDestroy()
{
if (_isQuitting) return;
_dashCooldownEffect.DOKill();
}
#endregion
// Initialize Methods
#region Initialize Methods
[Button("컴포넌트 초기화")]
private void InitializeComponents()
{
Rigidbody = GetComponent<Rigidbody>();
_visualLook = transform.Find("VisualLook");
_animationController = GetComponent<AnimationController>();
_comboAttackable = GetComponent<IComboAttackable>();
_skillHandler = GetComponent<ISkillHandler>();
_stunnable = GetComponent<IStunnable>();
_dashCooldownEffect = _visualLook.GetComponent<DOTweenAnimation>();
}
#endregion
// Methods
#region Methods
// Event methods
public void InputMovement(Vector2 movementInput)
{
_inputDirection = new Vector3(movementInput.x, 0, movementInput.y).normalized;
}
public void SetMoveSpeedCoefficient(float value) => MoveSpeedCoefficient = value;
public void ResetMoveSpeedCoefficient() => MoveSpeedCoefficient = 1f;
public void SetCurrentDirection(Vector3 normalDirection) => CurrentDirection = normalDirection;
// Methods
private void FlipVisualLook()
{
var localScale = _visualLook.localScale;
localScale.x = CurrentDirection.x switch
{
> 0.01f => Mathf.Abs(localScale.x),
< -0.01f => -Mathf.Abs(localScale.x),
_ => localScale.x
};
_visualLook.localScale = localScale;
}
// Move
public bool CanMove()
{
return IsMoveEnabled;
// if (!IsMoveEnabled || IsDashing) return false;
//
// var isActivatingSkill = _skillHandler?.IsActivatingSkill ?? false;
// var isStunned = _stunnable?.IsStunned ?? false;
// // if (isStunned)
// // {
// // IsMoving = false;
// // }
// var isAttacking = _comboAttackable?.CurrentComboAttackCount > 0;
//
// var canMove = !isActivatingSkill && !isStunned && !isAttacking;
// if (!canMove)
// {
// if (!Rigidbody.isKinematic)
// {
// Rigidbody.linearVelocity = Vector3.zero;
// }
// IsMoving = false;
// }
//
// return canMove;
}
public void Move()
{
if (!_isDashing && _comboAttackable?.CurrentComboAttackCount <= 0 && _skillHandler?.IsActivatingSkill == false)
{
var velocityDirection = _inputDirection;
if (_stunnable?.IsStunned == true)
{
velocityDirection = Vector3.zero;
}
else
{
CurrentDirection = velocityDirection;
}
IsMoving = velocityDirection != Vector3.zero;
_finalVelocity = velocityDirection * (MoveSpeed * MoveSpeedCoefficient);
var pushVelocity = PushDirection * PushPower;
_finalVelocity += pushVelocity;
if (!Rigidbody.isKinematic)
{
Rigidbody.linearVelocity = _finalVelocity;
}
}
PushPower = Mathf.Max(0, PushPower - PushPowerReduction * Time.deltaTime);
// CurrentDirection = _inputDirection;
// IsMoving = _inputDirection != Vector3.zero;
// var finalVelocity = _inputDirection * (MoveSpeed * MoveSpeedCoefficient);
// Rigidbody.linearVelocity = finalVelocity;
}
public void AddForce(Vector3 force, ForceMode forceMode)
{
if (IsDashing) return;
Rigidbody.AddForce(force, forceMode);
}
public void SetPush(Vector3 pushDirection, float pushPower)
{
PushDirection = pushDirection;
PushPower = pushPower;
}
// Dash
public bool CanDash()
{
if (!IsDashEnabled || IsDashing) return false;
if (IsDashCoolDownActive)
{
if (EnableDashCooldownEffect)
{
_dashCooldownEffect.DORestart();
}
return false;
}
var isActivatingSkill = _skillHandler?.IsActivatingSkill ?? false;
var isStunned = _stunnable?.IsStunned ?? false;
if (isActivatingSkill || isStunned) return false;
var isAttacking = _comboAttackable?.CurrentComboAttackCount > 0;
if (isAttacking)
{
_comboAttackable.EndAttack();
}
return true;
}
public void Dash()
{
if (!CanDash()) return;
Utils.StartUniqueCoroutine(this, ref _dashCoroutine, DashCoroutine());
}
private IEnumerator DashCoroutine()
{
IsDashing = true;
IsDashCoolDownActive = true;
if (_dashParticle)
{
_dashParticle.Play();
}
var dashDirection = _inputDirection;
if (dashDirection == Vector3.zero)
{
dashDirection = CurrentDirection;
}
var animationStarted = false;
yield return StartCoroutine(_animationController.WaitForAnimationToRun("DashState",
success => animationStarted = success));
if (!animationStarted)
{
EndDash(0);
yield break;
}
_animationController.SetCurrentAnimationSpeed(DashTime);
AudioManager.Instance.PlaySfx("CombatPlayerDash");
while (_animationController.IsComparingCurrentAnimation("DashState") &&
_animationController.GetCurrentAnimationNormalizedTime() < 1f)
{
// MovePosition()는 벽을 뚫는 현상이 있음
// var finalVelocity = transform.position + dashDirection * (DashSpeed * Time.fixedDeltaTime);
// Rigidbody.MovePosition(finalVelocity);
var finalVelocity = dashDirection * DashSpeed;
Rigidbody.linearVelocity = finalVelocity;
yield return new WaitForFixedUpdate();
}
EndDash(DashCooldown);
}
public void EndDash(float dashCooldown = float.PositiveInfinity)
{
Utils.EndUniqueCoroutine(this, ref _dashCoroutine);
Rigidbody.linearVelocity = Vector3.zero;
_animationController.ResetAnimationSpeed();
IsDashing = false;
if (float.IsPositiveInfinity(dashCooldown))
{
dashCooldown = DashCooldown;
}
StartCoroutine(Utils.CoolDownCoroutine(dashCooldown, () => IsDashCoolDownActive = false));
}
#endregion
}
}