연속 액션 기능 및 관련 설정 기능 추가
This commit is contained in:
@@ -85,6 +85,12 @@ AnimatorController:
|
|||||||
m_DefaultInt: 0
|
m_DefaultInt: 0
|
||||||
m_DefaultBool: 0
|
m_DefaultBool: 0
|
||||||
m_Controller: {fileID: 9100000}
|
m_Controller: {fileID: 9100000}
|
||||||
|
- m_Name: ActionSpeed
|
||||||
|
m_Type: 1
|
||||||
|
m_DefaultFloat: 1
|
||||||
|
m_DefaultInt: 0
|
||||||
|
m_DefaultBool: 0
|
||||||
|
m_Controller: {fileID: 9100000}
|
||||||
m_AnimatorLayers:
|
m_AnimatorLayers:
|
||||||
- serializedVersion: 5
|
- serializedVersion: 5
|
||||||
m_Name: Base Layer
|
m_Name: Base Layer
|
||||||
@@ -108,7 +114,8 @@ AnimatorState:
|
|||||||
m_Name: Locomotion
|
m_Name: Locomotion
|
||||||
m_Speed: 1
|
m_Speed: 1
|
||||||
m_CycleOffset: 0
|
m_CycleOffset: 0
|
||||||
m_Transitions: []
|
m_Transitions:
|
||||||
|
- {fileID: 5226680357144867497}
|
||||||
m_StateMachineBehaviours: []
|
m_StateMachineBehaviours: []
|
||||||
m_Position: {x: 50, y: 50, z: 0}
|
m_Position: {x: 50, y: 50, z: 0}
|
||||||
m_IKOnFeet: 0
|
m_IKOnFeet: 0
|
||||||
@@ -156,7 +163,7 @@ AnimatorState:
|
|||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: Melee_1H_Attack_Chop
|
m_Name: 2H Attack
|
||||||
m_Speed: 1
|
m_Speed: 1
|
||||||
m_CycleOffset: 0
|
m_CycleOffset: 0
|
||||||
m_Transitions:
|
m_Transitions:
|
||||||
@@ -166,13 +173,13 @@ AnimatorState:
|
|||||||
m_IKOnFeet: 0
|
m_IKOnFeet: 0
|
||||||
m_WriteDefaultValues: 1
|
m_WriteDefaultValues: 1
|
||||||
m_Mirror: 0
|
m_Mirror: 0
|
||||||
m_SpeedParameterActive: 0
|
m_SpeedParameterActive: 1
|
||||||
m_MirrorParameterActive: 0
|
m_MirrorParameterActive: 0
|
||||||
m_CycleOffsetParameterActive: 0
|
m_CycleOffsetParameterActive: 0
|
||||||
m_TimeParameterActive: 0
|
m_TimeParameterActive: 0
|
||||||
m_Motion: {fileID: 4043807988371827432, guid: 79b3d1d24644f7d4987c6bdd614dd439, type: 3}
|
m_Motion: {fileID: -3183232228448455838, guid: 79b3d1d24644f7d4987c6bdd614dd439, type: 3}
|
||||||
m_Tag: Attack
|
m_Tag: Attack
|
||||||
m_SpeedParameter:
|
m_SpeedParameter: ActionSpeed
|
||||||
m_MirrorParameter:
|
m_MirrorParameter:
|
||||||
m_CycleOffsetParameter:
|
m_CycleOffsetParameter:
|
||||||
m_TimeParameter:
|
m_TimeParameter:
|
||||||
@@ -243,14 +250,39 @@ AnimatorStateTransition:
|
|||||||
m_Mute: 0
|
m_Mute: 0
|
||||||
m_IsExit: 0
|
m_IsExit: 0
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TransitionDuration: 0.25
|
m_TransitionDuration: 0.1
|
||||||
m_TransitionOffset: 0
|
m_TransitionOffset: 0
|
||||||
m_ExitTime: 0.765625
|
m_ExitTime: 0.9
|
||||||
m_HasExitTime: 1
|
m_HasExitTime: 1
|
||||||
m_HasFixedDuration: 1
|
m_HasFixedDuration: 1
|
||||||
m_InterruptionSource: 0
|
m_InterruptionSource: 0
|
||||||
m_OrderedInterruption: 1
|
m_OrderedInterruption: 1
|
||||||
m_CanTransitionToSelf: 1
|
m_CanTransitionToSelf: 1
|
||||||
|
--- !u!1101 &5226680357144867497
|
||||||
|
AnimatorStateTransition:
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name:
|
||||||
|
m_Conditions:
|
||||||
|
- m_ConditionMode: 1
|
||||||
|
m_ConditionEvent: Attack
|
||||||
|
m_EventTreshold: 0
|
||||||
|
m_DstStateMachine: {fileID: 0}
|
||||||
|
m_DstState: {fileID: 1042583441410514574}
|
||||||
|
m_Solo: 0
|
||||||
|
m_Mute: 0
|
||||||
|
m_IsExit: 0
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransitionDuration: 0.1
|
||||||
|
m_TransitionOffset: 0
|
||||||
|
m_ExitTime: 0.82954544
|
||||||
|
m_HasExitTime: 0
|
||||||
|
m_HasFixedDuration: 1
|
||||||
|
m_InterruptionSource: 0
|
||||||
|
m_OrderedInterruption: 1
|
||||||
|
m_CanTransitionToSelf: 1
|
||||||
--- !u!1101 &7110953658697184367
|
--- !u!1101 &7110953658697184367
|
||||||
AnimatorStateTransition:
|
AnimatorStateTransition:
|
||||||
m_ObjectHideFlags: 1
|
m_ObjectHideFlags: 1
|
||||||
@@ -359,6 +391,6 @@ AnimatorStateTransition:
|
|||||||
m_ExitTime: 0.75
|
m_ExitTime: 0.75
|
||||||
m_HasExitTime: 0
|
m_HasExitTime: 0
|
||||||
m_HasFixedDuration: 1
|
m_HasFixedDuration: 1
|
||||||
m_InterruptionSource: 0
|
m_InterruptionSource: 1
|
||||||
m_OrderedInterruption: 1
|
m_OrderedInterruption: 1
|
||||||
m_CanTransitionToSelf: 1
|
m_CanTransitionToSelf: 0
|
||||||
|
|||||||
@@ -15,4 +15,6 @@ MonoBehaviour:
|
|||||||
actionName: Mining
|
actionName: Mining
|
||||||
duration: 1
|
duration: 1
|
||||||
animTrigger: Attack
|
animTrigger: Attack
|
||||||
|
impactDelay: 0
|
||||||
|
baseSpeed: 5
|
||||||
damage: 50
|
damage: 50
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
||||||
GlobalObjectIdHash: 856270328
|
GlobalObjectIdHash: 4268073897
|
||||||
InScenePlacedSourceGlobalObjectIdHash: 0
|
InScenePlacedSourceGlobalObjectIdHash: 0
|
||||||
DeferredDespawnTick: 0
|
DeferredDespawnTick: 0
|
||||||
Ownership: 1
|
Ownership: 1
|
||||||
@@ -422,7 +422,14 @@ MonoBehaviour:
|
|||||||
NetworkAnimatorExpanded: 0
|
NetworkAnimatorExpanded: 0
|
||||||
AuthorityMode: 0
|
AuthorityMode: 0
|
||||||
m_Animator: {fileID: 5870045807328036684}
|
m_Animator: {fileID: 5870045807328036684}
|
||||||
TransitionStateInfoList: []
|
TransitionStateInfoList:
|
||||||
|
- IsCrossFadeExit: 0
|
||||||
|
Layer: 0
|
||||||
|
OriginatingState: -2089788878
|
||||||
|
DestinationState: -437043462
|
||||||
|
TransitionDuration: 0.1
|
||||||
|
TriggerNameHash: 1080829965
|
||||||
|
TransitionIndex: 0
|
||||||
AnimatorParameterEntries:
|
AnimatorParameterEntries:
|
||||||
ParameterEntries:
|
ParameterEntries:
|
||||||
- name: MoveSpeed
|
- name: MoveSpeed
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ public class MiningActionData : PlayerActionData
|
|||||||
|
|
||||||
public override void ExecuteEffect(GameObject performer, GameObject target)
|
public override void ExecuteEffect(GameObject performer, GameObject target)
|
||||||
{
|
{
|
||||||
|
if(target == null) return;
|
||||||
|
|
||||||
if (target.TryGetComponent<MineableBlock>(out var block))
|
if (target.TryGetComponent<MineableBlock>(out var block))
|
||||||
{
|
{
|
||||||
// 서버 RPC 호출은 블록 내부의 로직을 그대로 사용합니다.
|
// 서버 RPC 호출은 블록 내부의 로직을 그대로 사용합니다.
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ public abstract class PlayerActionData : ScriptableObject
|
|||||||
{
|
{
|
||||||
public string actionName;
|
public string actionName;
|
||||||
public float duration; // 액션 자체가 시간을 가짐
|
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)은 있을 수도 있고(채광), 없을 수도 있음(회복/대쉬)
|
// 대상(target)은 있을 수도 있고(채광), 없을 수도 있음(회복/대쉬)
|
||||||
public abstract void ExecuteEffect(GameObject performer, GameObject target);
|
public abstract void ExecuteEffect(GameObject performer, GameObject target);
|
||||||
|
|||||||
@@ -44,11 +44,36 @@ public class PlayerActionHandler : NetworkBehaviour
|
|||||||
private IEnumerator ActionRoutine(PlayerActionData data, GameObject target)
|
private IEnumerator ActionRoutine(PlayerActionData data, GameObject target)
|
||||||
{
|
{
|
||||||
_isBusy = true;
|
_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;
|
_isBusy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +58,9 @@ public class PlayerNetworkController : NetworkBehaviour
|
|||||||
private bool _isGrounded;
|
private bool _isGrounded;
|
||||||
private bool _isHoldingInteract = false;
|
private bool _isHoldingInteract = false;
|
||||||
|
|
||||||
|
private bool _isHoldingAction = false;
|
||||||
|
private bool _hasExecutedOnce = false; // 단발성 액션이 중복 실행되지 않도록 방지
|
||||||
|
|
||||||
// 현재 플레이어가 어떤 행동을 하고 있는지 나타내는 상태
|
// 현재 플레이어가 어떤 행동을 하고 있는지 나타내는 상태
|
||||||
public enum ActionState { Idle, Busy }
|
public enum ActionState { Idle, Busy }
|
||||||
private ActionState _currentState = ActionState.Idle;
|
private ActionState _currentState = ActionState.Idle;
|
||||||
@@ -102,8 +105,17 @@ public class PlayerNetworkController : NetworkBehaviour
|
|||||||
_inputActions.Player.Action.performed += ctx => OnActionInput();
|
_inputActions.Player.Action.performed += ctx => OnActionInput();
|
||||||
_inputActions.Player.Interact.performed += ctx => OnInteractTap(); // 탭 상호작용
|
_inputActions.Player.Interact.performed += ctx => OnInteractTap(); // 탭 상호작용
|
||||||
|
|
||||||
_inputActions.Player.Interact.started += ctx => _isHoldingInteract = true;
|
// started: 버튼을 누르는 순간 즉시 첫 번째 시도
|
||||||
_inputActions.Player.Interact.canceled += ctx => _isHoldingInteract = false;
|
_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.Select1.performed += ctx => _inventory.ChangeSelectedSlotRpc(0);
|
||||||
_inputActions.Player.Select2.performed += ctx => _inventory.ChangeSelectedSlotRpc(1);
|
_inputActions.Player.Select2.performed += ctx => _inventory.ChangeSelectedSlotRpc(1);
|
||||||
@@ -147,6 +159,12 @@ public class PlayerNetworkController : NetworkBehaviour
|
|||||||
_lastRevealTime = Time.time;
|
_lastRevealTime = Time.time;
|
||||||
RevealSurroundings();
|
RevealSurroundings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 버튼을 꾹 누르고 있고, 아직 액션이 진행 중이 아닐 때만 반복 체크
|
||||||
|
if (_isHoldingAction && !_actionHandler.IsBusy)
|
||||||
|
{
|
||||||
|
HandleContinuousAction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 이동 관련 로직 (기존 유지) ---
|
// --- 이동 관련 로직 (기존 유지) ---
|
||||||
@@ -210,6 +228,7 @@ public class PlayerNetworkController : NetworkBehaviour
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Log("조준된 블록이 없음 (하이라이트 확인 필요)");
|
Debug.Log("조준된 블록이 없음 (하이라이트 확인 필요)");
|
||||||
|
_actionHandler.PerformAction(selectedItem.toolAction, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,6 +484,35 @@ public class PlayerNetworkController : NetworkBehaviour
|
|||||||
return closest;
|
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()
|
private void OnDrawGizmos()
|
||||||
{
|
{
|
||||||
if (!Application.isPlaying || !IsOwner) return;
|
if (!Application.isPlaying || !IsOwner) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user