From 1e0bd1b708286581ab52acd06879cfeb493fe4c6 Mon Sep 17 00:00:00 2001
From: Sehyeon <ksh1837@naver.com>
Date: Sat, 29 Mar 2025 21:29:56 +0900
Subject: [PATCH 1/2] =?UTF-8?q?DO-85=20[Fix]=20=EC=9E=90=EC=9E=98=ED=95=9C?=
 =?UTF-8?q?=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Assets/GameUIController.cs                    | 15 +++++-----
 .../Prefabs/Panels/Confirm Panel.prefab       | 28 +++++++++++++++++
 .../Prefabs/Panels/Draw Confirm Panel.prefab  | 30 +++++++++++++++++++
 .../Prefabs/Panels/Main Panel.prefab          |  8 ++---
 .../Resources/Prefabs/[Canvas] Game UI.prefab |  3 +-
 Assets/Script/Game/GameLogic.cs               | 23 ++++++++------
 Assets/Script/Game/GameManager.cs             | 10 ++++++-
 Assets/Script/Game/GameUtility/GameRoutine.cs |  1 -
 Assets/Script/Game/MultiplayManager.cs        |  9 ++++--
 .../PanelController/ConfirmPanelController.cs |  3 ++
 .../DrawConfirmPanelController.cs             |  5 ++++
 .../Script/UI/PanelController/PanelManager.cs |  7 +++++
 12 files changed, 117 insertions(+), 25 deletions(-)

diff --git a/Assets/GameUIController.cs b/Assets/GameUIController.cs
index 8e49533..12f077d 100644
--- a/Assets/GameUIController.cs
+++ b/Assets/GameUIController.cs
@@ -47,8 +47,7 @@ public class GameUIController : MonoBehaviour
     
     public void OnClickExitButton()
     {
-        // "Main" 씬으로 이동
-        SceneManager.LoadScene("Main");
+        GameManager.Instance.ChangeToMainScene();
     }
 
     public void OnClickSurrenderButton()
@@ -94,12 +93,15 @@ public class GameUIController : MonoBehaviour
 
     public void OnClickRevengeRequestButton()
     {
+        if (!GameManager.Instance.GetGameLogic().OpponentExist)
+        {
+            GameManager.Instance.panelManager.OpenConfirmPanel("상대방이 방을 나갔습니다.",() => { });
+            return;
+        }
+        
         if (GameManager.Instance.CheckIsSinglePlay())
         {
-            GameManager.Instance.panelManager.OpenConfirmPanel("상대방이 방을 나갔습니다.",() =>
-            {
-                
-            });
+            GameManager.Instance.panelManager.OpenConfirmPanel("상대방이 방을 나갔습니다.",() => { });
         }
         else
         {
@@ -178,7 +180,6 @@ public class GameUIController : MonoBehaviour
     /// <param name="gameInProgress">게임 진행이면 true</param>
     public void SetButtonsIndicator(bool gameInProgress)
     {
-        Debug.Log("gameInProgress" + gameInProgress);
         inGameMenuButtonsObject.SetActive(gameInProgress);
         confirmButtonObject.SetActive(gameInProgress);
         timerObject.SetActive(!gameInProgress);
diff --git a/Assets/Resources/Prefabs/Panels/Confirm Panel.prefab b/Assets/Resources/Prefabs/Panels/Confirm Panel.prefab
index 964b583..45ad5f8 100644
--- a/Assets/Resources/Prefabs/Panels/Confirm Panel.prefab	
+++ b/Assets/Resources/Prefabs/Panels/Confirm Panel.prefab	
@@ -146,6 +146,7 @@ GameObject:
   - component: {fileID: 8494676347912440962}
   - component: {fileID: 1257633341820217709}
   - component: {fileID: 1753961836956471979}
+  - component: {fileID: 1873769388125956862}
   m_Layer: 5
   m_Name: Ok Button
   m_TagString: Untagged
@@ -267,6 +268,19 @@ MonoBehaviour:
           m_StringArgument: 
           m_BoolArgument: 0
         m_CallState: 2
+--- !u!114 &1873769388125956862
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317228258542092256}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4330206548604932b038a7007dacf94b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  enableOneTimeClick: 1
 --- !u!1 &4661890517030743811
 GameObject:
   m_ObjectHideFlags: 0
@@ -597,6 +611,7 @@ GameObject:
   - component: {fileID: 2998236242917363859}
   - component: {fileID: 8555214474145769210}
   - component: {fileID: 7759243219178030454}
+  - component: {fileID: 3536771767490368521}
   m_Layer: 5
   m_Name: Close Button
   m_TagString: Untagged
@@ -717,3 +732,16 @@ MonoBehaviour:
           m_StringArgument: 
           m_BoolArgument: 0
         m_CallState: 2
+--- !u!114 &3536771767490368521
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8913073875457554875}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4330206548604932b038a7007dacf94b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  enableOneTimeClick: 1
diff --git a/Assets/Resources/Prefabs/Panels/Draw Confirm Panel.prefab b/Assets/Resources/Prefabs/Panels/Draw Confirm Panel.prefab
index 6976e8f..abe3729 100644
--- a/Assets/Resources/Prefabs/Panels/Draw Confirm Panel.prefab	
+++ b/Assets/Resources/Prefabs/Panels/Draw Confirm Panel.prefab	
@@ -146,6 +146,7 @@ GameObject:
   - component: {fileID: 8494676347912440962}
   - component: {fileID: 1257633341820217709}
   - component: {fileID: 1753961836956471979}
+  - component: {fileID: 158827458667474525}
   m_Layer: 5
   m_Name: Yes Button
   m_TagString: Untagged
@@ -267,6 +268,19 @@ MonoBehaviour:
           m_StringArgument: 
           m_BoolArgument: 0
         m_CallState: 2
+--- !u!114 &158827458667474525
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317228258542092256}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4330206548604932b038a7007dacf94b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  enableOneTimeClick: 1
 --- !u!1 &3698158704839373389
 GameObject:
   m_ObjectHideFlags: 0
