Skip to content

Commit af415ee

Browse files
committed
ESC 일시정지 시 외부 입력 차단
1 parent 7d9dd19 commit af415ee

8 files changed

Lines changed: 195 additions & 8 deletions

File tree

Assets/Plugins/FMOD/Cache/Editor/FMODStudioCache.asset

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ MonoBehaviour:
490490
StringsBanks:
491491
- {fileID: 6573240060274684362}
492492
cacheVersion: 131858
493-
cacheTime: 639150932071371481
493+
cacheTime: 639150090963297375
494494
SerializableEventsDict:
495495
- key: event:/SFX/Player/Landing
496496
index: 0
@@ -1116,7 +1116,7 @@ MonoBehaviour:
11161116
Path: FMOD_Project/Build/Desktop/Master.bank
11171117
Name: Master
11181118
StudioPath: bank:/Master
1119-
lastModified: 639150932071371481
1119+
lastModified: 639150090963297375
11201120
FileSizes:
11211121
- Name: Desktop
11221122
Value: 3753952
@@ -1136,7 +1136,7 @@ MonoBehaviour:
11361136
Path: FMOD_Project/Build/Desktop/Master.strings.bank
11371137
Name: Master.strings
11381138
StudioPath: bank:/Master.strings
1139-
lastModified: 639149993704398228
1139+
lastModified: 639150012489183501
11401140
FileSizes:
11411141
- Name: Desktop
11421142
Value: 2922
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
**ESC 일시정지 입력 차단 계획**
2+
3+
**요약**
4+
- ESC 일시정지는 **로컬 플레이어 입력만 멈추는 방식**으로 처리합니다.
5+
- 멀티플레이 세션, 서버 로직, 다른 플레이어, UI 애니메이션은 계속 동작합니다.
6+
- 현재 문제의 핵심은 `PlayerInputActions`만 꺼지고 `PlayerController.Update()`의 카메라/이동 루프가 계속 도는 점이므로, 게임플레이 루프 자체를 일시정지 상태에서 막습니다.
7+
8+
**주요 변경**
9+
- [PlayerController.cs](<C:\Users\robor\Documents\GitHub\NUNBORA\Assets\_Project\Scripts\02_Player\PlayerController.cs>)에서 `PauseMenuManager.IsAnyUIOpen()`이 true면 게임플레이 업데이트를 중단합니다.
10+
- 카메라 회전, 이동 FSM, 중력, `Controller.Move`, 자세 전환, 아이템 사용을 막습니다.
11+
- 일시정지 진입 시 `currentVelocity`도 0으로 만들어 관성처럼 미끄러지는 현상을 막습니다.
12+
- [RoomLauncher.cs](<C:\Users\robor\Documents\GitHub\NUNBORA\Assets\_Project\Scripts\06_Backend\RoomLauncher.cs>)`OnInput`에서 일시정지 또는 UI 오픈 중이면 빈 입력을 전송합니다.
13+
- 네트워크 입력에 이전 프레임의 이동/시점/공격 값이 새는 것을 막습니다.
14+
- [PlayerInputHandler.cs](<C:\Users\robor\Documents\GitHub\NUNBORA\Assets\_Project\Scripts\02_Player\PlayerInputHandler.cs>)의 기존 `SetInputActive(false)`와 입력 리셋 구조는 유지하되, UI가 닫힌 뒤에만 정상 입력으로 복귀하도록 정리합니다.
15+
16+
**일시정지 중 막아야 할 것**
17+
- 마우스 시점 회전, 카메라 반동 복귀, 뷰모델 흔들림
18+
- 이동, 달리기, 점프, 앉기, 중력 이동, 남아 있는 속도
19+
- 공격/아이템 사용, 조준, 상호작용, 홀드 상호작용
20+
- 아이템 줍기, 문 열기, 상점/루팅 상호작용
21+
- 퀵슬롯 숫자키, 재장전/회전 같은 게임플레이 단축키
22+
- 네트워크 이동/시점/액션 입력 전송
23+
- 메뉴 뒤쪽의 상호작용 하이라이트와 안내 프롬프트 갱신
24+
25+
**테스트**
26+
- ESC 화면에서 마우스를 움직여도 카메라가 움직이지 않아야 합니다.
27+
- 이동/달리기/점프 중 ESC를 눌러도 플레이어가 멈춰야 합니다.
28+
- 낙하나 이동 중 ESC를 눌렀을 때 미끄러지지 않아야 합니다.
29+
- 일시정지 메뉴 버튼, 설정창, 확인창은 정상 클릭되어야 합니다.
30+
- 재개 후 커서가 다시 잠기고 입력이 정상 복구되어야 합니다.
31+
- 멀티플레이에서는 내 일시정지가 다른 플레이어나 서버 진행을 멈추지 않아야 합니다.
32+
33+
**가정**
34+
- ESC 일시정지는 멀티플레이 기준으로 로컬 입력만 차단합니다.
35+
- `Time.timeScale = 0`은 사용하지 않습니다.
36+
- 기존 인벤토리/상점/루팅 UI도 `PauseMenuManager.IsAnyUIOpen()` 기준으로 게임플레이 입력을 막습니다.

