Merge branch 'main' into DO-56-승급-패널-구현

# Conflicts:
#	Assets/Script/Main/NetworkManager.cs
This commit is contained in:
HaeinLEE 2025-03-27 14:34:37 +09:00
commit 7d787e0749
48 changed files with 864 additions and 641 deletions

View File

@ -18,10 +18,16 @@ public class GameUIController : MonoBehaviour
[SerializeField] private Sprite[] profileImageSprites; //0. 기본 드래곤 1. 기본 호랑이 2.아이보리 드래곤 3. 아이보리 호랑이 [SerializeField] private Sprite[] profileImageSprites; //0. 기본 드래곤 1. 기본 호랑이 2.아이보리 드래곤 3. 아이보리 호랑이
[SerializeField] private Sprite[] indicatorSprites; //0. active 1. inactive [SerializeField] private Sprite[] indicatorSprites; //0. active 1. inactive
private Sprite _originalSpriteA; private Sprite _originalSpriteA;
private Sprite _originalSpriteB; private Sprite _originalSpriteB;
private MultiplayManager _multiplayManager;
private void Start()
{
_multiplayManager = GameManager.Instance.GetMultiplayManager();
}
public void OnClickConfirmButton() public void OnClickConfirmButton()
{ {
GameManager.Instance.OnClickConfirmButton(); GameManager.Instance.OnClickConfirmButton();
@ -36,9 +42,7 @@ public class GameUIController : MonoBehaviour
{ {
GameManager.Instance.panelManager.OpenConfirmPanel("항복 하시겠습니까?", () => GameManager.Instance.panelManager.OpenConfirmPanel("항복 하시겠습니까?", () =>
{ {
//TODO: 서버에 항복 전달 및 기타 등등 _multiplayManager.RequestSurrender();
GameManager.Instance.ChangeToMainScene();
}); });
} }

View File

@ -10,7 +10,6 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 2402232447803946232} - component: {fileID: 2402232447803946232}
- component: {fileID: 3667565604047053759} - component: {fileID: 3667565604047053759}
- component: {fileID: 841089304725320238}
m_Layer: 0 m_Layer: 0
m_Name: Audio Manager m_Name: Audio Manager
m_TagString: Untagged m_TagString: Untagged
@ -46,103 +45,16 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
mainBgm: {fileID: 8300000, guid: 1d9c7fb20aa822c48933d00b6bd6a757, type: 3} mainBgm: {fileID: 8300000, guid: 1d9c7fb20aa822c48933d00b6bd6a757, type: 3}
gameBgm: {fileID: 8300000, guid: 6d4eda23943dd0b4099b86b28fa0840c, type: 3} gameBgm: {fileID: 8300000, guid: 576c895328ccd5f4a91364f7fa42bea8, type: 3}
clickSound: {fileID: 8300000, guid: cff2e6cf7f46a074d86955b3b6fd499a, type: 3} clickSound: {fileID: 8300000, guid: cff2e6cf7f46a074d86955b3b6fd499a, type: 3}
closeSound: {fileID: 8300000, guid: e7c0f32158a3e5b46bc3b59035aba898, type: 3} closeSound: {fileID: 8300000, guid: e7c0f32158a3e5b46bc3b59035aba898, type: 3}
sfxVolume: 0 coinsAddSound: {fileID: 8300000, guid: 1ec44182fa76a4b3eb1459c0a6d9a8ab, type: 3}
--- !u!82 &841089304725320238 coinsEmptySound: {fileID: 8300000, guid: 908a78cb991984977bea42916bed8684, type: 3}
AudioSource: coinsRemoveSound: {fileID: 8300000, guid: 585a9de0fb7ee4163af5c559ba5b2364, type: 3}
m_ObjectHideFlags: 0 winSound: {fileID: 8300000, guid: 1613a4bf934e4d043b4e50b1b74c16b5, type: 3}
m_CorrespondingSourceObject: {fileID: 0} loseSound: {fileID: 8300000, guid: 2a467daa72a01214384d2fa5677f668a, type: 3}
m_PrefabInstance: {fileID: 0} stoneSound: {fileID: 8300000, guid: 829ae38dccffa8f4ebf5829b8963ad31, type: 3}
m_PrefabAsset: {fileID: 0} bgmAudioSource: {fileID: 0}
m_GameObject: {fileID: 2946408323859178723} sfxVolume: 1
m_Enabled: 1 isPlayBGM: 0
serializedVersion: 4 isPlaySFX: 0
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4

View File

@ -527,6 +527,7 @@ GameObject:
- component: {fileID: 8635639988778983738} - component: {fileID: 8635639988778983738}
- component: {fileID: 4545556044007292713} - component: {fileID: 4545556044007292713}
- component: {fileID: 6152865991947934791} - component: {fileID: 6152865991947934791}
- component: {fileID: 3813612584874639807}
m_Layer: 5 m_Layer: 5
m_Name: Draw Effect Panel m_Name: Draw Effect Panel
m_TagString: Untagged m_TagString: Untagged
@ -624,3 +625,48 @@ MonoBehaviour:
tigerOpenEyes: {fileID: 1508819185250841244} tigerOpenEyes: {fileID: 1508819185250841244}
tigerCloseEyes: {fileID: 399504369641388738} tigerCloseEyes: {fileID: 399504369641388738}
flipDuration: 0.3 flipDuration: 0.3
--- !u!61 &3813612584874639807
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8383435151006156655}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: 0}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
oldSize: {x: 0, y: 0}
newSize: {x: 0, y: 0}
adaptiveTilingThreshold: 0
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 1, y: 1}
m_EdgeRadius: 0

View File

@ -450,6 +450,7 @@ GameObject:
- component: {fileID: 8635639988778983738} - component: {fileID: 8635639988778983738}
- component: {fileID: 4545556044007292713} - component: {fileID: 4545556044007292713}
- component: {fileID: 3229800624310508893} - component: {fileID: 3229800624310508893}
- component: {fileID: 6984539173991577744}
m_Layer: 5 m_Layer: 5
m_Name: Lose Effect Panel m_Name: Lose Effect Panel
m_TagString: Untagged m_TagString: Untagged
@ -546,3 +547,48 @@ MonoBehaviour:
characterOpenEyes: {fileID: 1632927645355555415} characterOpenEyes: {fileID: 1632927645355555415}
characterCloseEyes: {fileID: 3881260292094838299} characterCloseEyes: {fileID: 3881260292094838299}
depressedEffect: {fileID: 155037671892554820} depressedEffect: {fileID: 155037671892554820}
--- !u!61 &6984539173991577744
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8383435151006156655}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: 0}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
oldSize: {x: 0, y: 0}
newSize: {x: 0, y: 0}
adaptiveTilingThreshold: 0
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 1, y: 1}
m_EdgeRadius: 0

View File