@@ -639,6 +653,8 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   panelRectTransform: {fileID: 1049729465715420315}
   messageText: {fileID: 773857893073654059}
+  yesButton: {fileID: 2317228258542092256}
+  noButton: {fileID: 8664974708086771355}
 --- !u!1 &8611399693750823341
 GameObject:
   m_ObjectHideFlags: 0
@@ -729,6 +745,7 @@ GameObject:
   - component: {fileID: 6738990646649674804}
   - component: {fileID: 4523293559331202638}
   - component: {fileID: 3091834035832018361}
+  - component: {fileID: 5520929008480269547}
   m_Layer: 5
   m_Name: No Button
   m_TagString: Untagged
@@ -850,3 +867,16 @@ MonoBehaviour:
           m_StringArgument: 
           m_BoolArgument: 0
         m_CallState: 2
+--- !u!114 &5520929008480269547
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8664974708086771355}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4330206548604932b038a7007dacf94b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  enableOneTimeClick: 1
diff --git a/Assets/Resources/Prefabs/Panels/Main Panel.prefab b/Assets/Resources/Prefabs/Panels/Main Panel.prefab
index ff3e082..3693831 100644
--- a/Assets/Resources/Prefabs/Panels/Main Panel.prefab	
+++ b/Assets/Resources/Prefabs/Panels/Main Panel.prefab	
@@ -1104,7 +1104,7 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_text: "18\uAE09"
+  m_text: "1\uAE09"
   m_isRightToLeft: 0
   m_fontAsset: {fileID: 11400000, guid: 85a19688db53c77469fc4406b01045da, type: 2}
   m_sharedMaterial: {fileID: -2477908578676791210, guid: 85a19688db53c77469fc4406b01045da, type: 2}
@@ -1457,7 +1457,7 @@ GameObject:
   m_Icon: {fileID: 0}
   m_NavMeshLayer: 0
   m_StaticEditorFlags: 0
-  m_IsActive: 0
+  m_IsActive: 1
 --- !u!224 &405965270916774547
 RectTransform:
   m_ObjectHideFlags: 0
@@ -1727,7 +1727,7 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_text: "\uD638\uB7AD\uC774"
+  m_text: ksh
   m_isRightToLeft: 0
   m_fontAsset: {fileID: 11400000, guid: 85a19688db53c77469fc4406b01045da, type: 2}
   m_sharedMaterial: {fileID: -2477908578676791210, guid: 85a19688db53c77469fc4406b01045da, type: 2}
