From bb2463d970e222585da19a68f6814c5d08e5cf33 Mon Sep 17 00:00:00 2001 From: Konstantin Dyachenko Date: Sat, 6 Jun 2026 22:48:30 +0700 Subject: [PATCH] [Add] End game, Restart, Final Check --- Assets/Config/MinesweeperUiConfig.asset | 4 +- .../Runtime/Commands/GameCommandHandlers.cs | 7 + Assets/Runtime/Core/GameStateService.cs | 5 + Assets/Runtime/Core/IGameStateService.cs | 1 + Assets/Runtime/ECS/BoardEcsSyncService.cs | 10 + Assets/Runtime/ECS/IBoardEcsSyncService.cs | 1 + .../Presentation/Presenters/GamePresenter.cs | 2 +- Assets/Scenes/SampleScene.unity | 390 +----------------- 8 files changed, 29 insertions(+), 391 deletions(-) diff --git a/Assets/Config/MinesweeperUiConfig.asset b/Assets/Config/MinesweeperUiConfig.asset index 78589cb..6aaef77 100644 --- a/Assets/Config/MinesweeperUiConfig.asset +++ b/Assets/Config/MinesweeperUiConfig.asset @@ -17,8 +17,8 @@ MonoBehaviour: k__BackingField: {fileID: -4087064840323337479, guid: 4c4c10e49c2777748899d811a0e67689, type: 3} k__BackingField: {fileID: -3219474053889490514, guid: 4c4c10e49c2777748899d811a0e67689, type: 3} k__BackingField: {fileID: 6406400753494049822, guid: 266915ac0173ea44b81985eb253dfa88, type: 3} - k__BackingField: {fileID: 0} - k__BackingField: {fileID: 0} + k__BackingField: {fileID: -8492488664197331416, guid: 4c4c10e49c2777748899d811a0e67689, type: 3} + k__BackingField: {fileID: 1268057099028474845, guid: 4c4c10e49c2777748899d811a0e67689, type: 3} k__BackingField: {r: 0.5, g: 0.5, b: 0.5, a: 1} k__BackingField: {r: 1, g: 1, b: 1, a: 1} defaultTextColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Runtime/Commands/GameCommandHandlers.cs b/Assets/Runtime/Commands/GameCommandHandlers.cs index e885282..86e31f4 100644 --- a/Assets/Runtime/Commands/GameCommandHandlers.cs +++ b/Assets/Runtime/Commands/GameCommandHandlers.cs @@ -169,12 +169,18 @@ namespace Minesweeper.Commands public void Handle(RestartCommand command) { + var shouldNotifyReset = gameStateService.Current == GameState.Preparing; pauseService.Resume(); timerService.Reset(); boardService.InitializeEmptyBoard(); gameStateService.SetState(GameState.Preparing); boardEcsSyncService.SyncBoard(boardService); boardEcsSyncService.SyncGameState(gameStateService.Current, false); + + if (shouldNotifyReset) + { + gameStateService.NotifyCurrentStateChanged(); + } } } @@ -233,6 +239,7 @@ namespace Minesweeper.Commands pauseService.Resume(); timerService.Reset(); gameStateService.SetState(GameState.FieldSelection); + boardEcsSyncService.ClearBoard(); boardEcsSyncService.SyncGameState(gameStateService.Current, false); } } diff --git a/Assets/Runtime/Core/GameStateService.cs b/Assets/Runtime/Core/GameStateService.cs index 6b33236..271c0d2 100644 --- a/Assets/Runtime/Core/GameStateService.cs +++ b/Assets/Runtime/Core/GameStateService.cs @@ -18,5 +18,10 @@ namespace Minesweeper.Core Current = state; StateChanged?.Invoke(Current); } + + public void NotifyCurrentStateChanged() + { + StateChanged?.Invoke(Current); + } } } diff --git a/Assets/Runtime/Core/IGameStateService.cs b/Assets/Runtime/Core/IGameStateService.cs index 271a543..d2b17c8 100644 --- a/Assets/Runtime/Core/IGameStateService.cs +++ b/Assets/Runtime/Core/IGameStateService.cs @@ -9,5 +9,6 @@ namespace Minesweeper.Core GameState Current { get; } void SetState(GameState state); + void NotifyCurrentStateChanged(); } } diff --git a/Assets/Runtime/ECS/BoardEcsSyncService.cs b/Assets/Runtime/ECS/BoardEcsSyncService.cs index be1179a..7c899ff 100644 --- a/Assets/Runtime/ECS/BoardEcsSyncService.cs +++ b/Assets/Runtime/ECS/BoardEcsSyncService.cs @@ -7,6 +7,16 @@ namespace Minesweeper.ECS { public sealed class BoardEcsSyncService : IBoardEcsSyncService { + public void ClearBoard() + { + if (!TryGetEntityManager(out var entityManager)) + { + return; + } + + ClearCells(entityManager); + } + public void SyncBoard(IBoardService boardService) { if (!TryGetEntityManager(out var entityManager)) diff --git a/Assets/Runtime/ECS/IBoardEcsSyncService.cs b/Assets/Runtime/ECS/IBoardEcsSyncService.cs index bbeb96e..8d90860 100644 --- a/Assets/Runtime/ECS/IBoardEcsSyncService.cs +++ b/Assets/Runtime/ECS/IBoardEcsSyncService.cs @@ -4,6 +4,7 @@ namespace Minesweeper.ECS { public interface IBoardEcsSyncService { + void ClearBoard(); void SyncBoard(IBoardService boardService); void SyncGameState(GameState state, bool hasFirstClick); } diff --git a/Assets/Runtime/Presentation/Presenters/GamePresenter.cs b/Assets/Runtime/Presentation/Presenters/GamePresenter.cs index defcc52..c5d8435 100644 --- a/Assets/Runtime/Presentation/Presenters/GamePresenter.cs +++ b/Assets/Runtime/Presentation/Presenters/GamePresenter.cs @@ -155,7 +155,7 @@ namespace Minesweeper.Presentation.Presenters private void OnPauseChanged(bool isPaused) { - if (isPaused) + if (isPaused && gameStateService.Current == GameState.Playing) { view.ShowPause(); } diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index d06384b..a18d77b 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -256,43 +256,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 54829048} m_CullTransparentMesh: 1 ---- !u!1 &89755652 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 89755653} - m_Layer: 5 - m_Name: Content - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &89755653 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 89755652} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 469640542} - - {fileID: 787116859} - m_Father: {fileID: 1414158412} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -15, y: -15} - m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &196388795 GameObject: m_ObjectHideFlags: 0 @@ -686,7 +649,6 @@ RectTransform: m_Children: - {fileID: 1101876292} - {fileID: 1373940536} - - {fileID: 1414158412} m_Father: {fileID: 239194491} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -896,96 +858,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 420741123} m_CullTransparentMesh: 1 ---- !u!1 &469640541 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 469640542} - - component: {fileID: 469640545} - - component: {fileID: 469640544} - - component: {fileID: 469640543} - m_Layer: 5 - m_Name: Image - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &469640542 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 469640541} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 89755653} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &469640543 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 469640541} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 86710e43de46f6f4bac7c8e50813a599, type: 3} - m_Name: - m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.AspectRatioFitter - m_AspectMode: 4 - m_AspectRatio: 1 ---- !u!114 &469640544 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 469640541} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: -8492488664197331416, guid: 4c4c10e49c2777748899d811a0e67689, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &469640545 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 469640541} - m_CullTransparentMesh: 1 --- !u!1 &513281805 GameObject: m_ObjectHideFlags: 0 @@ -1708,143 +1580,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 751542996} m_CullTransparentMesh: 1 ---- !u!1 &787116858 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 787116859} - - component: {fileID: 787116861} - - component: {fileID: 787116860} - m_Layer: 5 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &787116859 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 787116858} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 89755653} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 30, y: 30} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &787116860 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 787116858} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: 1 - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 54.6 - m_fontSizeBase: 15 - m_fontWeight: 400 - m_enableAutoSizing: 1 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_characterHorizontalScale: 1 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 0 - m_ActiveFontFeatures: 6e72656b - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_EmojiFallbackSupport: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 2, y: 2, z: 2, w: 2} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &787116861 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 787116858} - m_CullTransparentMesh: 1 --- !u!1 &805410197 GameObject: m_ObjectHideFlags: 0 @@ -2822,7 +2557,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!114 &1183237466 MonoBehaviour: m_ObjectHideFlags: 0 @@ -2840,7 +2575,7 @@ MonoBehaviour: m_Right: 0 m_Top: 0 m_Bottom: 0 - m_ChildAlignment: 0 + m_ChildAlignment: 4 m_StartCorner: 0 m_StartAxis: 0 m_CellSize: {x: 100, y: 100} @@ -3095,127 +2830,6 @@ RectTransform: m_AnchoredPosition: {x: 0, y: -32.5} m_SizeDelta: {x: -30, y: -95} m_Pivot: {x: 0.5, y: 0.5} ---- !u!1 &1414158411 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1414158412} - - component: {fileID: 1414158415} - - component: {fileID: 1414158414} - - component: {fileID: 1414158413} - m_Layer: 5 - m_Name: Button (Mine) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!224 &1414158412 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1414158411} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 89755653} - m_Father: {fileID: 289057769} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 50, y: 50} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1414158413 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1414158411} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1414158414} - m_OnClick: - m_PersistentCalls: - m_Calls: [] ---- !u!114 &1414158414 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1414158411} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: -4571551822685222379, guid: 4c4c10e49c2777748899d811a0e67689, type: 3} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 2 ---- !u!222 &1414158415 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1414158411} - m_CullTransparentMesh: 1 --- !u!1 &1520711086 GameObject: m_ObjectHideFlags: 0