@ -788,6 +788,7 @@ GameObject:
- component: {fileID: 8635639988778983738} - component: {fileID: 8635639988778983738}
- component: {fileID: 3127148509640414758} - component: {fileID: 3127148509640414758}
- component: {fileID: 4545556044007292713} - component: {fileID: 4545556044007292713}
- component: {fileID: 7229651074095795597}
m_Layer: 5 m_Layer: 5
m_Name: Win Effect Panel m_Name: Win Effect Panel
m_TagString: Untagged m_TagString: Untagged
@ -866,7 +867,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 9b132148519758c42824252ec9a2d3a4, type: 3} m_Script: {fileID: 11500000, guid: 9b132148519758c42824252ec9a2d3a4, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
bannerObj: {fileID: 0} bannerObj: {fileID: 7291411618834705046}
bannerText: {fileID: 5108301403921453943} bannerText: {fileID: 5108301403921453943}
interval: 0.1 interval: 0.1
haloEffectImg: {fileID: 376994097320605198} haloEffectImg: {fileID: 376994097320605198}
@ -890,6 +891,51 @@ CanvasGroup:
m_Interactable: 1 m_Interactable: 1
m_BlocksRaycasts: 1 m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0 m_IgnoreParentGroups: 0
--- !u!61 &7229651074095795597
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8383435151006156655}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: 0}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
oldSize: {x: 0, y: 0}
newSize: {x: 0, y: 0}
adaptiveTilingThreshold: 0
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 1, y: 1}
m_EdgeRadius: 0
--- !u!1 &8851077685063213123 --- !u!1 &8851077685063213123
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -10,7 +10,6 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 1769668775421633028} - component: {fileID: 1769668775421633028}
- component: {fileID: 4222531876603999234} - component: {fileID: 4222531876603999234}
- component: {fileID: 5499754916380040505}
m_Layer: 5 m_Layer: 5
m_Name: Coins Panel m_Name: Coins Panel
m_TagString: Untagged m_TagString: Untagged
@ -53,106 +52,6 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
coinsRemoveImageObject: {fileID: 4198953742281733827} coinsRemoveImageObject: {fileID: 4198953742281733827}
coinsCountText: {fileID: 2892066450466788586} coinsCountText: {fileID: 2892066450466788586}
coinsRemoveAudioClip: {fileID: 8300000, guid: 585a9de0fb7ee4163af5c559ba5b2364, type: 3}
coinsAddAudioClip: {fileID: 8300000, guid: 1ec44182fa76a4b3eb1459c0a6d9a8ab, type: 3}
coinsEmptyAudioClip: {fileID: 8300000, guid: 908a78cb991984977bea42916bed8684, type: 3}
ShopPanel: {fileID: 8190964574954487140, guid: eb257b0a685b2254f860f294ce8cba54, type: 3}
--- !u!82 &5499754916380040505
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 646100354038727038}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!1 &4198953742281733827 --- !u!1 &4198953742281733827
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -13,9 +13,8 @@ GameObject:
- component: {fileID: 5762671619601460934} - component: {fileID: 5762671619601460934}
- component: {fileID: 6789969287113785900} - component: {fileID: 6789969287113785900}
- component: {fileID: 413977444317235173} - component: {fileID: 413977444317235173}
- component: {fileID: 6428684691423417346}
m_Layer: 5 m_Layer: 5
m_Name: Switch m_Name: BGM Switch
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -148,103 +147,6 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
handleImage: {fileID: 6756679498073114696} handleImage: {fileID: 6756679498073114696}
clickSound: {fileID: 8300000, guid: cff2e6cf7f46a074d86955b3b6fd499a, type: 3}
--- !u!82 &6428684691423417346
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 212417647848747046}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!1 &1754413034098038561 --- !u!1 &1754413034098038561
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -859,9 +761,8 @@ GameObject:
- component: {fileID: 2622934673103949083} - component: {fileID: 2622934673103949083}
- component: {fileID: 3464089222698319368} - component: {fileID: 3464089222698319368}
- component: {fileID: 8434701791193156984} - component: {fileID: 8434701791193156984}
- component: {fileID: 9145795730378986889}
m_Layer: 5 m_Layer: 5
m_Name: Switch m_Name: SFX Switch
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -994,103 +895,6 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
handleImage: {fileID: 1822478720763898751} handleImage: {fileID: 1822478720763898751}
clickSound: {fileID: 8300000, guid: cff2e6cf7f46a074d86955b3b6fd499a, type: 3}
--- !u!82 &9145795730378986889
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5387157431517620447}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!1 &7654744771681034987 --- !u!1 &7654744771681034987
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -1347,7 +1347,19 @@ MonoBehaviour:
m_Calls: [] m_Calls: []
m_OnDeselect: m_OnDeselect:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls:
- m_Target: {fileID: 5818338764896528680}
m_TargetAssemblyTypeName: SignupPanelController, Assembly-CSharp
m_MethodName: OnChangeEndPassword
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_OnTextSelection: m_OnTextSelection:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
@ -2141,7 +2153,19 @@ MonoBehaviour:
m_Calls: [] m_Calls: []
m_OnValueChanged: m_OnValueChanged:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls:
- m_Target: {fileID: 5818338764896528680}
m_TargetAssemblyTypeName: SignupPanelController, Assembly-CSharp
m_MethodName: OnChangeNickname
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_OnTouchScreenKeyboardStatusChanged: m_OnTouchScreenKeyboardStatusChanged:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
@ -2791,10 +2815,34 @@ MonoBehaviour:
m_Calls: [] m_Calls: []
m_OnSelect: m_OnSelect:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls:
- m_Target: {fileID: 5818338764896528680}
m_TargetAssemblyTypeName: SignupPanelController, Assembly-CSharp
m_MethodName: OnSelectEmail
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_OnDeselect: m_OnDeselect:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls:
- m_Target: {fileID: 5818338764896528680}
m_TargetAssemblyTypeName: SignupPanelController, Assembly-CSharp
m_MethodName: OnChangeEndEmail
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_OnTextSelection: m_OnTextSelection:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9fc9c29bf8c5aa040aaeace773096d1b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 576c895328ccd5f4a91364f7fa42bea8
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 1613a4bf934e4d043b4e50b1b74c16b5
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,41 +1,71 @@
using UnityEngine; using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.Timeline;
public class AudioManager : Singleton<AudioManager> public class AudioManager : Singleton<AudioManager>
{ {
[Header("BGM")] private AudioClip mainBgm;
[SerializeField] private AudioClip mainBgm; private AudioClip gameBgm;
[SerializeField] private AudioClip gameBgm;
[Header("SFX")]
[SerializeField] private AudioClip clickSound;
[SerializeField] private AudioClip closeSound;
private AudioSource bgmAudioSource; // BGM을 위한 AudioSource [HideInInspector] public AudioSource bgmAudioSource; // BGM을 위한 AudioSource
private AudioSource sfxAudioSource; // SFX를 위한 AudioSource private AudioSource sfxAudioSource; // SFX를 위한 AudioSource
[HideInInspector] public float sfxVolume = 1.0f; // SFX 볼륨 (기본값 1) public float sfxVolume = 1.0f; // SFX 볼륨 (기본값 1)
private void Awake() [HideInInspector]public bool isPlayBGM;
[HideInInspector]public bool isPlaySFX;
private Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();
protected override void Awake()
{ {
base.Awake(); // 부모 클래스의 Awake 호출 base.Awake(); // 부모 클래스의 Awake 호출
// BGM과 SFX를 위한 별도의 AudioSource 생성 // BGM과 SFX를 위한 별도의 AudioSource 생성
bgmAudioSource = gameObject.AddComponent<AudioSource>(); bgmAudioSource = gameObject.AddComponent<AudioSource>();
sfxAudioSource = gameObject.AddComponent<AudioSource>(); sfxAudioSource = gameObject.AddComponent<AudioSource>();
//Sounds폴더 내의 모든 오디오클립 로드
AudioClip[] clips = Resources.LoadAll<AudioClip>("Sounds");
foreach (AudioClip clip in clips)
{
audioClips[clip.name] = clip;
}
Debug.Log($"총 {audioClips.Count}개의 오디오클립이 로드됨.");
}
public AudioClip GetAudioClip(string clipName)
{
if (audioClips.TryGetValue(clipName, out AudioClip clip))
{
return clip;
}
else
{
Debug.LogError($"패널 '{clipName}'을 찾을 수 없습니다.");
}
return null;
} }
// 시작 시 BGM을 자동으로 재생 // 시작 시 BGM을 자동으로 재생
private void Start() private void Start()
{ {
if (UserManager.IsPlayBGM) // UserManager의 BGM 설정값에 따라 BGM을 재생 isPlayBGM = UserManager.IsPlayBGM;
{ isPlaySFX = UserManager.IsPlaySFX;
PlayMainBGM(); // 기본 BGM을 재생
} PlayBGM();
} }
// 메인 BGM을 재생하는 함수 // 메인 BGM을 재생하는 함수
public void PlayMainBGM() public void PlayMainBGM()
{ {
mainBgm = GetAudioClip("main bgm");
if (bgmAudioSource != null && mainBgm != null && !bgmAudioSource.isPlaying) if (bgmAudioSource != null && mainBgm != null && !bgmAudioSource.isPlaying)
{ {
bgmAudioSource.clip = mainBgm; bgmAudioSource.clip = mainBgm;
@ -45,17 +75,10 @@ public class AudioManager : Singleton<AudioManager>
} }
} }
// BGM을 멈추는 함수
public void StopMainBGM()
{
if (bgmAudioSource != null && bgmAudioSource.isPlaying)
{
bgmAudioSource.Stop(); // BGM을 멈춤
}
}
public void PlayGameBGM() public void PlayGameBGM()
{ {
gameBgm = GetAudioClip("Game bgm2");
if (bgmAudioSource != null && gameBgm != null && !bgmAudioSource.isPlaying) if (bgmAudioSource != null && gameBgm != null && !bgmAudioSource.isPlaying)
{ {
bgmAudioSource.clip = gameBgm; bgmAudioSource.clip = gameBgm;
@ -65,7 +88,26 @@ public class AudioManager : Singleton<AudioManager>
} }
} }
public void StopGameBGM() public void PlayBGM()
{
if (isPlayBGM)
{
Scene currentScene = SceneManager.GetActiveScene();
if (currentScene.name == "Main")
{
StopBGM();
PlayMainBGM();
}
else if (currentScene.name == "Game")
{
StopBGM();
PlayGameBGM();
}
}
}
public void StopBGM()
{ {
if (bgmAudioSource != null && bgmAudioSource.isPlaying) if (bgmAudioSource != null && bgmAudioSource.isPlaying)
{ {
@ -73,44 +115,75 @@ public class AudioManager : Singleton<AudioManager>
} }
} }
// 씬이 로드될 때마다 호출되는 OnSceneLoaded 메서드
protected override void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
PlayBGM();
}
// 클릭 사운드(SFX) 재생 // 클릭 사운드(SFX) 재생
public void PlayClickSound() public void PlayClickSound()
{ {
if (sfxAudioSource != null) if (isPlaySFX && sfxAudioSource != null)
{ {
sfxAudioSource.PlayOneShot(clickSound, sfxVolume); sfxAudioSource.PlayOneShot(GetAudioClip("Click Sound"), sfxVolume);
} }
} }
// 닫기 사운드(SFX) 재생 // 닫기 사운드(SFX) 재생
public void PlayCloseSound() public void PlayCloseSound()
{ {
if (sfxAudioSource != null) if (isPlaySFX && sfxAudioSource != null)
{ {
sfxAudioSource.PlayOneShot(closeSound, sfxVolume); sfxAudioSource.PlayOneShot(GetAudioClip("Close Sound"), sfxVolume);
} }
} }
// 씬이 로드될 때마다 호출되는 OnSceneLoaded 메서드 public void PlayCoinsAddSound()
protected override void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{ {
if (scene.name == "Main") if (isPlaySFX && sfxAudioSource!=null)
{ {
StopGameBGM(); sfxAudioSource.PlayOneShot(GetAudioClip("Coins ADD Sound"), sfxVolume);
}
}
if (UserManager.IsPlayBGM) // BGM 설정값에 따라 메인 BGM을 재생 public void PlayCoinsEmptySound()
{ {
PlayMainBGM(); if (isPlaySFX && sfxAudioSource!=null)
{
sfxAudioSource.PlayOneShot(GetAudioClip("Coins Empty Sound"), sfxVolume);
} }
} }
else if (scene.name == "Game")
{
StopMainBGM();
if (UserManager.IsPlayBGM) // BGM 설정값에 따라 게임 BGM을 재생 public void PlayCoinsRemoveSound()
{ {
PlayGameBGM(); if (isPlaySFX && sfxAudioSource!=null)
} {
sfxAudioSource.PlayOneShot(GetAudioClip("Coins Remove Sound"), sfxVolume);
}
}
public void PlayLoseSound()
{
if (isPlaySFX && sfxAudioSource!=null)
{
sfxAudioSource.PlayOneShot(GetAudioClip("lose sound"), sfxVolume);
}
}
public void PlayWinSound()
{
if (isPlaySFX && sfxAudioSource!=null)
{
sfxAudioSource.PlayOneShot(GetAudioClip("win sound"), sfxVolume);
}
}
public void PlayStoneSound()
{
if (isPlaySFX && sfxAudioSource!=null)
{
sfxAudioSource.PlayOneShot(GetAudioClip("stone sound3"), sfxVolume);
} }
} }
} }

