using System; using System.Collections; using BlueWater.Audios; using BlueWater.Interfaces; using BlueWater.Utility; using UnityEngine; namespace BlueWater.Players.Combat { public class CombatMovement : MonoBehaviour, IDashable, IPhysicMovable { // Variables #region Variables // Components public Rigidbody Rigidbody { get; private set; } private Transform _visualLook; private AnimationController _animationController; // Move [field: SerializeField, Range(1f, 10f), Tooltip("이동 속도")] public float MoveSpeed { get; private set; } = 7f; public bool EnableMove { get; private set; } = true; private bool _isMoving; public bool IsMoving { get => _isMoving; set { _isMoving = value; _animationController.SetAnimationParameter("isMoving", _isMoving); } } private Vector3 _inputDirection; private Vector3 _currentDirection = Vector3.back; public Vector3 CurrentDirection { get => _currentDirection; set { if (value == Vector3.zero) return; _currentDirection = value; _animationController.SetAnimationParameter("xDirection", _currentDirection.x); _animationController.SetAnimationParameter("zDirection", _currentDirection.z); } } private float _finalSpeed; private float _moveSpeedCoefficient = 1f; // Dash [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; public bool EnableDash { 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; // Events public event Action OnStartDash; public event Action OnEndDash; #endregion // Unity events #region Unity events private void Update() { FlipVisualLook(); } private void FixedUpdate() { if (!CanMove()) return; ApplyMovement(); } #endregion // Initialize Methods #region Initialize Methods public void InitializeComponents(Rigidbody rigidbody, Transform visualLook, AnimationController animationController) { Rigidbody = rigidbody; _visualLook = visualLook; _animationController = animationController; } #endregion // Methods #region Methods // Event methods public void HandleInputMovement(Vector2 movementInput) { _inputDirection = new Vector3(movementInput.x, 0, movementInput.y).normalized; } public void HandleAttackInDash() { if (IsDashing) { EndDash(DashCooldown); } } public void HandleMoveSpeedCoefficient(float value) => _moveSpeedCoefficient = value; public void HandleResetMoveSpeedCoefficient() => _moveSpeedCoefficient = 1f; public void HandleEnableMove() => EnableMove = true; public void HandleDisableMove() => EnableMove = false; public void HandleEnableDash() => EnableDash = true; public void HandleDisableDash() => EnableDash = false; public void HandleEnableMoveAndDash() { EnableMove = true; EnableDash = true; } public void HandleDisableMoveAndDash() { EnableMove = false; EnableDash = false; } // 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 EnableMove && !IsDashing; } public void AddForce(Vector3 force, ForceMode forceMode) { if (_isDashing) return; Rigidbody.AddForce(force, forceMode); } private void ApplyMovement() { CurrentDirection = _inputDirection; IsMoving = _inputDirection != Vector3.zero; // var finalVelocity = _inputDirection * (MoveSpeed * _moveSpeedCoefficient); // Rigidbody.linearVelocity = finalVelocity; var finalVelocity = _inputDirection * (MoveSpeed * _moveSpeedCoefficient * Time.deltaTime); Rigidbody.MovePosition(transform.position + finalVelocity); } // Dash public bool CanDash() { return EnableMove && EnableDash && !IsDashing && !IsDashCoolDownActive; } public void HandleDash() { if (!CanDash()) return; Utils.StartUniqueCoroutine(this, ref _dashCoroutine, DashCoroutine()); } private IEnumerator DashCoroutine() { OnStartDash?.Invoke(); IsDashing = true; IsDashCoolDownActive = true; var 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) { //var finalVelocity = rb.position + dashDirection * (dashSpeed * Time.fixedDeltaTime); //rb.MovePosition(finalVelocity); var finalVelocity = dashDirection * DashSpeed; Rigidbody.linearVelocity = finalVelocity; yield return new WaitForFixedUpdate(); } EndDash(DashCooldown); } public void EndDash(float dashCooldown) { Utils.EndUniqueCoroutine(this, ref _dashCoroutine); Rigidbody.linearVelocity = Vector3.zero; _animationController.ResetAnimationSpeed(); OnEndDash?.Invoke(); IsDashing = false; StartCoroutine(Utils.CoolDownCoroutine(dashCooldown, () => IsDashCoolDownActive = false)); } #endregion } }