@@ -1813,7 +1813,7 @@ GameObject:
   m_Icon: {fileID: 0}
   m_NavMeshLayer: 0
   m_StaticEditorFlags: 0
-  m_IsActive: 1
+  m_IsActive: 0
 --- !u!224 &8172929902404983356
 RectTransform:
   m_ObjectHideFlags: 0
diff --git a/Assets/Resources/Prefabs/[Canvas] Game UI.prefab b/Assets/Resources/Prefabs/[Canvas] Game UI.prefab
index efff5d1..fdaff28 100644
--- a/Assets/Resources/Prefabs/[Canvas] Game UI.prefab	
+++ b/Assets/Resources/Prefabs/[Canvas] Game UI.prefab	
@@ -2497,7 +2497,8 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: 35a536dce57360441898a57e5d5a1335, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
-  exitButton: {fileID: 2183639868091494604}
+  exitButton: {fileID: 403017146611159122}
+  retryButton: {fileID: 0}
   playerANameText: {fileID: 4888719462249568075}
   playerBNameText: {fileID: 5649645114775233136}
   indicatorA: {fileID: 822440635660578859}
diff --git a/Assets/Script/Game/GameLogic.cs b/Assets/Script/Game/GameLogic.cs
index 837a47c..80106c7 100644
--- a/Assets/Script/Game/GameLogic.cs
+++ b/Assets/Script/Game/GameLogic.cs
@@ -35,6 +35,7 @@ public partial class GameLogic : IDisposable
     public int SelectedCol { get; private set; }
     public FioTimer FioTimer { get; private set; }
     public bool GameInProgress { get; private set; } // 게임 진행 중인지 확인
+    public bool OpponentExist { get; private set; } // 상대방 존재 여부
 
     #endregion
 
@@ -46,6 +47,7 @@ public partial class GameLogic : IDisposable
         InitializeBoard(stoneController, gameType);             // 보드 초기화
         InitializeFioTimer(fioTimer);                           // timer 초기화
         GameModeSetter(gameType);                               // 게임 모드 설정
+        OpponentExist = false;
     }
 
     // 게임 모드 분기 처리
@@ -114,17 +116,16 @@ public partial class GameLogic : IDisposable
                     StartGameOnMainThread();
                     break;
                 case Constants.MultiplayManagerState.ExitRoom:
-                    Debug.Log("## Exit Room"); 
+                    Debug.Log("## Exit Room"); // 방을 나갔으니 room id == null
+                    OpponentExist = false;
                     // TODO: Exit Room 처리
                     break;
                 case Constants.MultiplayManagerState.EndGame:
                     Debug.Log("## End Game");
+                    OpponentExist = false;
                     ExecuteOnMainThread(() =>
                     {
-                        GameManager.Instance.panelManager.OpenConfirmPanel("상대방이 방을 나갔습니다.", () => 
-                        {
-                            // TODO: 무승부/항복 등 버튼 동작 안하도록 처리
-                        });
+                        GameManager.Instance.panelManager.OpenConfirmPanel("상대방이 방을 나갔습니다.", () => { });
                     });
                     break;
                 case Constants.MultiplayManagerState.DoSurrender:
@@ -298,6 +299,7 @@ public partial class GameLogic : IDisposable
                     break;
                 case Constants.MultiplayManagerState.OpponentDisconnected:
                     Debug.Log("상대방 강제 종료");