View File

@ -6,16 +6,11 @@ using UnityEngine.EventSystems;
using UnityEngine.Serialization; using UnityEngine.Serialization;
using UnityEngine.UI; using UnityEngine.UI;
[RequireComponent(typeof(AudioSource))]
public class CoinsPanelController : MonoBehaviour public class CoinsPanelController : MonoBehaviour
{ {
[SerializeField] private GameObject coinsRemoveImageObject; [SerializeField] private GameObject coinsRemoveImageObject;
[SerializeField] private TMP_Text coinsCountText; [SerializeField] private TMP_Text coinsCountText;
[SerializeField] private AudioClip coinsRemoveAudioClip;
[SerializeField] private AudioClip coinsAddAudioClip;
[SerializeField] private AudioClip coinsEmptyAudioClip;
private Color _coinsColor; private Color _coinsColor;
private AudioSource _audioSource; private AudioSource _audioSource;
private int _coinsCount; private int _coinsCount;
@ -58,7 +53,7 @@ public class CoinsPanelController : MonoBehaviour
_coinsRect.sizeDelta = new Vector2(100 + textLength * 30f, 100f); _coinsRect.sizeDelta = new Vector2(100 + textLength * 30f, 100f);
} }
private void ChangeTextAnimation(bool isAdd, Action action) private void ChangeTextAnimation(int coinAdd, bool isAdd, Action action)
{ {
float duration = 0.2f; float duration = 0.2f;
float yPos = 40f; float yPos = 40f;
@ -69,8 +64,8 @@ public class CoinsPanelController : MonoBehaviour
if (isAdd) if (isAdd)
{ {
var currentHeartCount = coinsCountText.text; var currentHeartCount = coinsCountText.text;
coinsCountText.text = (int.Parse(currentHeartCount) + 500).ToString(); coinsCountText.text = (int.Parse(currentHeartCount) + coinAdd).ToString();
// 코인 텍스트 100씩 증가 // 코인 텍스트 증가
} }
else else
{ {
@ -103,26 +98,21 @@ public class CoinsPanelController : MonoBehaviour
_canvasGroup.blocksRaycasts = false; //코인 중복 추가 방지 코드 _canvasGroup.blocksRaycasts = false; //코인 중복 추가 방지 코드
Sequence sequence = DOTween.Sequence(); Sequence sequence = DOTween.Sequence();
// i += a 반복 횟수 조절, 100개 단위로 상승 차감 시 100으로 설정
for (int i = 0; i < coinsCount; i+=500)
{
sequence.AppendCallback(() => sequence.AppendCallback(() =>
{ {
ChangeTextAnimation(true, ()=> ChangeTextAnimation(coinsCount,true, ()=>
{ {
// TODO : 코인 수량 업데이트 _coinsCount += coinsCount;
action?.Invoke(); action?.Invoke();
}); });
// 효과음 재생 // 효과음 재생
// TODO : if (UserInformation.IsPlaySFX) AudioManager.Instance.PlayCoinsAddSound();
_audioSource.PlayOneShot(coinsAddAudioClip);
}); });
sequence.AppendInterval(0.5f); sequence.AppendInterval(0.5f);
}
sequence.OnComplete(() => sequence.OnComplete(() =>
{ {
_coinsCount += coinsCount; //추가된 코인 적용
_canvasGroup.blocksRaycasts = true; //구매 후 클릭 활성화 _canvasGroup.blocksRaycasts = true; //구매 후 클릭 활성화
}); });
} }
@ -130,8 +120,7 @@ public class CoinsPanelController : MonoBehaviour
public void EmptyCoins() public void EmptyCoins()
{ {
// 효과음 재생 // 효과음 재생
// TODO: if (UserInformation.IsPlaySFX) AudioManager.Instance.PlayCoinsEmptySound();
_audioSource.PlayOneShot(coinsEmptyAudioClip);
GetComponent<RectTransform>().DOPunchPosition(new Vector3(20f, 0, 0), 1f, 7); GetComponent<RectTransform>().DOPunchPosition(new Vector3(20f, 0, 0), 1f, 7);
} }
@ -151,8 +140,7 @@ public class CoinsPanelController : MonoBehaviour
} }
// 효과음 재생 // 효과음 재생
// TODO: if (UserInformation.IsPlaySFX) AudioManager.Instance.PlayCoinsRemoveSound();
_audioSource.PlayOneShot(coinsRemoveAudioClip);
// 코인 사라지는 연출 // 코인 사라지는 연출
coinsRemoveImageObject.SetActive(true); coinsRemoveImageObject.SetActive(true);
@ -161,7 +149,7 @@ public class CoinsPanelController : MonoBehaviour
coinsRemoveImageObject.transform.DOScale(3f, 1f); coinsRemoveImageObject.transform.DOScale(3f, 1f);
coinsRemoveImageObject.GetComponent<Image>().DOFade(0f, 1f) coinsRemoveImageObject.GetComponent<Image>().DOFade(0f, 1f)
.OnComplete( ()=>ChangeTextAnimation(false, ()=> .OnComplete( ()=>ChangeTextAnimation(0,false, ()=>
{ {
//감소된 코인 적용 //감소된 코인 적용
_coinsCount -= 100; _coinsCount -= 100;

View File

@ -16,6 +16,9 @@
StartGame, // 생성한 방에 다른 유저가 참여해서 게임 시작 StartGame, // 생성한 방에 다른 유저가 참여해서 게임 시작
SwitchAI, // 15초 후 매칭 실패 시 AI 플레이로 전환 알림 SwitchAI, // 15초 후 매칭 실패 시 AI 플레이로 전환 알림
ExitRoom, // 자신이 방을 빠져 나왔을 때 ExitRoom, // 자신이 방을 빠져 나왔을 때
EndGame // 상대방이 접속을 끊거나 방을 나갔을 때 EndGame, // 상대방이 접속을 끊거나 방을 나갔을 때
DoSurrender, // 상대방이 항복했을 때
SurrenderConfirmed, // 항복 요청이 성공적으로 전송되었을 때
ReceiveTimeout // 상대방이 타임 아웃일 때
}; };
} }

View File

@ -13,16 +13,31 @@ public abstract class BasePlayerState
public abstract void HandleMove(GameLogic gameLogic, int row, int col); public abstract void HandleMove(GameLogic gameLogic, int row, int col);
public abstract void HandleNextTurn(GameLogic gameLogic); public abstract void HandleNextTurn(GameLogic gameLogic);
protected string _roomId;
protected bool _isMultiplay;
protected MultiplayManager _multiplayManager;
public void ProcessMove(GameLogic gameLogic, Enums.PlayerType playerType, int row, int col) public void ProcessMove(GameLogic gameLogic, Enums.PlayerType playerType, int row, int col)
{ {
gameLogic.fioTimer.PauseTimer(); gameLogic.fioTimer.PauseTimer();
gameLogic.SetNewBoardValue(playerType, row, col); gameLogic.SetNewBoardValue(playerType, row, col);
gameLogic.CountStoneCounter(); gameLogic.CountStoneCounter();
if (_isMultiplay)
{
_multiplayManager.SendPlayerMove(_roomId, new Vector2Int(row, col));
}
if (gameLogic.CheckGameWin(playerType, row, col)) if (gameLogic.CheckGameWin(playerType, row, col))
{ {
var gameResult = playerType == Enums.PlayerType.PlayerA? Enums.GameResult.Win:Enums.GameResult.Lose; var gameResult = playerType == Enums.PlayerType.PlayerA? Enums.GameResult.Win:Enums.GameResult.Lose;
if (gameLogic.gameType == Enums.GameType.MultiPlay)
{
if (gameLogic.firstPlayerState.GetType() != typeof(PlayerState))
{
gameResult = gameResult == Enums.GameResult.Win ? Enums.GameResult.Lose : Enums.GameResult.Win;
}
}
GameManager.Instance.panelManager.OpenEffectPanel(gameResult); GameManager.Instance.panelManager.OpenEffectPanel(gameResult);
gameLogic.EndGame(gameResult); gameLogic.EndGame(gameResult);
} }
@ -53,10 +68,6 @@ public class PlayerState : BasePlayerState
private Enums.PlayerType _playerType; private Enums.PlayerType _playerType;
private bool _isFirstPlayer; private bool _isFirstPlayer;
private MultiplayManager _multiplayManager;
private string _roomId;
private bool _isMultiplay;
public PlayerState(bool isFirstPlayer) public PlayerState(bool isFirstPlayer)
{ {
_isFirstPlayer = isFirstPlayer; _isFirstPlayer = isFirstPlayer;
@ -64,17 +75,10 @@ public class PlayerState : BasePlayerState
_isMultiplay = false; _isMultiplay = false;
} }
public PlayerState(bool isFirstPlayer, MultiplayManager multiplayManager, JoinRoomData data)
: this(isFirstPlayer)
{
_multiplayManager = multiplayManager;
_roomId = data.roomId;
_isMultiplay = true;
}
public PlayerState(bool isFirstPlayer, MultiplayManager multiplayManager, string roomId) public PlayerState(bool isFirstPlayer, MultiplayManager multiplayManager, string roomId)
: this(isFirstPlayer) : this(isFirstPlayer)
{ {
_isFirstPlayer = isFirstPlayer;
_multiplayManager = multiplayManager; _multiplayManager = multiplayManager;
_roomId = roomId; _roomId = roomId;
_isMultiplay = true; _isMultiplay = true;
@ -108,11 +112,6 @@ public class PlayerState : BasePlayerState
public override void HandleMove(GameLogic gameLogic, int row, int col) public override void HandleMove(GameLogic gameLogic, int row, int col)
{ {
gameLogic.SetStoneSelectedState(row, col); gameLogic.SetStoneSelectedState(row, col);
if (_isMultiplay)
{
Debug.Log("row: " + row + "col: " + col);
_multiplayManager.SendPlayerMove(_roomId, new Vector2Int(row, col));
}
} }
public override void HandleNextTurn(GameLogic gameLogic) public override void HandleNextTurn(GameLogic gameLogic)
@ -178,7 +177,7 @@ public class MultiPlayerState: BasePlayerState
gameLogic.UpdateForbiddenMoves(); gameLogic.UpdateForbiddenMoves();
#endregion #endregion
// gameLogic.currentTurn = _playerType; gameLogic.currentTurn = _playerType;
// gameLogic.stoneController.OnStoneClickedDelegate = (row, col) => // gameLogic.stoneController.OnStoneClickedDelegate = (row, col) =>
// { // {
// HandleMove(gameLogic, row, col); // HandleMove(gameLogic, row, col);
@ -242,7 +241,7 @@ public class GameLogic : MonoBehaviour
private int _lastRow; private int _lastRow;
private int _lastCol; private int _lastCol;
private MultiplayManager _multiplayManager; public MultiplayManager _multiplayManager;
private string _roomId; private string _roomId;
#region Renju Members #region Renju Members
@ -279,17 +278,24 @@ public class GameLogic : MonoBehaviour
//timer 시간초과시 진행 함수 //timer 시간초과시 진행 함수
this.fioTimer.OnTimeout = () => this.fioTimer.OnTimeout = () =>
{ {
if (currentTurn == Enums.PlayerType.PlayerA) // 현재 턴의 플레이어가 로컬(유저)인지 확인
bool isCurrentPlayerLocal = (currentTurn == Enums.PlayerType.PlayerA && firstPlayerState is PlayerState) ||
(currentTurn == Enums.PlayerType.PlayerB && secondPlayerState is PlayerState);
if (isCurrentPlayerLocal) // 내가 타임 오버일 때
{ {
GameManager.Instance.panelManager.OpenConfirmPanel($"Game Over: {Enums.PlayerType.PlayerB} Win", if (this.gameType == Enums.GameType.MultiPlay) // 멀티플레이인 경우
() =>{}); {
_multiplayManager?.SendTimeout();
}
GameManager.Instance.panelManager.OpenEffectPanel(Enums.GameResult.Lose);
EndGame(Enums.GameResult.Lose); EndGame(Enums.GameResult.Lose);
} }
else if (currentTurn == Enums.PlayerType.PlayerB) else // 로컬에서 자신의 타이머 기준으로 상대방이 타임 오버일 때
{ {
GameManager.Instance.panelManager.OpenConfirmPanel($"Game Over: {Enums.PlayerType.PlayerA} Win", // TODO: 컨펌 패널 OK 버튼 삭제?
GameManager.Instance.panelManager.OpenConfirmPanel("상대방의 응답을 기다리는 중입니다",
() => { } ); () => { } );
EndGame(Enums.GameResult.Win);
} }
}; };
} }
@ -340,15 +346,14 @@ public class GameLogic : MonoBehaviour
return; return;
} }
// TODO: 선공, 후공 처리 // 선공, 후공 처리
if (joinRoomData.isBlack) bool isFirstPlayer = joinRoomData.isBlack;
if (isFirstPlayer)
{ {
} Debug.Log("해당 플레이어가 선공 입니다");
firstPlayerState = new PlayerState(true, _multiplayManager, joinRoomData.roomId);
firstPlayerState = new MultiPlayerState(true, _multiplayManager); secondPlayerState = new MultiPlayerState(false, _multiplayManager);
secondPlayerState = new PlayerState(false, _multiplayManager, joinRoomData);
// 메인 스레드에서 실행 - UI 업데이트는 메인 스레드에서 실행 필요
UnityMainThreadDispatcher.Instance().Enqueue(() => UnityMainThreadDispatcher.Instance().Enqueue(() =>
{ {
GameManager.Instance.InitPlayersName(UserManager.Instance.Nickname, joinRoomData.opponentNickname); GameManager.Instance.InitPlayersName(UserManager.Instance.Nickname, joinRoomData.opponentNickname);
@ -356,7 +361,27 @@ public class GameLogic : MonoBehaviour
// 리플레이 데이터 업데이트 // 리플레이 데이터 업데이트
ReplayManager.Instance.InitReplayData(UserManager.Instance.Nickname, joinRoomData.opponentNickname, UserManager.Instance.imageIndex, joinRoomData.opponentImageIndex); ReplayManager.Instance.InitReplayData(UserManager.Instance.Nickname, joinRoomData.opponentNickname, UserManager.Instance.imageIndex, joinRoomData.opponentImageIndex);
});
}
else
{
Debug.Log("해당 플레이어가 후공 입니다");
firstPlayerState = new MultiPlayerState(true, _multiplayManager);
secondPlayerState = new PlayerState(false, _multiplayManager, joinRoomData.roomId);
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
GameManager.Instance.InitPlayersName(joinRoomData.opponentNickname, UserManager.Instance.Nickname);
GameManager.Instance.InitProfileImages(joinRoomData.opponentImageIndex, UserManager.Instance.imageIndex);
// 리플레이 데이터 업데이트
ReplayManager.Instance.InitReplayData(joinRoomData.opponentNickname, UserManager.Instance.Nickname, joinRoomData.opponentImageIndex, UserManager.Instance.imageIndex);
});
}
// 메인 스레드에서 실행 - UI 업데이트는 메인 스레드에서 실행 필요
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
// 로딩 패널 열려있으면 닫기 // 로딩 패널 열려있으면 닫기
GameManager.Instance.panelManager.CloseLoadingPanel(); GameManager.Instance.panelManager.CloseLoadingPanel();
@ -378,15 +403,14 @@ public class GameLogic : MonoBehaviour
Debug.Log("Start Game 응답값이 null 입니다"); Debug.Log("Start Game 응답값이 null 입니다");
return; return;
} }
// 선공, 후공 처리
isFirstPlayer = startGameData.isBlack;
// TODO: 선공, 후공 처리 if (isFirstPlayer)
if (startGameData.isBlack)
{ {
} Debug.Log("해당 플레이어가 선공 입니다");
firstPlayerState = new PlayerState(true, _multiplayManager, _roomId); firstPlayerState = new PlayerState(true, _multiplayManager, _roomId);
secondPlayerState = new MultiPlayerState(false, _multiplayManager); secondPlayerState = new MultiPlayerState(false, _multiplayManager);
// 메인 스레드에서 실행 - UI 업데이트는 메인 스레드에서 실행 필요
UnityMainThreadDispatcher.Instance().Enqueue(() => UnityMainThreadDispatcher.Instance().Enqueue(() =>
{ {
GameManager.Instance.InitPlayersName(UserManager.Instance.Nickname, startGameData.opponentNickname); GameManager.Instance.InitPlayersName(UserManager.Instance.Nickname, startGameData.opponentNickname);
@ -394,7 +418,26 @@ public class GameLogic : MonoBehaviour
// 리플레이 데이터 업데이트 // 리플레이 데이터 업데이트
ReplayManager.Instance.InitReplayData(UserManager.Instance.Nickname, startGameData.opponentNickname, UserManager.Instance.imageIndex, startGameData.opponentImageIndex); ReplayManager.Instance.InitReplayData(UserManager.Instance.Nickname, startGameData.opponentNickname, UserManager.Instance.imageIndex, startGameData.opponentImageIndex);
});
}
else
{
Debug.Log("해당 플레이어가 후공 입니다");
firstPlayerState = new MultiPlayerState(true, _multiplayManager);
secondPlayerState = new PlayerState(false, _multiplayManager, _roomId);
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
GameManager.Instance.InitPlayersName(startGameData.opponentNickname, UserManager.Instance.Nickname);
GameManager.Instance.InitProfileImages(startGameData.opponentImageIndex, UserManager.Instance.imageIndex);
// 리플레이 데이터 업데이트
ReplayManager.Instance.InitReplayData(startGameData.opponentNickname, UserManager.Instance.Nickname, startGameData.opponentImageIndex, UserManager.Instance.imageIndex);
});
}
// 메인 스레드에서 실행 - UI 업데이트는 메인 스레드에서 실행 필요
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
// 로딩 패널 열려있으면 닫기 // 로딩 패널 열려있으면 닫기
GameManager.Instance.panelManager.CloseLoadingPanel(); GameManager.Instance.panelManager.CloseLoadingPanel();
@ -410,6 +453,30 @@ public class GameLogic : MonoBehaviour
Debug.Log("## End Game"); Debug.Log("## End Game");
// TODO: End Room 처리 // TODO: End Room 처리
break; break;
case Constants.MultiplayManagerState.DoSurrender:
Debug.Log("상대방의 항복 요청 들어옴");
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
GameManager.Instance.panelManager.OpenEffectPanel(Enums.GameResult.Win);
EndGame(Enums.GameResult.Win);
});
break;
case Constants.MultiplayManagerState.SurrenderConfirmed:
Debug.Log("항복 요청 전송 완료");
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
GameManager.Instance.panelManager.OpenEffectPanel(Enums.GameResult.Lose);
EndGame(Enums.GameResult.Lose);
});
break;
case Constants.MultiplayManagerState.ReceiveTimeout:
Debug.Log("상대방이 타임 아웃 됨");
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
GameManager.Instance.panelManager.OpenEffectPanel(Enums.GameResult.Win);
EndGame(Enums.GameResult.Win);
});
break;
} }
ReplayManager.Instance.InitReplayData(UserManager.Instance.Nickname,"nicknameB"); ReplayManager.Instance.InitReplayData(UserManager.Instance.Nickname,"nicknameB");
@ -440,6 +507,7 @@ public class GameLogic : MonoBehaviour
// 기존 멀티플레이 상태 초기화 // 기존 멀티플레이 상태 초기화
_multiplayManager = null; _multiplayManager = null;
_roomId = null; _roomId = null;
this.gameType = Enums.GameType.SinglePlay;
// 싱글 플레이 상태로 변경 // 싱글 플레이 상태로 변경
firstPlayerState = new PlayerState(true); firstPlayerState = new PlayerState(true);