Assets/_Project/Scripts/01_PM/PlayerInteraction.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ private void Update()
8181
return;
8282
}
8383

84+
if (PauseMenuManager.IsAnyUIOpen())
85+
{
86+
ClearCurrentInteractable();
87+
ClearProximityHint();
88+
player.InputHandler.ConsumeInteract();
89+
return;
90+
}
91+
8492
CheckInteractionFocus();
8593
if (currentLookObject == null)
8694
{

Assets/_Project/Scripts/02_Player/PlayerCameraHandler.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,37 @@ private void Update()
5252
return;
5353
}
5454

55+
if (ShouldBlockLocalCameraEffectsForUI())
56+
{
57+
targetAmplitude = 0f;
58+
targetFrequency = 0f;
59+
noiseComponent.AmplitudeGain = 0f;
60+
noiseComponent.FrequencyGain = 0f;
61+
return;
62+
}
63+
5564
UpdateHeadbobTargets();
5665

5766
noiseComponent.AmplitudeGain = Mathf.Lerp(noiseComponent.AmplitudeGain, targetAmplitude, Time.deltaTime * transitionSpeed);
5867
noiseComponent.FrequencyGain = Mathf.Lerp(noiseComponent.FrequencyGain, targetFrequency, Time.deltaTime * transitionSpeed);
5968
}
6069

70+
private bool ShouldBlockLocalCameraEffectsForUI()
71+
{
72+
if (!PauseMenuManager.IsAnyUIOpen())
73+
{
74+
return false;
75+
}
76+
77+
if (player.IsLocalPlayer)
78+
{
79+
return true;
80+
}
81+
82+
return LocalPlayerReferenceResolver.TryGetLocalPlayer(out PlayerController localPlayer) &&
83+
localPlayer == player;
84+
}
85+
6186
private void UpdateHeadbobTargets()
6287
{
6388
Vector3 horizontalVelocity = new Vector3(player.Controller.velocity.x, 0f, player.Controller.velocity.z);
@@ -109,4 +134,4 @@ public void TestLocalCameraSetup()
109134
Debug.LogWarning("씬에 CinemachineCamera가 없습니다.");
110135
}
111136
}
112-
}
137+
}

Assets/_Project/Scripts/02_Player/PlayerController.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public class PlayerController : MonoBehaviour, IPlayerNetworkConfigurable
8282
[Header("Camera Recoil")]
8383
public float recoilReturnSpeed = 2f; // 반동이 원위치로 돌아오는 속도
8484
private float currentRecoilOffset = 0f; // 현재 적용된 반동 수치
85+
private bool wasGameplayBlockedByUI;
8586