+                    OpponentExist = false;
                     ExecuteOnMainThread(() =>
                     {
                         GameManager.Instance.panelManager.OpenConfirmPanel("연결이 끊어졌습니다.", () => 
@@ -338,6 +340,8 @@ public partial class GameLogic : IDisposable
 
             UpdateUIForSecondPlayer(_opponentNickname, _opponentImageIndex);
         }
+
+        OpponentExist = true;
     }
 
     private void UpdateUIForFirstPlayer(string opponentNickname, int opponentImageIndex)
@@ -369,9 +373,8 @@ public partial class GameLogic : IDisposable
     private void StartGameOnMainThread()
     {
         ChangeGameInProgress(true);
-        Debug.Log("GameInProgress 변경 true");
         GameButtonSetter(GameInProgress); // 버튼 상태 교체
-
+        
         ExecuteOnMainThread(() =>
         {
             // 로딩 패널 열려있으면 닫기
@@ -601,13 +604,15 @@ public partial class GameLogic : IDisposable
     
     public void Dispose()
     {
-        MultiPlayManager?.LeaveRoom(_roomId);
+        MultiPlayManager?.LeaveRoom();
+        _roomId = null; // room id 초기화
         MultiPlayManager?.Dispose();
     }
     
     public void ForceQuit()
     {
-        MultiPlayManager?.ForceQuit(_roomId);
+        MultiPlayManager?.ForceQuit();
+        _roomId = null;
         MultiPlayManager?.Dispose();
     }
 }
diff --git a/Assets/Script/Game/GameManager.cs b/Assets/Script/Game/GameManager.cs
index 91a135b..32b56e3 100644
--- a/Assets/Script/Game/GameManager.cs
+++ b/Assets/Script/Game/GameManager.cs
@@ -27,6 +27,11 @@ public class GameManager : Singleton<GameManager>
         base.Awake();
         InitPanels();
     }
+
+    public GameLogic GetGameLogic()
+    {
+        return _gameLogic;
+    }
     
     public MultiplayManager GetMultiplayManager()
     {
@@ -78,7 +83,10 @@ public class GameManager : Singleton<GameManager>
     {
         _gameType = Enums.GameType.None;
         // TODO: 추후 혹시 모를 존재하는 socket 통신 종료 필요 - _gameLogic?.Dispose에서 LeaveRoom 호출하긴 하는데 서버에서 이미 해당 방을 삭제했을 경우 동작 확인 필요
-        // _gameLogic?.Dispose();
+        if (_multiplayManager.GetRoomId() != null) // null 에러 방지
+        {
+            _gameLogic?.Dispose();
+        }
         SceneManager.LoadScene("Main");
     }
 
diff --git a/Assets/Script/Game/GameUtility/GameRoutine.cs b/Assets/Script/Game/GameUtility/GameRoutine.cs
index 9668342..03ae7d0 100644
--- a/Assets/Script/Game/GameUtility/GameRoutine.cs
+++ b/Assets/Script/Game/GameUtility/GameRoutine.cs
@@ -90,7 +90,6 @@ public partial class GameLogic
         ReplayManager.Instance.SaveReplayDataResult(result);
         //TODO: 게임 종료 후 행동 구현
         ChangeGameInProgress(false);
-        Debug.Log("GameInProgress 변경 false");
         // 인게임 버튼 표시
         GameManager.Instance.SetButtonsIndicator(false);
     }
diff --git a/Assets/Script/Game/MultiplayManager.cs b/Assets/Script/Game/MultiplayManager.cs
index 1e8c232..3c659d6 100644
--- a/Assets/Script/Game/MultiplayManager.cs
+++ b/Assets/Script/Game/MultiplayManager.cs
@@ -206,7 +206,7 @@ public class MultiplayManager : IDisposable
         _onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.EndGame, null);
     }
 
-    public void LeaveRoom(string roomId)
+    public void LeaveRoom() // MultiplayManager에 있는 _roomId 사용, 매개변수 필요 X
     {
         if (string.IsNullOrEmpty(_roomId))
         {
@@ -218,7 +218,7 @@ public class MultiplayManager : IDisposable
         _roomId = null; // 방 나가면 roomId 초기화
     }
     
-    public void ForceQuit(string roomId)
+    public void ForceQuit()
     {
         if (string.IsNullOrEmpty(_roomId))
         {
@@ -454,4 +454,9 @@ public class MultiplayManager : IDisposable
             _roomId = null;
         }
     }
+
+    public string GetRoomId()
+    {
+        return _roomId;
+    }
 }