View File

@ -20,12 +20,21 @@ public class GameManager : Singleton<GameManager>
[NonSerialized] public PanelManager panelManager; [NonSerialized] public PanelManager panelManager;
[NonSerialized] public AudioManager audioManager; [NonSerialized] public AudioManager audioManager;
private MultiplayManager _multiplayManager;
protected override void Awake() protected override void Awake()
{ {
base.Awake(); base.Awake();
InitPanels(); InitPanels();
} }
public MultiplayManager GetMultiplayManager()
{
_multiplayManager = _gameLogic._multiplayManager;
if (_multiplayManager == null) Debug.Log("MultiplayManager가 null입니다");
return _multiplayManager;
}
private void InitPanels() private void InitPanels()
{ {
if (panelManager == null) if (panelManager == null)

View File

@ -67,6 +67,8 @@ public class MultiplayManager : IDisposable
private event Action<Constants.MultiplayManagerState, object> _onMultiplayStateChanged; private event Action<Constants.MultiplayManagerState, object> _onMultiplayStateChanged;
public Action<MoveData> OnOpponentMove; public Action<MoveData> OnOpponentMove;
private string _roomId;
public MultiplayManager(Action<Constants.MultiplayManagerState, object> onMultiplayStateChanged) public MultiplayManager(Action<Constants.MultiplayManagerState, object> onMultiplayStateChanged)
{ {
_onMultiplayStateChanged = onMultiplayStateChanged; _onMultiplayStateChanged = onMultiplayStateChanged;
@ -86,6 +88,9 @@ public class MultiplayManager : IDisposable
_socket.On("exitRoom", ExitRoom); _socket.On("exitRoom", ExitRoom);
_socket.On("endGame", EndGame); _socket.On("endGame", EndGame);
_socket.On("doOpponent", DoOpponent); _socket.On("doOpponent", DoOpponent);
_socket.On("doSurrender", DoSurrender);
_socket.On("surrenderConfirmed", SurrenderConfirmed);
_socket.On("receiveTimeout", ReceiveTimeout);
_socket.Connect(); _socket.Connect();
} }
@ -109,6 +114,7 @@ public class MultiplayManager : IDisposable
private void CreateRoom(SocketIOResponse response) private void CreateRoom(SocketIOResponse response)
{ {
var data = response.GetValue<CreateRoomData>(); var data = response.GetValue<CreateRoomData>();
_roomId = data.roomId;
_onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.CreateRoom, data.roomId); _onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.CreateRoom, data.roomId);
} }
@ -116,8 +122,7 @@ public class MultiplayManager : IDisposable
{ {
var data = response.GetValue<JoinRoomData>(); var data = response.GetValue<JoinRoomData>();
Debug.Log($"룸에 참여: 룸 ID - {data.roomId}, 상대방 등급 - {data.opponentRating}, 상대방 이름 - {data.opponentNickname}, 흑/백 여부 - {data.isBlack}, 상대방 이미지 인덱스 - {data.opponentImageIndex}"); Debug.Log($"룸에 참여: 룸 ID - {data.roomId}, 상대방 등급 - {data.opponentRating}, 상대방 이름 - {data.opponentNickname}, 흑/백 여부 - {data.isBlack}, 상대방 이미지 인덱스 - {data.opponentImageIndex}");
_roomId = data.roomId;
// 필요한 데이터 사용
_onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.JoinRoom, data); _onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.JoinRoom, data);
} }
@ -180,7 +185,62 @@ public class MultiplayManager : IDisposable
public void LeaveRoom(string roomId) public void LeaveRoom(string roomId)
{ {
_socket.Emit("leaveRoom", new { roomId }); if (string.IsNullOrEmpty(_roomId))
{
Debug.LogError("LeaveRoom 호출 실패: _roomId가 설정되지 않음");
return;
}
_socket.Emit("leaveRoom", new { roomId = _roomId });
_roomId = null; // 방 나가면 roomId 초기화
}
public void RequestSurrender()
{
if (string.IsNullOrEmpty(_roomId))
{
Debug.LogError("LeaveRoom 호출 실패: _roomId가 설정되지 않음");
return;
}
_socket.Emit("requestSurrender",new { roomId = _roomId });
}
private void DoSurrender(SocketIOResponse response)
{
var data = response.GetValue<MessageData>();
_onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.DoSurrender, data.message);
}
private void SurrenderConfirmed(SocketIOResponse response)
{
var data = response.GetValue<MessageData>();
_onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.SurrenderConfirmed, data.message);
}
/// <summary>
/// 타임 아웃 요청
/// </summary>
public void SendTimeout()
{
if (string.IsNullOrEmpty(_roomId))
{
Debug.LogError("LeaveRoom 호출 실패: _roomId가 설정되지 않음");
return;
}
_socket.Emit("sendTimeout",new { roomId = _roomId });
}
/// <summary>
/// 타임 아웃 수신
/// </summary>
/// <param name="response"></param>
private void ReceiveTimeout(SocketIOResponse response)
{
var data = response.GetValue<MessageData>();
_onMultiplayStateChanged?.Invoke(Constants.MultiplayManagerState.ReceiveTimeout, data.message);
} }
public void Dispose() public void Dispose()

