2026-05-18 버그 수정
This commit is contained in:
@@ -82,7 +82,9 @@ public class PlayerController : MonoBehaviour
|
||||
private CancellationTokenSource _motionCts;
|
||||
private CancellationTokenSource _animationSpeedCts;
|
||||
private CancellationTokenSource _actionVelocityCts;
|
||||
private bool _isAttackActive;
|
||||
private bool _isMotionActive;
|
||||
private float _actionDirection = 1f;
|
||||
private ActionData _lastAttackGizmoData;
|
||||
[SerializeField] private float _hitGizmoFadeDuration = 0.5f;
|
||||
private ActionData _lastHitData;
|
||||
@@ -161,10 +163,10 @@ private void FixedUpdate()
|
||||
ExecuteBufferedInputIfReady();
|
||||
TickComboWindow();
|
||||
|
||||
if (!IsMovementLocked())
|
||||
if (!IsMovementLocked() && !IsActionActive())
|
||||
_rb.linearVelocity = new Vector2(_moveInputX * _moveSpeed, _rb.linearVelocity.y);
|
||||
|
||||
if (!IsFacingLocked())
|
||||
if (!IsFacingLocked() && !IsActionActive())
|
||||
UpdateFacingFromMoveInput();
|
||||
|
||||
ApplyGravity();
|
||||
@@ -201,7 +203,7 @@ private void TickComboWindow()
|
||||
private void OnMoveInput(Vector2 value)
|
||||
{
|
||||
_moveInputX = value.x == 0f ? 0f : Mathf.Sign(value.x);
|
||||
if (_facingLockTimer <= 0f)
|
||||
if (_facingLockTimer <= 0f && !IsActionActive())
|
||||
UpdateFacingFromMoveInput();
|
||||
}
|
||||
|
||||
@@ -268,6 +270,7 @@ private void ExecuteComboInput(ComboInputType input)
|
||||
{
|
||||
if (transition.Trigger != input) continue;
|
||||
if (transition.Next == null || transition.Next.Action == null) continue;
|
||||
if (!CanPerformAction(transition.Next.Action)) continue;
|
||||
|
||||
ApplyForwardStep(transition.ForwardStep, transition.ForwardStepDuration);
|
||||
PerformAttack(transition.Next.Action, transition.ForwardStep > 0f);
|
||||
@@ -286,12 +289,21 @@ private void ExecuteComboInput(ComboInputType input)
|
||||
_ => null
|
||||
};
|
||||
if (root == null || root.Action == null) return;
|
||||
if (!CanPerformAction(root.Action)) return;
|
||||
|
||||
PerformAttack(root.Action);
|
||||
_currentNode = root;
|
||||
_comboWindowTimer = root.ComboWindow;
|
||||
}
|
||||
|
||||
private bool CanPerformAction(ActionData data)
|
||||
{
|
||||
if (data == null) return false;
|
||||
// 잡기 액션은 사정 거리 안에 적이 있어야만 실행. 없으면 입력 자체를 캔슬.
|
||||
if (data.IsGrab && FindGrabTarget(data) == null) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ExecuteMotionNode(ComboNode root)
|
||||
{
|
||||
if (root == null || root.Action == null) return;
|
||||
@@ -336,14 +348,17 @@ private async void PerformAttack(ActionData data, bool preserveHorizontalVelocit
|
||||
CancelMotion();
|
||||
CancelAndDispose(ref _attackCts);
|
||||
_attackCts = CancellationTokenSource.CreateLinkedTokenSource(destroyCancellationToken);
|
||||
CancellationTokenSource currentAttackCts = _attackCts;
|
||||
CancellationToken token = _attackCts.Token;
|
||||
|
||||
_attackCooldownTimer = data.Cooldown;
|
||||
_isAttackActive = true;
|
||||
_lastAttackGizmoData = data;
|
||||
_attackStartTime = Time.time;
|
||||
_hitFired = false;
|
||||
|
||||
ClearActionLocks();
|
||||
CaptureActionDirection(data);
|
||||
PlayActionAnimation(data);
|
||||
|
||||
PlayActionVelocity(data);
|
||||
@@ -362,6 +377,9 @@ private async void PerformAttack(ActionData data, bool preserveHorizontalVelocit
|
||||
{
|
||||
_attackHitbox?.Deactivate();
|
||||
}
|
||||
|
||||
if (_attackCts == currentAttackCts)
|
||||
_isAttackActive = false;
|
||||
}
|
||||
|
||||
private async void PerformMotion(ActionData data)
|
||||
@@ -375,12 +393,13 @@ private async void PerformMotion(ActionData data)
|
||||
CancellationToken token = _motionCts.Token;
|
||||
|
||||
SetMotionCooldown(data);
|
||||
_isMotionActive = true;
|
||||
ClearActionLocks();
|
||||
CaptureActionDirection(data);
|
||||
_isMotionActive = true;
|
||||
FaceMotionDirection(data);
|
||||
PlayActionAnimation(data);
|
||||
PlayActionVelocity(data);
|
||||
LockMovementIfNeeded(data);
|
||||
LockMovementIfNeeded(data, false, true);
|
||||
LockFacingIfNeeded(data);
|
||||
|
||||
bool completed = false;
|
||||
@@ -432,6 +451,7 @@ private async void PerformGroundPound()
|
||||
_hitFired = false;
|
||||
|
||||
ClearActionLocks();
|
||||
CaptureActionDirection(_groundPoundData);
|
||||
FaceMotionDirection(_groundPoundData);
|
||||
PlayActionAnimation(_groundPoundData);
|
||||
LockMovementIfNeeded(_groundPoundData);
|
||||
@@ -512,6 +532,7 @@ private async void PerformGroundPound()
|
||||
|
||||
private void CancelAttack()
|
||||
{
|
||||
_isAttackActive = false;
|
||||
CancelAndDispose(ref _attackCts);
|
||||
CancelAndDispose(ref _actionVelocityCts);
|
||||
_attackCooldownTimer = 0f;
|
||||
@@ -527,6 +548,11 @@ private void CancelMotion()
|
||||
CancelAndDispose(ref _actionVelocityCts);
|
||||
}
|
||||
|
||||
private bool IsActionActive()
|
||||
{
|
||||
return _isAttackActive || _isMotionActive || _isGroundPounding;
|
||||
}
|
||||
|
||||
private bool CanTransitionFromCurrentNode(ComboInputType input)
|
||||
{
|
||||
if (_comboWindowTimer <= 0f || _currentNode == null) return false;
|
||||
@@ -672,6 +698,7 @@ private void ActivateAttackHitbox(ActionData data)
|
||||
_lastHitTime = Time.time;
|
||||
_hitFired = true;
|
||||
|
||||
Debug.Log($"[Activate] t={Time.time:F3} action={GetActionName(data)} hitDuration={data.HitDuration:F3} motionActive={_isMotionActive} groundPounding={_isGroundPounding}");
|
||||
Vector2 sourcePosition = _rb != null ? _rb.position : (Vector2)transform.position;
|
||||
_attackHitbox.Activate(data, localPosition, hitVelocity, sourcePosition, hitTargetPosition, data.CorrectHitTargetY, _groundLayer.value, _enemyLayer);
|
||||
}
|
||||
@@ -737,8 +764,17 @@ private void LockMovementIfNeeded(ActionData data, bool preserveHorizontalVeloci
|
||||
if (!preserveHorizontalVelocity && data.Velocity == Vector2.zero)
|
||||
_rb.linearVelocity = new Vector2(0f, _rb.linearVelocity.y);
|
||||
|
||||
_inputLockTimer = GetActionLockDuration(data);
|
||||
_movementLockAction = ShouldUseAnimationLength(data) ? data : null;
|
||||
if (forceLock)
|
||||
{
|
||||
// 액션 길이 전체를 보장: 애니메이션 길이와 무관하게 MotionDuration만큼 잠금.
|
||||
_inputLockTimer = Mathf.Max(data.MotionDuration, 0.02f);
|
||||
_movementLockAction = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inputLockTimer = GetActionLockDuration(data);
|
||||
_movementLockAction = ShouldUseAnimationLength(data) ? data : null;
|
||||
}
|
||||
}
|
||||
|
||||
private void LockFacingIfNeeded(ActionData data)
|
||||
@@ -889,21 +925,25 @@ private float GetAnimationSpeed(ActionData data, float normalizedTime)
|
||||
|
||||
private float GetMotionDirection(ActionData data)
|
||||
{
|
||||
if (data.UseInputDirection && _moveInputX != 0f)
|
||||
return _moveInputX;
|
||||
|
||||
return _spriteRenderer != null && _spriteRenderer.flipX ? -1f : 1f;
|
||||
return _actionDirection;
|
||||
}
|
||||
|
||||
private void FaceMotionDirection(ActionData data)
|
||||
{
|
||||
if (_spriteRenderer == null) return;
|
||||
if (!data.UseInputDirection || _moveInputX == 0f) return;
|
||||
|
||||
_spriteRenderer.flipX = _moveInputX < 0f;
|
||||
_spriteRenderer.flipX = _actionDirection < 0f;
|
||||
_facingLockTimer = 0f;
|
||||
}
|
||||
|
||||
private void CaptureActionDirection(ActionData data)
|
||||
{
|
||||
if (data != null && data.UseInputDirection && _moveInputX != 0f)
|
||||
_actionDirection = _moveInputX;
|
||||
else
|
||||
_actionDirection = _spriteRenderer != null && _spriteRenderer.flipX ? -1f : 1f;
|
||||
}
|
||||
|
||||
private Vector2 GetHitVelocity(Vector2 hitVelocity)
|
||||
{
|
||||
float facing = _spriteRenderer != null && _spriteRenderer.flipX ? -1f : 1f;
|
||||
|
||||
Reference in New Issue
Block a user