연속 액션 기능 및 관련 설정 기능 추가

This commit is contained in:
2026-01-18 21:40:29 +09:00
parent a3b27f08c9
commit 733ea30631
7 changed files with 138 additions and 17 deletions

View File

@@ -7,6 +7,8 @@ public class MiningActionData : PlayerActionData
public override void ExecuteEffect(GameObject performer, GameObject target)
{
if(target == null) return;
if (target.TryGetComponent<MineableBlock>(out var block))
{
// 서버 RPC 호출은 블록 내부의 로직을 그대로 사용합니다.

View File

@@ -4,7 +4,12 @@ public abstract class PlayerActionData : ScriptableObject
{
public string actionName;
public float duration; // 액션 자체가 시간을 가짐
public string animTrigger;
public string animTrigger;
public float impactDelay; // 애니메이션 원본 길이 기준 타격 지연 시간
public float baseSpeed = 1f; // 기본 재생 속도 (1.0 = 100%)
[Header("Repeat Settings")]
public bool canRepeat = true; // [추가] 꾹 눌렀을 때 반복할지 여부
// 대상(target)은 있을 수도 있고(채광), 없을 수도 있음(회복/대쉬)
public abstract void ExecuteEffect(GameObject performer, GameObject target);

View File

@@ -44,11 +44,36 @@ public class PlayerActionHandler : NetworkBehaviour
private IEnumerator ActionRoutine(PlayerActionData data, GameObject target)
{
_isBusy = true;
_animator.SetTrigger(data.animTrigger);
data.ExecuteEffect(gameObject, target); // 로직 실행
// 1. 애니메이션 재생 속도 결정
// (나중에 캐릭터 스탯이나 버프에 따라 이 값을 추가로 계산할 수 있습니다)
float finalSpeed = data.baseSpeed;
_animator.SetFloat("ActionSpeed", finalSpeed);
// 2. 애니메이션 실행
if (!string.IsNullOrEmpty(data.animTrigger))
_animator.SetTrigger(data.animTrigger);
// 3. 속도에 맞춰 보정된 타격 지연 시간 계산
// 공식: 실제 대기 시간 = 설정된 지연 시간 / 재생 속도
float adjustedImpactDelay = data.impactDelay / finalSpeed;
yield return new WaitForSeconds(adjustedImpactDelay);
// 4. 타격 효과 실행
if (target != null)
{
data.ExecuteEffect(gameObject, target);
}
// 5. 속도에 맞춰 보정된 나머지 시간 계산
float adjustedTotalDuration = data.duration / finalSpeed;
float remainingTime = adjustedTotalDuration - adjustedImpactDelay;
if (remainingTime > 0)
{
yield return new WaitForSeconds(remainingTime);
}
yield return new WaitForSeconds(data.duration);
_isBusy = false;
}
}

View File

@@ -58,6 +58,9 @@ public class PlayerNetworkController : NetworkBehaviour
private bool _isGrounded;
private bool _isHoldingInteract = false;
private bool _isHoldingAction = false;
private bool _hasExecutedOnce = false; // 단발성 액션이 중복 실행되지 않도록 방지
// 현재 플레이어가 어떤 행동을 하고 있는지 나타내는 상태
public enum ActionState { Idle, Busy }
private ActionState _currentState = ActionState.Idle;
@@ -102,8 +105,17 @@ public class PlayerNetworkController : NetworkBehaviour
_inputActions.Player.Action.performed += ctx => OnActionInput();
_inputActions.Player.Interact.performed += ctx => OnInteractTap(); // 탭 상호작용
_inputActions.Player.Interact.started += ctx => _isHoldingInteract = true;
_inputActions.Player.Interact.canceled += ctx => _isHoldingInteract = false;
// started: 버튼을 누르는 순간 즉시 첫 번째 시도
_inputActions.Player.Action.started += ctx => {
_isHoldingAction = true;
_hasExecutedOnce = false; // 누르기 시작할 때 초기화
TryExecuteAction();
};
// canceled: 버튼을 떼는 순간
_inputActions.Player.Action.canceled += ctx => {
_isHoldingAction = false;
};
_inputActions.Player.Select1.performed += ctx => _inventory.ChangeSelectedSlotRpc(0);
_inputActions.Player.Select2.performed += ctx => _inventory.ChangeSelectedSlotRpc(1);
@@ -147,6 +159,12 @@ public class PlayerNetworkController : NetworkBehaviour
_lastRevealTime = Time.time;
RevealSurroundings();
}
// 버튼을 꾹 누르고 있고, 아직 액션이 진행 중이 아닐 때만 반복 체크
if (_isHoldingAction && !_actionHandler.IsBusy)
{
HandleContinuousAction();
}
}
// --- 이동 관련 로직 (기존 유지) ---
@@ -210,6 +228,7 @@ public class PlayerNetworkController : NetworkBehaviour
else
{
Debug.Log("조준된 블록이 없음 (하이라이트 확인 필요)");
_actionHandler.PerformAction(selectedItem.toolAction, null);
}
}
}
@@ -465,6 +484,35 @@ public class PlayerNetworkController : NetworkBehaviour
return closest;
}
private void HandleContinuousAction()
{
ItemData selectedItem = _inventory.GetSelectedItemData();
if (selectedItem == null || !selectedItem.isTool || selectedItem.toolAction == null) return;
// [핵심] 반복 가능한 액션일 때만 Update에서 재실행
if (selectedItem.toolAction.canRepeat)
{
TryExecuteAction();
}
}
private void TryExecuteAction()
{
if (_actionHandler.IsBusy) return;
ItemData selectedItem = _inventory.GetSelectedItemData();
if (selectedItem != null && selectedItem.isTool && selectedItem.toolAction != null)
{
// 단발성 액션인데 이미 한 번 실행했다면 스킵
if (!selectedItem.toolAction.canRepeat && _hasExecutedOnce) return;
GameObject target = _lastHighlightedBlock != null ? _lastHighlightedBlock.gameObject : null;
_actionHandler.PerformAction(selectedItem.toolAction, target);
_hasExecutedOnce = true; // 실행 기록 저장
}
}
private void OnDrawGizmos()
{
if (!Application.isPlaying || !IsOwner) return;