View File

@ -228,56 +228,13 @@ public class NetworkManager : Singleton<NetworkManager>
} }
} }
public void UpdateScore(int isWin, Action<ScoreInfoResult> success, Action failure)
{
StartCoroutine(UpdateScoreCoroutine(isWin, success, failure));
}
public IEnumerator UpdateScoreCoroutine(int isWin, Action<ScoreInfoResult> success, Action failure)
{
string jsonString = "{\"isWin\": "+isWin.ToString() + "}";
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonString);
using (UnityWebRequest www = public void GetLeaderboard(Action<List<ScoreInfo>> success, Action failure)
new UnityWebRequest(Constants.ServerURL + "/users/score-update", UnityWebRequest.kHttpVerbPOST))
{ {
www.uploadHandler = new UploadHandlerRaw(bodyRaw); StartCoroutine(GetLeaderboardCoroutine(success, failure));
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
string sid = PlayerPrefs.GetString("sid", "");
if (!string.IsNullOrEmpty(sid))
{
www.SetRequestHeader("Cookie", sid);
}
else
{
Debug.LogError("SID 값이 없습니다. 로그인 정보가 없습니다.");
GameManager.Instance.panelManager.OpenConfirmPanel("SID 값이 없습니다. 로그인 정보가 없습니다.", () =>
{
failure?.Invoke();
});
yield break; // 더 이상 진행하지 않고 종료
} }
yield return www.SendWebRequest(); public IEnumerator GetLeaderboardCoroutine(Action<List<ScoreInfo>> success, Action failure)
if (www.result == UnityWebRequest.Result.ConnectionError ||
www.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError("Error: " + www.error);
failure?.Invoke();
}
else
{
var result = www.downloadHandler.text;
var scoreResultInfo = JsonUtility.FromJson<ScoreInfoResult>(result);
success?.Invoke(scoreResultInfo);
}
}
}
public IEnumerator GetLeaderboard(Action<Scores> success, Action failure)
{ {
using (UnityWebRequest www = using (UnityWebRequest www =
new UnityWebRequest(Constants.ServerURL + "/leaderboard", UnityWebRequest.kHttpVerbGET)) new UnityWebRequest(Constants.ServerURL + "/leaderboard", UnityWebRequest.kHttpVerbGET))
@ -305,10 +262,15 @@ public class NetworkManager : Singleton<NetworkManager>
} }
else else
{ {
var result = www.downloadHandler.text; // 성공적으로 데이터를 받아온 경우
var scores = JsonUtility.FromJson<Scores>(result); string jsonResponse = www.downloadHandler.text; // 응답으로 받은 JSON 데이터
success?.Invoke(scores); // JSON을 ScoreInfo 리스트로 파싱
ScoreListWrapper wrapper = JsonUtility.FromJson<ScoreListWrapper>(jsonResponse);
List<ScoreInfo> leaderboardItems = wrapper.leaderboardDatas;
// Show 메서드를 통해 데이터를 표시
success?.Invoke(leaderboardItems);
} }
} }
} }
@ -561,35 +523,53 @@ public class NetworkManager : Singleton<NetworkManager>
} }
} }
public void GetLeaderboardData(Action<List<ScoreInfo>> success, Action failure) public void UpdateScore(int isWin, Action<ScoreInfoResult> success, Action failure)
{ {
StartCoroutine(GetLeaderboardDataCoroutine(success, failure)); StartCoroutine(UpdateScoreCoroutine(isWin, success, failure));
}
public IEnumerator UpdateScoreCoroutine(int isWin, Action<ScoreInfoResult> success, Action failure)
{
string jsonString = "{\"isWin\": "+isWin.ToString() + "}";
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonString);
using (UnityWebRequest www =
new UnityWebRequest(Constants.ServerURL + "/users/score-update", UnityWebRequest.kHttpVerbPOST))
{
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
string sid = PlayerPrefs.GetString("sid", "");
if (!string.IsNullOrEmpty(sid))
{
www.SetRequestHeader("Cookie", sid);
}
else
{
Debug.LogError("SID 값이 없습니다. 로그인 정보가 없습니다.");
GameManager.Instance.panelManager.OpenConfirmPanel("SID 값이 없습니다. 로그인 정보가 없습니다.", () =>
{
failure?.Invoke();
});
yield break; // 더 이상 진행하지 않고 종료
} }
private IEnumerator GetLeaderboardDataCoroutine(Action<List<ScoreInfo>> success, Action failure) yield return www.SendWebRequest();
{
string url = Constants.ServerURL + "/leaderboard/"; // 서버의 리더보드 데이터 URL
UnityWebRequest www = UnityWebRequest.Get(url); // GET 요청으로 데이터 받기 if (www.result == UnityWebRequest.Result.ConnectionError ||
yield return www.SendWebRequest(); // 요청 전송 대기 www.result == UnityWebRequest.Result.ProtocolError)
// 요청이 실패했을 때
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
{ {
Debug.LogError("Error: " + www.error); Debug.LogError("Error: " + www.error);
failure?.Invoke(); failure?.Invoke();
} }
else else
{ {
// 성공적으로 데이터를 받아온 경우 var result = www.downloadHandler.text;
string jsonResponse = www.downloadHandler.text; // 응답으로 받은 JSON 데이터 var scoreResultInfo = JsonUtility.FromJson<ScoreInfoResult>(result);
// JSON을 ScoreInfo 리스트로 파싱 success?.Invoke(scoreResultInfo);
ScoreListWrapper wrapper = JsonUtility.FromJson<ScoreListWrapper>(jsonResponse); }
List<ScoreInfo> leaderboardItems = wrapper.leaderboardDatas; }
}
// Show 메서드를 통해 데이터를 표시
success?.Invoke(leaderboardItems);
}
}
} }