diff --git a/Assets/Script/UI/PanelController/ConfirmPanelController.cs b/Assets/Script/UI/PanelController/ConfirmPanelController.cs
index 3119812..8ad45b5 100644
--- a/Assets/Script/UI/PanelController/ConfirmPanelController.cs
+++ b/Assets/Script/UI/PanelController/ConfirmPanelController.cs
@@ -15,6 +15,9 @@ public class ConfirmPanelController : PanelController
     
     public void Show(string message, OnConfirmButtonClick onConfirmButtonClick, bool isClose, bool isConfirm)
     {
+        confirmButton.GetComponent<SingleInteractableButtonHandler>().ResetButton();
+        closeButton.GetComponent<SingleInteractableButtonHandler>().ResetButton();
+        
         messageText.text = message;
         this.onConfirmButtonClick = onConfirmButtonClick;
         closeButton.SetActive(isClose);
diff --git a/Assets/Script/UI/PanelController/DrawConfirmPanelController.cs b/Assets/Script/UI/PanelController/DrawConfirmPanelController.cs
index 4ff1379..982df81 100644
--- a/Assets/Script/UI/PanelController/DrawConfirmPanelController.cs
+++ b/Assets/Script/UI/PanelController/DrawConfirmPanelController.cs
@@ -6,6 +6,8 @@ using UnityEngine;
 public class DrawConfirmPanelController : PanelController
 {
     [SerializeField] private TMP_Text messageText;  //자식 텍스트 변수
+    [SerializeField] private GameObject yesButton;
+    [SerializeField] private GameObject noButton;
 
     public delegate void OnConfirmButtonClick();
     private OnConfirmButtonClick onConfirmButtonClick;
@@ -15,6 +17,9 @@ public class DrawConfirmPanelController : PanelController
 
     public void Show(string message, OnConfirmButtonClick onConfirmButtonClick, OnContradictButtonClick onContradictButtonClick)
     {
+        yesButton.GetComponent<SingleInteractableButtonHandler>().ResetButton();
+        noButton.GetComponent<SingleInteractableButtonHandler>().ResetButton();
+        
         messageText.text = message;
         this.onConfirmButtonClick = onConfirmButtonClick;
         this.onContradictButtonClick = onContradictButtonClick;
diff --git a/Assets/Script/UI/PanelController/PanelManager.cs b/Assets/Script/UI/PanelController/PanelManager.cs
index 9448713..0ae7365 100644
--- a/Assets/Script/UI/PanelController/PanelManager.cs
+++ b/Assets/Script/UI/PanelController/PanelManager.cs
@@ -66,6 +66,13 @@ public class PanelManager : MonoBehaviour
 
     public GameObject GetEffectPanel(string panelName)
     {
+        // 게임 결과 이펙트 전에 로딩 패널이 있으면 닫기
+        if (loadingPanelObject != null && loadingPanelObject.activeSelf)
+        {
+            CloseLoadingPanel();
+            Destroy(loadingPanelObject);
+        }
+        
         if (effectPanelPrefabs.TryGetValue(panelName, out GameObject prefab))
         {
             return Instantiate(prefab, _canvas.transform);

From 5d42eb7fbe2d7dac9e39e80a1abf6d77f15da94b Mon Sep 17 00:00:00 2001
From: HaeinLEE <heyin0122@korea.ac.kr~>
Date: Sun, 30 Mar 2025 17:26:41 +0900
Subject: [PATCH 2/2] =?UTF-8?q?[Fix]=20=EB=A1=9C=EB=94=A9=ED=99=94?=
 =?UTF-8?q?=EB=A9=B4=20=EB=B2=84=EA=B7=B8=20=ED=95=B4=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

CloseLoadingPanel 대신 잘못된 함수 호출, TimerUnpause과의 순서 수정
---
 Assets/Script/Game/GameLogic.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Assets/Script/Game/GameLogic.cs b/Assets/Script/Game/GameLogic.cs
index 837a47c..1b63fee 100644
--- a/Assets/Script/Game/GameLogic.cs
+++ b/Assets/Script/Game/GameLogic.cs
@@ -190,19 +190,19 @@ public partial class GameLogic : IDisposable
                 }
                 case Constants.MultiplayManagerState.DrawRejected:
                     Debug.Log("무승부 요청이 거부가 들어옴");
-                    TimerUnpause();
                     ExecuteOnMainThread(() =>
                     {
                         GameManager.Instance.panelManager.CloseLoadingPanel();
                         GameManager.Instance.panelManager.OpenConfirmPanel("무승부 요청을 거부하였습니다.", () => { });
                     });
+                    TimerUnpause();
                     break;
                 case Constants.MultiplayManagerState.DrawRejectionConfirmed:
                 {
                     Debug.Log("무승부 요청 거부 완료");
                     ExecuteOnMainThread(() =>
                     {
-                        GameManager.Instance.panelManager.OpenLoadingPanel(true, true, false, false);
+                        GameManager.Instance.panelManager.CloseLoadingPanel();
                     });
                     TimerUnpause();
                     break;