8687
private void Awake()
8788
{
@@ -182,6 +183,14 @@ private void Update()
182183

183184
CheckEnvironmentFlags();
184185

186+
if (ShouldBlockLocalGameplayForUI())
187+
{
188+
FreezeLocalGameplayForUI();
189+
return;
190+
}
191+
192+
wasGameplayBlockedByUI = false;
193+
185194
if (canLook)
186195
{
187196
HandleLook();
@@ -206,6 +215,11 @@ private void Update()
206215

207216
private void FixedUpdate()
208217
{
218+
if (ShouldBlockLocalGameplayForUI())
219+
{
220+
return;
221+
}
222+
209223
StateMachine.CurrentState.PhysicsUpdate();
210224
}
211225

@@ -215,6 +229,36 @@ private void CheckEnvironmentFlags()
215229
IsGrounded = Controller.isGrounded;
216230
}
217231

232+
private bool ShouldBlockLocalGameplayForUI()
233+
{
234+
if (!PauseMenuManager.IsAnyUIOpen())
235+
{
236+
return false;
237+
}
238+
239+
if (IsLocalPlayer)
240+
{
241+
return true;
242+
}
243+
244+
return LocalPlayerReferenceResolver.TryGetLocalPlayer(out PlayerController localPlayer) &&
245+
localPlayer == this;
246+
}
247+
248+
private void FreezeLocalGameplayForUI()
249+
{
250+
currentVelocity = Vector3.zero;
251+
InputHandler?.ClearInputState();
252+
253+
if (!wasGameplayBlockedByUI && Animator != null)
254+
{
255+
Animator.SetSprinting(false);
256+
Animator.UpdateMovement(Vector2.zero);
257+
}
258+
259+
wasGameplayBlockedByUI = true;
260+
}
261+
218262
private void ApplyGravity()
219263
{
220264
if (IsGrounded && currentVelocity.y < 0)

Assets/_Project/Scripts/02_Player/PlayerInputHandler.cs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class PlayerInputHandler : MonoBehaviour, IPlayerNetworkConfigurable
2424
private bool _useNetworkInputOverride;
2525
private PlayerInputSnapshot _networkSnapshot;
2626
private bool _previousNetworkCrouch;
27+
private bool _networkConfigured;
28+
private bool _isLocalPlayer;
2729

2830
private void Awake()
2931
{
@@ -54,6 +56,12 @@ private void Awake()
5456

5557
private void Update()
5658
{
59+
if (ShouldBlockLocalGameplayInput())
60+
{
61+
ResetAllInputs();
62+
return;
63+
}
64+
5765
if (_useNetworkInputOverride)
5866
{
5967
ApplySnapshotToCurrentState(_networkSnapshot);
@@ -67,7 +75,14 @@ private void Update()
6775

6876
private void OnEnable()
6977
{
70-
inputActions.Enable();
78+
if (!ShouldBlockLocalGameplayInput())
79+
{
80+
inputActions.Enable();
81+
}
82+
else
83+
{
84+
ResetAllInputs();
85+
}
7186
}
7287

7388
private void OnDisable()
@@ -95,7 +110,7 @@ public void DisableInput()
95110
/// </summary>
96111
public void SetInputActive(bool isActive)
97112
{
98-
if (isActive)
113+
if (isActive && !ShouldBlockLocalGameplayInput())
99114
{
100115
inputActions.Enable();
101116
}
@@ -121,6 +136,28 @@ private void ResetAllInputs()
121136
_previousNetworkCrouch = false;
122137
}
123138

139+
public void ClearInputState()
140+
{
141+
ResetAllInputs();
142+
}
143+
144+
private bool ShouldBlockLocalGameplayInput()
145+
{
146+
if (!PauseMenuManager.IsAnyUIOpen())
147+
{
148+
return false;
149+
}
150+
151+
if (_networkConfigured)
152+
{
153+
return _isLocalPlayer;
154+
}
155+
156+
return LocalPlayerReferenceResolver.TryGetLocalPlayer(out PlayerController localPlayer) &&
157+
localPlayer != null &&
158+
localPlayer.InputHandler == this;
159+
}
160+
124161

125162

126163
public void SetNetworkInputOverride(bool enabled)
@@ -138,8 +175,14 @@ public void SetNetworkInputOverride(bool enabled)
138175
return;
139176
}
140177

141-
if (isActiveAndEnabled && inputActions != null)
178+
if (isActiveAndEnabled && inputActions != null && !ShouldBlockLocalGameplayInput())
179+
{
142180
inputActions.Enable();
181+
}
182+
else
183+
{
184+
ResetAllInputs();
185+
}
143186
}
144187

145188
public void ApplyNetworkSnapshot(PlayerInputSnapshot snapshot)
@@ -175,6 +218,9 @@ private void ApplySnapshotToCurrentState(PlayerInputSnapshot snapshot)
175218

176219
public void ConfigureForNetwork(bool isLocalPlayer)
177220
{
221+
_networkConfigured = true;
222+
_isLocalPlayer = isLocalPlayer;
223+
178224
if (isLocalPlayer)
179225
{
180226
SetInputActive(true);

Assets/_Project/Scripts/02_Player/Utilities/PlayerViewmodelController.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ private void LateUpdate()
7373
{
7474
if (inputHandler == null || player == null) return;
7575

76+
if (ShouldBlockLocalViewmodelForUI())
77+
{
78+
return;
79+
}
80+
7681
// ==========================================
7782
// 1. Sway
7883
// ==========================================
@@ -152,4 +157,20 @@ private void LateUpdate()
152157
viewmodelTransform.localPosition = defaultLocalPos + currentSwayPos + currentBobPos + currentRecoilPos;
153158
viewmodelTransform.localRotation = defaultLocalRot * currentSwayRot * currentRecoilRot;
154159
}
155-
}
160+
161+
private bool ShouldBlockLocalViewmodelForUI()
162+
{
163+
if (!PauseMenuManager.IsAnyUIOpen())
164+
{
165+
return false;
166+
}
167+
168+
if (player.IsLocalPlayer)
169+
{
170+
return true;
171+
}
172+
173+
return LocalPlayerReferenceResolver.TryGetLocalPlayer(out PlayerController localPlayer) &&
174+
localPlayer == player;
175+
}
176+
}

Assets/_Project/Scripts/06_Backend/RoomLauncher.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,13 @@ public void OnInput(NetworkRunner runner, NetworkInput input)
15041504

15051505
BackendPlayerNetworkInput payload = default;
15061506
PlayerInputHandler inputHandler = GetOrResolveLocalInputHandler(runner);
1507+
if (PauseMenuManager.IsAnyUIOpen())
1508+
{
1509+
inputHandler?.ClearInputState();
1510+
input.Set(payload);
1511+
return;
1512+
}
1513+
15071514
if (inputHandler != null)
15081515
{
15091516
payload.Move = inputHandler.MoveInput;

0 commit comments

Comments
 (0)