View File

@ -1,5 +1,7 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
@ -23,6 +25,8 @@ public class SignupPanelController : MonoBehaviour
[SerializeField] private Toggle[] imageSelectToggles; [SerializeField] private Toggle[] imageSelectToggles;
private int _selectedImageIndex = 0; private int _selectedImageIndex = 0;
private bool _emailValid = false;
private void Start() private void Start()
{ {
SetToggleInit(); SetToggleInit();
@ -43,14 +47,36 @@ public class SignupPanelController : MonoBehaviour
public void OnValueChanged(bool value, int index) public void OnValueChanged(bool value, int index)
{ {
// 현재 토글을 끄려고 할 때 (value가 false)
if (!value && index == _selectedImageIndex)
{
// 현재 켜져 있는 토글을 다시 켜지 않게 하고
imageSelectToggles[index].onValueChanged.RemoveAllListeners();
// 다른 토글을 켬 (현재 선택된 인덱스가 아닌 다음 토글을 켬)
int nextIndex = (index + 1) % imageSelectToggles.Length;
_selectedImageIndex = nextIndex;
imageSelectToggles[nextIndex].isOn = true;
// 이벤트 리스너 다시 추가
int capturedIndex = index;
imageSelectToggles[index].onValueChanged.AddListener((bool val) => OnValueChanged(val, capturedIndex));
return;
}
// 새로운 토글을 선택했을 때
if (value) if (value)
{ {
int previousIndex = _selectedImageIndex;
_selectedImageIndex = index; _selectedImageIndex = index;
int previousIndex = (_selectedImageIndex == 0) ? 1 : 0;
// 선택된 토글이 변경되었을 때만 이전 토글을 끔
if (previousIndex != index)
{
imageSelectToggles[previousIndex].isOn = false; imageSelectToggles[previousIndex].isOn = false;
} }
} }
}
public void OnClickConfirmButton() public void OnClickConfirmButton()
{ {
@ -59,7 +85,7 @@ public class SignupPanelController : MonoBehaviour
var password = passwordInputField.text; var password = passwordInputField.text;
var confirmPassword = confirmPasswordInputField.text; var confirmPassword = confirmPasswordInputField.text;
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(nickname) || if (string.IsNullOrEmpty(email) || !_emailValid || string.IsNullOrEmpty(nickname) ||
string.IsNullOrEmpty(password) || string.IsNullOrEmpty(confirmPassword)) string.IsNullOrEmpty(password) || string.IsNullOrEmpty(confirmPassword))
{ {
// 입력 내용 누락 팝업 표시 // 입력 내용 누락 팝업 표시
@ -104,4 +130,63 @@ public class SignupPanelController : MonoBehaviour
{ {
Destroy(gameObject); Destroy(gameObject);
} }
// 이메일 입력을 완료하면 유효성 검사를 진행함
public void OnChangeEndEmail(string emailText)
{
const string emailPattern = @"^[^\s@]+@[^\s@]+\.[^\s@]+$";
// 입력이 끝났을 때 이메일 형식 검사
_emailValid = Regex.IsMatch(emailText, emailPattern);
// 이메일이 비어있지 않은 경우에만 색상 변경
if (!string.IsNullOrEmpty(emailText))
{
if (_emailValid) return;
emailInputField.textComponent.color = Color.red;
// 이메일 유효하지 않음
GameManager.Instance.panelManager.OpenConfirmPanel("올바른 이메일 주소를 입력하세요.", () => {});
Debug.Log("이메일 유효성 X");
}
}
// 이메일 인풋을 선택했을 때 이메일이 유효하지 않았으면 텍스트를 초기화함
public void OnSelectEmail()
{
if (!_emailValid)
{
emailInputField.textComponent.color = Color.black;
emailInputField.text = String.Empty;
}
}
// 닉네임 글자 6자 초과하면 마지막 글자를 잘라서 6자로 만듬
public void OnChangeNickname(string nicknameText)
{
const int maxNicknameLength = 6;
if (nicknameText.Length > maxNicknameLength)
{
// 글자수가 제한을 초과하면 처음 6글자만 남김
string limitedText = nicknameText.Substring(0, maxNicknameLength);
nicknameInputField.text = limitedText;
}
}
// 비밀번호 유효성 검사
public void OnChangeEndPassword(string passwordText)
{
// 비밀번호가 비어 있으면 검사하지 않음
if (string.IsNullOrEmpty(passwordText)) return;
// 비밀번호 글자수 제한 확인
if (passwordText.Length < 6 || passwordText.Length > 18)
{
// 비밀번호 글자 수 제한
GameManager.Instance.panelManager.OpenConfirmPanel("비밀번호는 6자 이상 18자 이하로 입력해주세요.", () => {});
Debug.Log("비밀번호 글자 수 제한");
}
}
} }

View File

@ -100,14 +100,22 @@ public class UserManager : Singleton<UserManager>
public static bool IsPlaySFX public static bool IsPlaySFX
{ {
get { return PlayerPrefs.GetInt("IsPlaySFX", 1) == 1; } get { return PlayerPrefs.GetInt("IsPlaySFX", 1) == 1; }
set { PlayerPrefs.SetInt("IsPlaySFX", value ? 1 : 0); } set
{
PlayerPrefs.SetInt("IsPlaySFX", value ? 1 : 0);
AudioManager.Instance.isPlaySFX = value;
}
} }
// 배경음악 재생 여부 // 배경음악 재생 여부
public static bool IsPlayBGM public static bool IsPlayBGM
{ {
get { return PlayerPrefs.GetInt("IsPlayBGM", 1) == 1; } get { return PlayerPrefs.GetInt("IsPlayBGM", 1) == 1; }
set { PlayerPrefs.SetInt("IsPlayBGM", value ? 1 : 0); } set
{
PlayerPrefs.SetInt("IsPlayBGM", value ? 1 : 0);
AudioManager.Instance.isPlayBGM = value;
}
} }
protected override void OnSceneLoaded(Scene scene, LoadSceneMode mode) protected override void OnSceneLoaded(Scene scene, LoadSceneMode mode)

View File

@ -12,10 +12,11 @@ public class DrawEffectController : EffectController
[SerializeField] private float flipDuration = 0.3f; [SerializeField] private float flipDuration = 0.3f;
protected override string fullText => "무승부 입니다"; protected override string fullText => "무승부 입니다";
protected override void ShowEffect() public override void ShowEffect(OnEffectPanelEnded onEffectPanelEnd)
{ {
gameObject.SetActive(true); gameObject.SetActive(true);
cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource = new CancellationTokenSource();
onEffectPanelEnded = onEffectPanelEnd;
ShowPanel(); ShowPanel();
StartCoroutine(AnimateLoadingText()); StartCoroutine(AnimateLoadingText());

View File

@ -3,9 +3,11 @@ using System.Threading;
using DG.Tweening; using DG.Tweening;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UIElements;
[RequireComponent(typeof(CanvasGroup))] [RequireComponent(typeof(CanvasGroup))]
public abstract class EffectController : MonoBehaviour public abstract class EffectController : MonoBehaviour, IPointerClickHandler
{ {
[SerializeField] protected GameObject bannerObj; [SerializeField] protected GameObject bannerObj;
[SerializeField] protected TextMeshProUGUI bannerText; [SerializeField] protected TextMeshProUGUI bannerText;
@ -15,13 +17,16 @@ public abstract class EffectController : MonoBehaviour
protected CancellationTokenSource cancellationTokenSource; protected CancellationTokenSource cancellationTokenSource;
protected int currentLength = 0; protected int currentLength = 0;
protected virtual void Start() public delegate void OnEffectPanelEnded();
{ protected OnEffectPanelEnded onEffectPanelEnded;
ShowEffect();
} // protected virtual void Start()
// {
// ShowEffect();
// }
// 효과를 실행하는 메서드 (자식이 구현해야 함) // 효과를 실행하는 메서드 (자식이 구현해야 함)
protected abstract void ShowEffect(); public abstract void ShowEffect(OnEffectPanelEnded onEffectPanelEnded);
// 공통 UI 애니메이션 (패널 표시) // 공통 UI 애니메이션 (패널 표시)
protected virtual void ShowPanel() protected virtual void ShowPanel()
@ -60,6 +65,12 @@ public abstract class EffectController : MonoBehaviour
cancellationTokenSource = null; cancellationTokenSource = null;
} }
onEffectPanelEnded?.Invoke();
gameObject.SetActive(false); gameObject.SetActive(false);
} }
public void OnPointerClick(PointerEventData eventData)
{
HideEffect();
}
} }

View File

@ -12,10 +12,11 @@ public class LoseEffectController : EffectController
protected override string fullText => "패배했습니다"; protected override string fullText => "패배했습니다";
protected override void ShowEffect() public override void ShowEffect(OnEffectPanelEnded onEffectPanelEnd)
{ {
gameObject.SetActive(true); gameObject.SetActive(true);
cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource = new CancellationTokenSource();
onEffectPanelEnded = onEffectPanelEnd;
ShowPanel(); ShowPanel();
StartCoroutine(AnimateLoadingText()); StartCoroutine(AnimateLoadingText());

View File

@ -14,10 +14,11 @@ public class WinEffectController : EffectController
protected override string fullText => "승리했습니다!"; protected override string fullText => "승리했습니다!";
protected override void ShowEffect() public override void ShowEffect(OnEffectPanelEnded onEffectPanelEnd)
{ {
gameObject.SetActive(true); gameObject.SetActive(true);
cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource = new CancellationTokenSource();
onEffectPanelEnded = onEffectPanelEnd;
ShowPanel(); ShowPanel();
StartCoroutine(AnimateLoadingText()); StartCoroutine(AnimateLoadingText());
@ -26,6 +27,16 @@ public class WinEffectController : EffectController
Invoke(nameof(PopupObject), 0.3f); Invoke(nameof(PopupObject), 0.3f);
} }
protected override void ShowPanel()
{
CanvasGroup canvasGroup = gameObject.GetComponent<CanvasGroup>() ?? gameObject.AddComponent<CanvasGroup>();
canvasGroup.alpha = 0f;
canvasGroup.DOFade(1f, 1f);
bannerObj.transform.DOScale(Vector3.zero, 0f);
bannerObj.transform.DOScale(Vector3.one, 1f);
}
private void RotateHaloObject() private void RotateHaloObject()
{ {
// 무한 회전 효과 // 무한 회전 효과

View File

@ -6,11 +6,9 @@ using UnityEngine.UI;
using DG.Tweening; using DG.Tweening;
[RequireComponent(typeof(Image))] [RequireComponent(typeof(Image))]
[RequireComponent(typeof(AudioSource))]
public class SwitchController : MonoBehaviour public class SwitchController : MonoBehaviour
{ {
[SerializeField] private Image handleImage; [SerializeField] private Image handleImage;
[SerializeField] private AudioClip clickSound;
//스위치에 상태 변경 시 호출할 콜백 함수 //스위치에 상태 변경 시 호출할 콜백 함수
public delegate void OnSwitchChangedDelegate(bool isOn); public delegate void OnSwitchChangedDelegate(bool isOn);
@ -21,7 +19,6 @@ public class SwitchController : MonoBehaviour
private RectTransform _handleRectTransform; private RectTransform _handleRectTransform;
private Image _backgroundImage; private Image _backgroundImage;
private AudioSource _audioSource;
private bool _isOn; private bool _isOn;
@ -29,7 +26,6 @@ public class SwitchController : MonoBehaviour
{ {
_handleRectTransform = handleImage.GetComponent<RectTransform>(); _handleRectTransform = handleImage.GetComponent<RectTransform>();
_backgroundImage = GetComponent<Image>(); _backgroundImage = GetComponent<Image>();
_audioSource = GetComponent<AudioSource>();
} }
private void Start() private void Start()
@ -37,7 +33,15 @@ public class SwitchController : MonoBehaviour
//초기 상태는 false //초기 상태는 false
_handleRectTransform.anchoredPosition = new Vector2(-14, 0); _handleRectTransform.anchoredPosition = new Vector2(-14, 0);
_backgroundImage.color = OffColor; _backgroundImage.color = OffColor;
_isOn = false;
if (gameObject.name == "SFX Switch")
{
_isOn = UserManager.IsPlaySFX;
}
else if (gameObject.name == "BGM Switch")
{
_isOn = UserManager.IsPlayBGM;
}
} }
//스위치 상태 변경 함수 //스위치 상태 변경 함수
@ -56,8 +60,7 @@ public class SwitchController : MonoBehaviour
} }
// 효과음 재생 // 효과음 재생
if (clickSound != null) AudioManager.Instance.PlayClickSound();
_audioSource.PlayOneShot(clickSound);
//이벤트 호출 //이벤트 호출
OnSwitchChanged?.Invoke(isOn); OnSwitchChanged?.Invoke(isOn);

View File

@ -27,7 +27,7 @@ public class LeaderBoardController : MonoBehaviour
if (isLeaderboardLoaded) return; // 이미 리더보드가 로드되었으면 중복 호출 방지 if (isLeaderboardLoaded) return; // 이미 리더보드가 로드되었으면 중복 호출 방지
leaderboardPanel.SetActive(true); leaderboardPanel.SetActive(true);
NetworkManager.Instance.GetLeaderboardData((leaderboardItems) => NetworkManager.Instance.GetLeaderboard((leaderboardItems) =>
{ {
Show(leaderboardItems); Show(leaderboardItems);
}, () => { }); }, () => { });

View File

@ -86,22 +86,30 @@ public class PanelManager : MonoBehaviour
if (_canvas != null) if (_canvas != null)
{ {
var winEffectPanelObject = GetEffectPanel("Win Effect Panel"); var winEffectPanelObject = GetEffectPanel("Win Effect Panel");
winEffectPanelObject.GetComponent<WinEffectController>().ShowEffect(OnEffectPanelEnded);
} }
break; break;
case Enums.GameResult.Lose: case Enums.GameResult.Lose:
if (_canvas != null) if (_canvas != null)
{ {
var winEffectPanelObject = GetEffectPanel("Lose Effect Panel"); var loseEffectPanelObject = GetEffectPanel("Lose Effect Panel");
loseEffectPanelObject.GetComponent<LoseEffectController>().ShowEffect(OnEffectPanelEnded);
} }
break; break;
case Enums.GameResult.Draw: case Enums.GameResult.Draw:
if (_canvas != null) if (_canvas != null)
{ {
var winEffectPanelObject = GetEffectPanel("Draw Effect Panel"); var drawEffectPanelObject = GetEffectPanel("Draw Effect Panel");
drawEffectPanelObject.GetComponent<DrawEffectController>().ShowEffect(OnEffectPanelEnded);
} }
break; break;
} }
} }
private void OnEffectPanelEnded()
{
OpenRatingPanel();
}
#endregion #endregion
public void OpenMainPanel() public void OpenMainPanel()
@ -254,7 +262,7 @@ public class PanelManager : MonoBehaviour
shopItems.Add(shopItem); shopItems.Add(shopItem);
} }
} }
GameManager.Instance.panelManager.OpenShopPanel(shopItems); OpenShopPanel(shopItems);
} }
//승급 패널 생성 //승급 패널 생성

View File

@ -33,15 +33,15 @@ public class SettingsPanelController : PanelController
// BGM을 끄는 경우 // BGM을 끄는 경우
if (!value) if (!value)
{ {
GameManager.Instance.audioManager.StopMainBGM(); // BGM을 끄기 AudioManager.Instance.StopBGM(); // BGM을 끄기
} }
// BGM을 켜는 경우 // BGM을 켜는 경우
else else
{ {
// 이미 BGM이 재생 중인 경우 새로 시작하지 않도록 체크 // 이미 BGM이 재생 중인 경우 새로 시작하지 않도록 체크
if (!GameManager.Instance.audioManager.GetComponent<AudioSource>().isPlaying) if (!AudioManager.Instance.bgmAudioSource.isPlaying)
{ {
GameManager.Instance.audioManager.PlayMainBGM(); // BGM을 켜기 AudioManager.Instance.PlayBGM(); // BGM을 켜기
} }
} }
} }

View File

@ -0,0 +1,52 @@
using UnityEngine;
using UnityEngine.UI;
public class SingleInteractableButtonHandler : MonoBehaviour
{
[Tooltip("이 버튼이 한 번만 클릭되도록 제한할지 여부")]
[SerializeField] private bool enableOneTimeClick = true;
private Button _button;
private bool hasBeenClicked = false;
private void Awake()
{
// 버튼 컴포넌트 가져오기
_button = GetComponent<Button>();
if (_button != null && enableOneTimeClick)
{
// 기존 onClick 이벤트를 저장
Button.ButtonClickedEvent originalOnClick = _button.onClick;
_button.onClick = new Button.ButtonClickedEvent();
_button.onClick.AddListener(() =>
{
if (!hasBeenClicked)
{
hasBeenClicked = true;
for (int i = 0; i < originalOnClick.GetPersistentEventCount(); i++)
{
originalOnClick.Invoke();
}
// 버튼 비활성화
_button.interactable = false;
}
});
}
}
// 버튼 상태 리셋
public void ResetButton()
{
hasBeenClicked = false;
if (_button != null)
{
_button.interactable = true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4330206548604932b038a7007dacf94b
timeCreated: 1742970986