From 9b71b004410622f59f25bd34c623ad775f2cac0a Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Thu, 4 Dec 2025 02:16:38 +0100 Subject: [PATCH] Finish work --- Assets/Scenes/MiniGames/FortFight.unity | 971 +++++++++++++++++- .../FortFight/AI/FortFightAIController.cs | 4 +- .../FortFight/Core/AmmunitionManager.cs | 32 + .../FortFight/Core/CameraController.cs | 59 +- .../FortFight/Core/FortFightGameManager.cs | 163 ++- .../Minigames/FortFight/Core/FortManager.cs | 27 + .../Minigames/FortFight/Core/TurnManager.cs | 47 +- .../Minigames/FortFight/Fort/FortBlock.cs | 14 +- .../FortFight/Fort/FortController.cs | 73 +- .../FortFight/Projectiles/ProjectileBase.cs | 49 + .../FortFight/Projectiles/TrashPiece.cs | 3 + .../Minigames/FortFight/UI/AmmunitionPanel.cs | 32 +- .../Minigames/FortFight/UI/FortHealthUI.cs | 87 +- .../Minigames/FortFight/UI/GameOverUI.cs | 234 +++++ .../Minigames/FortFight/UI/GameOverUI.cs.meta | 3 + .../Minigames/FortFight/UI/GameplayPage.cs | 5 +- Assets/Settings/FortFightSettings.asset | 8 +- 17 files changed, 1684 insertions(+), 127 deletions(-) create mode 100644 Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs create mode 100644 Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs.meta diff --git a/Assets/Scenes/MiniGames/FortFight.unity b/Assets/Scenes/MiniGames/FortFight.unity index 3bfbc26f..2ef43264 100644 --- a/Assets/Scenes/MiniGames/FortFight.unity +++ b/Assets/Scenes/MiniGames/FortFight.unity @@ -827,6 +827,142 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 298557364} m_CullTransparentMesh: 1 +--- !u!1 &325936741 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 325936742} + - component: {fileID: 325936744} + - component: {fileID: 325936743} + m_Layer: 5 + m_Name: Time + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &325936742 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 325936741} + 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: 1761040456} + 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: 3.637979e-12} + m_SizeDelta: {x: 300, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &325936743 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 325936741} + 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: 10:00 + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, 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: 150 + m_fontSizeBase: 150 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + 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: 0, y: 0, z: 0, w: 0} + 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 &325936744 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 325936741} + m_CullTransparentMesh: 1 --- !u!1 &377753195 GameObject: m_ObjectHideFlags: 0 @@ -1374,15 +1510,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 74f26236978245cdaf33909a7c242cbf, type: 3} m_Name: m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.FortFightPhase2Tester - _isRegistered: 0 - _cachedSaveId: - enableKeyboardControls: 1 - testDamageAmount: 25 - autoTestOnStart: 0 - autoTestDelay: 2 - fortManager: {fileID: 0} - playerFort: {fileID: 0} - enemyFort: {fileID: 0} --- !u!4 &534849268 Transform: m_ObjectHideFlags: 0 @@ -2337,6 +2464,142 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 716790031} m_CullTransparentMesh: 1 +--- !u!1 &729789711 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 729789712} + - component: {fileID: 729789714} + - component: {fileID: 729789713} + m_Layer: 5 + m_Name: Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &729789712 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 729789711} + 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: 1761040456} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -47} + m_SizeDelta: {x: 500, y: 200} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &729789713 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 729789711} + 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: GAME OVER + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, 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: 100 + m_fontSizeBase: 100 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + 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: 0, y: 0, z: 0, w: 0} + 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 &729789714 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 729789711} + m_CullTransparentMesh: 1 --- !u!1 &799036563 GameObject: m_ObjectHideFlags: 0 @@ -2370,6 +2633,73 @@ Transform: - {fileID: 1460473367} m_Father: {fileID: 204905895} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &805585727 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 805585728} + - component: {fileID: 805585730} + - component: {fileID: 805585729} + m_Layer: 5 + m_Name: GameOverScreen + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &805585728 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 805585727} + 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: 1761040456} + m_Father: {fileID: 1156219952} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.2, y: 0.2} + m_AnchorMax: {x: 0.8, y: 0.8} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!225 &805585729 +CanvasGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 805585727} + m_Enabled: 1 + m_Alpha: 1 + m_Interactable: 1 + m_BlocksRaycasts: 1 + m_IgnoreParentGroups: 0 +--- !u!114 &805585730 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 805585727} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ffb13ad5109340eba06f9c02082ece94, type: 3} + m_Name: + m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.UI.GameOverUI + rootPanel: {fileID: 805585727} + elapsedTimeText: {fileID: 325936743} + winnerText: {fileID: 729789713} + restartButton: {fileID: 1996879309} + canvasGroup: {fileID: 805585729} --- !u!1 &841922113 GameObject: m_ObjectHideFlags: 0 @@ -2896,7 +3226,6 @@ MonoBehaviour: m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.Core.TurnManager playerOneSlingshotController: {fileID: 841922117} playerTwoSlingshotController: {fileID: 1460473370} - ammunitionManager: {fileID: 878268913} cameraController: {fileID: 1674657452} --- !u!114 &878268911 MonoBehaviour: @@ -2910,11 +3239,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 517ef0a4f14e16f42987a95684371b73, type: 3} m_Name: m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.Core.FortFightGameManager - turnManager: {fileID: 878268910} aiController: {fileID: 878268909} - fortManager: {fileID: 878268912} modeSelectionPage: {fileID: 2036414581} gameplayPage: {fileID: 1585033674} + gameOverUI: {fileID: 805585730} --- !u!114 &878268912 MonoBehaviour: m_ObjectHideFlags: 0 @@ -3108,6 +3436,7 @@ RectTransform: m_Children: - {fileID: 2036414579} - {fileID: 1585033672} + - {fileID: 805585728} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -3421,6 +3750,7 @@ RectTransform: - {fileID: 1817075752} - {fileID: 579665402} - {fileID: 716790032} + - {fileID: 1956621112} m_Father: {fileID: 1286877329} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 1} @@ -3450,6 +3780,8 @@ MonoBehaviour: autoBindToFort: 1 isPlayerFort: 0 fortManager: {fileID: 0} + debugDisplay: 1 + debugHpText: {fileID: 1956621113} --- !u!114 &1209958793 MonoBehaviour: m_ObjectHideFlags: 0 @@ -3871,6 +4203,7 @@ RectTransform: - {fileID: 601402838} - {fileID: 1337135607} - {fileID: 123702486} + - {fileID: 1726433070} m_Father: {fileID: 1286877329} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} @@ -3938,6 +4271,8 @@ MonoBehaviour: autoBindToFort: 1 isPlayerFort: 1 fortManager: {fileID: 0} + debugDisplay: 1 + debugHpText: {fileID: 1726433071} --- !u!1 &1410755663 GameObject: m_ObjectHideFlags: 0 @@ -4624,7 +4959,6 @@ MonoBehaviour: playerOneCamera: {fileID: 846792105} playerTwoCamera: {fileID: 630420675} projectileCamera: {fileID: 1592155790} - turnManager: {fileID: 878268910} --- !u!4 &1674657453 Transform: m_ObjectHideFlags: 0 @@ -4640,6 +4974,142 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1726433069 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1726433070} + - component: {fileID: 1726433072} + - component: {fileID: 1726433071} + m_Layer: 5 + m_Name: DebugText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1726433070 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1726433069} + 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: 1366022892} + 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: 250, y: -50.00003} + m_SizeDelta: {x: 200, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1726433071 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1726433069} + 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: New Text + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4278190335 + m_fontColor: {r: 1, g: 0, b: 0, 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: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + 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: 0, y: 0, z: 0, w: 0} + 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 &1726433072 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1726433069} + m_CullTransparentMesh: 1 --- !u!1 &1755632906 GameObject: m_ObjectHideFlags: 0 @@ -4746,6 +5216,84 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1761040455 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1761040456} + - component: {fileID: 1761040458} + - component: {fileID: 1761040457} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1761040456 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1761040455} + 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: 729789712} + - {fileID: 325936742} + - {fileID: 1996879308} + m_Father: {fileID: 805585728} + 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 &1761040457 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1761040455} + 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: 0, g: 0, b: 0, a: 0.22745098} + 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: 0} + 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 &1761040458 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1761040455} + m_CullTransparentMesh: 1 --- !u!1 &1787332575 GameObject: m_ObjectHideFlags: 0 @@ -4949,7 +5497,7 @@ Camera: far clip plane: 1000 field of view: 60 orthographic: 1 - orthographic size: 25 + orthographic size: 15 m_Depth: -1 m_CullingMask: serializedVersion: 2 @@ -4974,7 +5522,7 @@ Transform: m_GameObject: {fileID: 1810521056} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 9.1, z: -10} + m_LocalPosition: {x: 0, y: 0, z: -10} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -5116,6 +5664,263 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1817075751} m_CullTransparentMesh: 1 +--- !u!1 &1956621111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1956621112} + - component: {fileID: 1956621114} + - component: {fileID: 1956621113} + m_Layer: 5 + m_Name: DebugText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1956621112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1956621111} + 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: 1209958791} + 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: -250.00006, y: -50} + m_SizeDelta: {x: 200, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1956621113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1956621111} + 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: New Text + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4278190335 + m_fontColor: {r: 1, g: 0, b: 0, 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: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + 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: 0, y: 0, z: 0, w: 0} + 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 &1956621114 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1956621111} + m_CullTransparentMesh: 1 +--- !u!1 &1996879307 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1996879308} + - component: {fileID: 1996879311} + - component: {fileID: 1996879310} + - component: {fileID: 1996879309} + m_Layer: 5 + m_Name: Restart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1996879308 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1996879307} + 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: 2136441733} + m_Father: {fileID: 1761040456} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 49} + m_SizeDelta: {x: 500, y: 250} + m_Pivot: {x: 0.5, y: 0} +--- !u!114 &1996879309 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1996879307} + 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: 1996879310} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1996879310 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1996879307} + 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: -4331849829665928538, guid: 8be45455b29f80241a3b8aae36291752, 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 &1996879311 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1996879307} + m_CullTransparentMesh: 1 --- !u!1 &2036414578 GameObject: m_ObjectHideFlags: 0 @@ -5687,6 +6492,142 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 2148236734266076239, guid: 2aa2fb2d3da8f3b4e9d1058cea4e418d, type: 3} m_PrefabInstance: {fileID: 2126145555} m_PrefabAsset: {fileID: 0} +--- !u!1 &2136441732 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2136441733} + - component: {fileID: 2136441735} + - component: {fileID: 2136441734} + 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 &2136441733 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136441732} + 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: 1996879308} + 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 &2136441734 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136441732} + 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: RESTART + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2} + m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, 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: 100 + m_fontSizeBase: 100 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + 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: 0, y: 0, z: 0, w: 0} + 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 &2136441735 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2136441732} + m_CullTransparentMesh: 1 --- !u!1001 &428622665700748139 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Minigames/FortFight/AI/FortFightAIController.cs b/Assets/Scripts/Minigames/FortFight/AI/FortFightAIController.cs index 14a78a47..d6484ca2 100644 --- a/Assets/Scripts/Minigames/FortFight/AI/FortFightAIController.cs +++ b/Assets/Scripts/Minigames/FortFight/AI/FortFightAIController.cs @@ -27,8 +27,8 @@ namespace Minigames.FortFight.AI /// public void Initialize() { - // Get reference to turn manager - turnManager = FindFirstObjectByType(); + // Get reference to turn manager via singleton + turnManager = TurnManager.Instance; if (turnManager == null) { diff --git a/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs b/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs index 694d8398..927ec53a 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs @@ -11,9 +11,27 @@ namespace Minigames.FortFight.Core /// /// Manages ammunition selection and cooldowns for Fort Fight. /// Tracks which ammo types are available and handles cooldown timers. + /// Singleton pattern for easy access throughout the game. /// public class AmmunitionManager : ManagedBehaviour { + #region Singleton + + private static AmmunitionManager _instance; + public static AmmunitionManager Instance + { + get + { + if (_instance == null) + { + _instance = FindFirstObjectByType(); + } + return _instance; + } + } + + #endregion + #region Constants private const int MaxPlayers = 2; // Support 2 players (indices 0 and 1) @@ -85,6 +103,20 @@ namespace Minigames.FortFight.Core #region Lifecycle + internal override void OnManagedAwake() + { + base.OnManagedAwake(); + + // Register singleton + if (_instance != null && _instance != this) + { + Logging.Warning("[AmmunitionManager] Multiple instances detected! Destroying duplicate."); + Destroy(gameObject); + return; + } + _instance = this; + } + internal override void OnManagedStart() { base.OnManagedStart(); diff --git a/Assets/Scripts/Minigames/FortFight/Core/CameraController.cs b/Assets/Scripts/Minigames/FortFight/Core/CameraController.cs index 1578e2ee..c68d88ab 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/CameraController.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/CameraController.cs @@ -10,9 +10,27 @@ namespace Minigames.FortFight.Core /// Manages camera states and transitions for the Fort Fight minigame. /// Subscribes to turn events and switches camera views accordingly. /// Uses Cinemachine for smooth camera blending. + /// Singleton pattern for easy access. /// public class CameraController : ManagedBehaviour { + #region Singleton + + private static CameraController _instance; + public static CameraController Instance + { + get + { + if (_instance == null) + { + _instance = FindFirstObjectByType(); + } + return _instance; + } + } + + #endregion + #region Inspector References [Header("Cinemachine Cameras")] @@ -28,9 +46,7 @@ namespace Minigames.FortFight.Core [Tooltip("Camera that follows projectiles in flight (should have CinemachineFollow component)")] [SerializeField] private CinemachineCamera projectileCamera; - [Header("References")] - [Tooltip("Turn manager to subscribe to turn events")] - [SerializeField] private TurnManager turnManager; + // Note: TurnManager accessed via singleton #endregion @@ -49,6 +65,15 @@ namespace Minigames.FortFight.Core { base.OnManagedAwake(); + // Register singleton + if (_instance != null && _instance != this) + { + Logging.Warning("[CameraController] Multiple instances detected! Destroying duplicate."); + Destroy(gameObject); + return; + } + _instance = this; + // Validate references if (wideViewCamera == null) { @@ -70,21 +95,17 @@ namespace Minigames.FortFight.Core Logging.Warning("[CameraController] Projectile camera not assigned - projectiles won't be followed!"); } - if (turnManager == null) - { - Logging.Error("[CameraController] Turn manager not assigned!"); - } } internal override void OnManagedStart() { base.OnManagedStart(); - // Subscribe to turn events - if (turnManager != null) + // Subscribe to turn events via singleton + if (TurnManager.Instance != null) { - turnManager.OnTurnStarted += HandleTurnStarted; - turnManager.OnTurnEnded += HandleTurnEnded; + TurnManager.Instance.OnTurnStarted += HandleTurnStarted; + TurnManager.Instance.OnTurnEnded += HandleTurnEnded; Logging.Debug("[CameraController] Subscribed to turn events"); } @@ -95,13 +116,18 @@ namespace Minigames.FortFight.Core internal override void OnManagedDestroy() { + if (_instance == this) + { + _instance = null; + } + base.OnManagedDestroy(); // Unsubscribe from events - if (turnManager != null) + if (TurnManager.Instance != null) { - turnManager.OnTurnStarted -= HandleTurnStarted; - turnManager.OnTurnEnded -= HandleTurnEnded; + TurnManager.Instance.OnTurnStarted -= HandleTurnStarted; + TurnManager.Instance.OnTurnEnded -= HandleTurnEnded; } } @@ -259,11 +285,6 @@ namespace Minigames.FortFight.Core #if UNITY_EDITOR private void OnValidate() { - // Auto-find TurnManager if not assigned - if (turnManager == null) - { - turnManager = FindFirstObjectByType(); - } } #endif diff --git a/Assets/Scripts/Minigames/FortFight/Core/FortFightGameManager.cs b/Assets/Scripts/Minigames/FortFight/Core/FortFightGameManager.cs index 32dd5366..e880e906 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/FortFightGameManager.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/FortFightGameManager.cs @@ -25,13 +25,14 @@ namespace Minigames.FortFight.Core #region Inspector References [Header("Core Systems")] - [SerializeField] private TurnManager turnManager; [SerializeField] private FortFightAIController aiController; - [SerializeField] private FortManager fortManager; [Header("UI References")] [SerializeField] private ModeSelectionPage modeSelectionPage; [SerializeField] private GameplayPage gameplayPage; + [SerializeField] private UI.GameOverUI gameOverUI; + + // Note: TurnManager and FortManager accessed via singletons #endregion @@ -60,10 +61,23 @@ namespace Minigames.FortFight.Core private PlayerData playerOne; private PlayerData playerTwo; private bool isGameActive = false; + private float gameStartTime = 0f; public FortFightGameMode CurrentGameMode => currentGameMode; public bool IsGameActive => isGameActive; + /// + /// Get elapsed game time in seconds since game started + /// + public float ElapsedGameTime + { + get + { + if (!isGameActive) return 0f; + return Time.time - gameStartTime; + } + } + #endregion #region Lifecycle @@ -97,9 +111,19 @@ namespace Minigames.FortFight.Core { base.OnManagedDestroy(); - if (_instance == this) + // Unsubscribe from fort defeated events + var fortManager = FortManager.Instance; + if (fortManager != null) { - _instance = null; + if (fortManager.PlayerFort != null) + { + fortManager.PlayerFort.OnFortDefeated -= OnFortDefeated; + } + + if (fortManager.EnemyFort != null) + { + fortManager.EnemyFort.OnFortDefeated -= OnFortDefeated; + } } // Clear events @@ -114,11 +138,6 @@ namespace Minigames.FortFight.Core private void ValidateReferences() { - if (turnManager == null) - { - Logging.Error("[FortFightGameManager] TurnManager reference not assigned!"); - } - if (aiController == null) { Logging.Warning("[FortFightGameManager] AIController reference not assigned! AI mode will not work."); @@ -133,6 +152,11 @@ namespace Minigames.FortFight.Core { Logging.Error("[FortFightGameManager] GameplayPage reference not assigned!"); } + + if (gameOverUI == null) + { + Logging.Error("[FortFightGameManager] GameOverUI reference not assigned!"); + } } #endregion @@ -151,10 +175,16 @@ namespace Minigames.FortFight.Core Logging.Debug("[FortFightGameManager] Showing mode selection page"); } + // Hide other UI pages if (gameplayPage != null) { gameplayPage.gameObject.SetActive(false); } + + if (gameOverUI != null) + { + gameOverUI.Hide(); + } } /// @@ -192,15 +222,15 @@ namespace Minigames.FortFight.Core Logging.Debug($"[FortFightGameManager] Players initialized - P1: {playerOne.PlayerName}, P2: {playerTwo.PlayerName}"); - // Spawn forts for both players - if (fortManager != null) + // Spawn forts for both players via singleton + if (FortManager.Instance != null) { - fortManager.SpawnForts(); + FortManager.Instance.SpawnForts(); Logging.Debug("[FortFightGameManager] Forts spawned for both players"); } else { - Logging.Warning("[FortFightGameManager] FortManager not assigned! Forts will not spawn."); + Logging.Warning("[FortFightGameManager] FortManager not found! Forts will not spawn."); } } @@ -221,11 +251,11 @@ namespace Minigames.FortFight.Core gameplayPage.TransitionIn(); } - // Initialize turn manager - if (turnManager != null) + // Initialize turn manager via singleton + if (TurnManager.Instance != null) { - turnManager.Initialize(playerOne, playerTwo); - turnManager.StartGame(); + TurnManager.Instance.Initialize(playerOne, playerTwo); + TurnManager.Instance.StartGame(); } // Initialize AI if in single player mode @@ -234,29 +264,122 @@ namespace Minigames.FortFight.Core aiController.Initialize(); } + // Subscribe to fort defeated events (may need to wait for forts to spawn) + StartCoroutine(SubscribeToFortEventsWhenReady()); + isGameActive = true; + gameStartTime = Time.time; // Start tracking elapsed time OnGameStarted?.Invoke(); Logging.Debug("[FortFightGameManager] Game started!"); } /// - /// End the game + /// Wait for forts to be spawned and ready, then subscribe to their defeat events + /// + private System.Collections.IEnumerator SubscribeToFortEventsWhenReady() + { + Logging.Debug("[FortFightGameManager] Waiting for forts to be ready..."); + + var fortManager = FortManager.Instance; + if (fortManager == null) + { + Logging.Error("[FortFightGameManager] FortManager not found! Cannot subscribe to fort events."); + yield break; + } + + // Wait up to 5 seconds for forts to spawn + float timeout = 5f; + float elapsed = 0f; + + while ((fortManager.PlayerFort == null || fortManager.EnemyFort == null) && elapsed < timeout) + { + yield return new WaitForSeconds(0.1f); + elapsed += 0.1f; + } + + if (fortManager.PlayerFort == null || fortManager.EnemyFort == null) + { + Logging.Error($"[FortFightGameManager] Forts not ready after {timeout}s! PlayerFort: {fortManager.PlayerFort != null}, EnemyFort: {fortManager.EnemyFort != null}"); + yield break; + } + + // Subscribe to both forts + Logging.Debug($"[FortFightGameManager] Forts ready! Subscribing to defeat events..."); + + fortManager.PlayerFort.OnFortDefeated += OnFortDefeated; + fortManager.EnemyFort.OnFortDefeated += OnFortDefeated; + + Logging.Debug($"[FortFightGameManager] Successfully subscribed to fort defeat events: PlayerFort={fortManager.PlayerFort.FortName}, EnemyFort={fortManager.EnemyFort.FortName}"); + } + + /// + /// Called when any fort is defeated + /// + private void OnFortDefeated() + { + Logging.Debug("[FortFightGameManager] Fort defeated, ending game..."); + EndGame(); + } + + /// + /// End the game and show game over UI /// public void EndGame() { + if (!isGameActive) + { + Logging.Warning("[FortFightGameManager] EndGame called but game is not active"); + return; + } + isGameActive = false; - if (turnManager != null) + // Stop turn manager + if (TurnManager.Instance != null) { - turnManager.SetGameOver(); + TurnManager.Instance.SetGameOver(); } + // Manage UI transitions + ShowGameOver(); + OnGameEnded?.Invoke(); Logging.Debug("[FortFightGameManager] Game ended"); } + /// + /// Show game over UI and hide gameplay UI + /// + private void ShowGameOver() + { + // Hide gameplay page + if (gameplayPage != null) + { + gameplayPage.gameObject.SetActive(false); + } + + // Show game over UI + if (gameOverUI != null) + { + gameOverUI.Show(); + } + else + { + Logging.Error("[FortFightGameManager] Cannot show game over UI - reference not assigned!"); + } + + // Switch camera to wide view + var cameraController = CameraController.Instance; + if (cameraController != null) + { + cameraController.ShowWideView(); + } + + Logging.Debug("[FortFightGameManager] Game over UI shown"); + } + #endregion } } diff --git a/Assets/Scripts/Minigames/FortFight/Core/FortManager.cs b/Assets/Scripts/Minigames/FortFight/Core/FortManager.cs index 08cc87b2..3c11f781 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/FortManager.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/FortManager.cs @@ -9,9 +9,27 @@ namespace Minigames.FortFight.Core { /// /// Manages fort prefab spawning and references during gameplay. + /// Singleton pattern for easy access to fort references. /// public class FortManager : ManagedBehaviour { + #region Singleton + + private static FortManager _instance; + public static FortManager Instance + { + get + { + if (_instance == null) + { + _instance = FindFirstObjectByType(); + } + return _instance; + } + } + + #endregion + #region Inspector Properties [Header("Fort Prefabs")] @@ -56,6 +74,15 @@ namespace Minigames.FortFight.Core { base.OnManagedAwake(); + // Register singleton + if (_instance != null && _instance != this) + { + Logging.Warning("[FortManager] Multiple instances detected! Destroying duplicate."); + Destroy(gameObject); + return; + } + _instance = this; + // Validate spawn points if (playerSpawnPoint == null) { diff --git a/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs b/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs index bfc87117..28136330 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs @@ -10,9 +10,27 @@ namespace Minigames.FortFight.Core /// Manages turn order and turn state for Fort Fight minigame. /// Handles transitions between Player One, Player Two/AI turns. /// Manages turn actions and input delegation. + /// Singleton pattern for easy access to turn state. /// public class TurnManager : ManagedBehaviour { + #region Singleton + + private static TurnManager _instance; + public static TurnManager Instance + { + get + { + if (_instance == null) + { + _instance = FindFirstObjectByType(); + } + return _instance; + } + } + + #endregion + #region Inspector References [Header("Slingshot Controllers")] @@ -23,12 +41,11 @@ namespace Minigames.FortFight.Core [SerializeField] private SlingshotController playerTwoSlingshotController; [Header("Systems")] - [Tooltip("Ammunition manager")] - [SerializeField] private AmmunitionManager ammunitionManager; - [Tooltip("Camera controller for projectile tracking")] [SerializeField] private CameraController cameraController; + // Note: AmmunitionManager accessed via singleton (AmmunitionManager.Instance) + #endregion #region Events @@ -75,6 +92,15 @@ namespace Minigames.FortFight.Core { base.OnManagedAwake(); + // Register singleton + if (_instance != null && _instance != this) + { + Logging.Warning("[TurnManager] Multiple instances detected! Destroying duplicate."); + Destroy(gameObject); + return; + } + _instance = this; + // Validate references if (playerOneSlingshotController == null) { @@ -86,11 +112,6 @@ namespace Minigames.FortFight.Core Logging.Error("[TurnManager] Player Two slingshot controller not assigned!"); } - if (ammunitionManager == null) - { - Logging.Error("[TurnManager] Ammunition manager not assigned!"); - } - if (cameraController == null) { Logging.Warning("[TurnManager] Camera controller not assigned - projectiles won't be followed by camera!"); @@ -186,12 +207,12 @@ namespace Minigames.FortFight.Core } // Create and execute turn action with player index - currentTurnAction = new ProjectileTurnAction(activeSlingshot, ammunitionManager, cameraController, currentPlayer.PlayerIndex); + currentTurnAction = new ProjectileTurnAction(activeSlingshot, AmmunitionManager.Instance, cameraController, currentPlayer.PlayerIndex); // Set current ammo on slingshot for this player - if (ammunitionManager != null) + if (AmmunitionManager.Instance != null) { - ProjectileConfig currentAmmo = ammunitionManager.GetSelectedAmmoConfig(currentPlayer.PlayerIndex); + ProjectileConfig currentAmmo = AmmunitionManager.Instance.GetSelectedAmmoConfig(currentPlayer.PlayerIndex); if (currentAmmo != null) { activeSlingshot.SetAmmo(currentAmmo); @@ -253,9 +274,9 @@ namespace Minigames.FortFight.Core OnTurnEnded?.Invoke(currentPlayer); // Decrement ammunition cooldowns for this player - if (ammunitionManager != null) + if (AmmunitionManager.Instance != null) { - ammunitionManager.DecrementCooldowns(currentPlayer.PlayerIndex); + AmmunitionManager.Instance.DecrementCooldowns(currentPlayer.PlayerIndex); } // Enter transition state (triggers wide view camera via OnTurnStarted) diff --git a/Assets/Scripts/Minigames/FortFight/Fort/FortBlock.cs b/Assets/Scripts/Minigames/FortFight/Fort/FortBlock.cs index ba872724..6b0f8224 100644 --- a/Assets/Scripts/Minigames/FortFight/Fort/FortBlock.cs +++ b/Assets/Scripts/Minigames/FortFight/Fort/FortBlock.cs @@ -20,6 +20,9 @@ namespace Minigames.FortFight.Fort [SerializeField] private BlockSize size = BlockSize.Medium; [SerializeField] private bool isWeakPoint = false; + [Tooltip("Fixed HP value for this block (default: 10)")] + [SerializeField] private float blockHp = 10f; + [Header("Weak Point Settings (if applicable)")] [Tooltip("Visual indicator shown in editor/game for weak points")] [SerializeField] private GameObject weakPointVisualIndicator; @@ -146,15 +149,8 @@ namespace Minigames.FortFight.Fort private void CalculateHp() { - // Get material config - var materialConfig = CachedSettings.GetMaterialConfig(material); - float baseMaterialHp = materialConfig?.baseHp ?? 20f; - - // Get size config - var sizeConfig = CachedSettings.GetSizeConfig(size); - float sizeMultiplier = sizeConfig?.hpMultiplier ?? 1f; - - maxHp = baseMaterialHp * sizeMultiplier; + // Use fixed block HP value (default 10) + maxHp = blockHp; currentHp = maxHp; Logging.Debug($"[FortBlock] {gameObject.name} initialized: {material} {size}, HP: {maxHp}"); diff --git a/Assets/Scripts/Minigames/FortFight/Fort/FortController.cs b/Assets/Scripts/Minigames/FortFight/Fort/FortController.cs index 3fdfc825..361381e9 100644 --- a/Assets/Scripts/Minigames/FortFight/Fort/FortController.cs +++ b/Assets/Scripts/Minigames/FortFight/Fort/FortController.cs @@ -52,6 +52,10 @@ namespace Minigames.FortFight.Fort public int InitialBlockCount => initialBlockCount; public bool IsDefeated { get; private set; } + // Aliases for consistency + public float MaxHp => maxFortHp; + public float CurrentHp => currentFortHp; + #endregion #region Private State @@ -171,6 +175,9 @@ namespace Minigames.FortFight.Fort RegisterBlock(block); } + // Step 3: Initialize current HP to match max HP (sum of all blocks) + currentFortHp = maxFortHp; + initialBlockCount = blocks.Count; Logging.Debug($"[FortController] {fortName} - Initialized and registered {blocks.Count} blocks, Total HP: {maxFortHp:F0}"); } @@ -181,7 +188,7 @@ namespace Minigames.FortFight.Fort /// private void RegisterWithManager() { - Core.FortManager manager = FindFirstObjectByType(); + Core.FortManager manager = Core.FortManager.Instance; if (manager == null) { @@ -207,8 +214,9 @@ namespace Minigames.FortFight.Fort if (!blocks.Contains(block)) { blocks.Add(block); + + // Only add to max HP, current HP will be calculated once at end of initialization maxFortHp += block.MaxHp; - currentFortHp += block.MaxHp; // Subscribe to block events block.OnBlockDestroyed += HandleBlockDestroyed; @@ -259,9 +267,8 @@ namespace Minigames.FortFight.Fort // Remove from list blocks.Remove(block); - // Update current HP - currentFortHp -= blockMaxHp; - currentFortHp = Mathf.Max(0f, currentFortHp); + // Recalculate HP by summing all remaining blocks (consistent calculation method) + RecalculateFortHp(); // Notify listeners OnBlockDestroyed?.Invoke(block); @@ -279,7 +286,38 @@ namespace Minigames.FortFight.Fort private void HandleBlockDamaged(float currentBlockHp, float maxBlockHp) { // Block damaged but not destroyed - // Could add visual feedback here if needed + Logging.Debug($"[FortController] {fortName} - Block damaged! CurrentBlockHP: {currentBlockHp}/{maxBlockHp}"); + + // Recalculate current fort HP based on all block HP + RecalculateFortHp(); + + // Notify UI to update + int listenerCount = OnFortDamaged?.GetInvocationList()?.Length ?? 0; + Logging.Debug($"[FortController] {fortName} - Firing OnFortDamaged event. HP: {HpPercentage:F1}%. Listeners: {listenerCount}"); + OnFortDamaged?.Invoke(0f, HpPercentage); + + // Check defeat condition after damage + CheckDefeatCondition(); + } + + /// + /// Recalculate total fort HP by summing all block HP + /// + private void RecalculateFortHp() + { + currentFortHp = 0f; + foreach (var block in blocks) + { + if (block != null) + { + currentFortHp += block.CurrentHp; + } + } + + if (showDebugInfo) + { + Logging.Debug($"[FortController] {fortName} - HP recalculated: {currentFortHp:F0}/{maxFortHp:F0} ({HpPercentage:F1}%)"); + } } #endregion @@ -288,17 +326,32 @@ namespace Minigames.FortFight.Fort private void CheckDefeatCondition() { - if (IsDefeated) return; + if (IsDefeated) + { + Logging.Debug($"[FortController] {fortName} - Already defeated, skipping check"); + return; + } float defeatThreshold = CachedSettings?.FortDefeatThreshold ?? 0.3f; float defeatThresholdPercent = defeatThreshold * 100f; - // Defeat if HP below threshold - if (HpPercentage < defeatThresholdPercent) + Logging.Debug($"[FortController] {fortName} - Checking defeat: HP={currentFortHp:F1}/{maxFortHp:F1} ({HpPercentage:F1}%) vs threshold={defeatThresholdPercent:F1}%"); + + // Defeat if HP at or below threshold + if (HpPercentage <= defeatThresholdPercent) { IsDefeated = true; - Logging.Debug($"[FortController] {fortName} DEFEATED! Final HP: {HpPercentage:F1}% (threshold: {defeatThresholdPercent:F1}%)"); + + int listeners = OnFortDefeated?.GetInvocationList()?.Length ?? 0; + Logging.Debug($"[FortController] {fortName} DEFEATED! Final HP: {HpPercentage:F1}% (threshold: {defeatThresholdPercent:F1}%). Firing event to {listeners} listeners..."); + OnFortDefeated?.Invoke(); + + Logging.Debug($"[FortController] {fortName} - OnFortDefeated event fired"); + } + else + { + Logging.Debug($"[FortController] {fortName} - Not defeated yet ({HpPercentage:F1}% >= {defeatThresholdPercent:F1}%)"); } } diff --git a/Assets/Scripts/Minigames/FortFight/Projectiles/ProjectileBase.cs b/Assets/Scripts/Minigames/FortFight/Projectiles/ProjectileBase.cs index 855ad428..3c96b942 100644 --- a/Assets/Scripts/Minigames/FortFight/Projectiles/ProjectileBase.cs +++ b/Assets/Scripts/Minigames/FortFight/Projectiles/ProjectileBase.cs @@ -56,6 +56,13 @@ namespace Minigames.FortFight.Projectiles public Vector2 LaunchDirection { get; protected set; } public float LaunchForce { get; protected set; } + #endregion + + #region Timeout + + private const float ProjectileTimeout = 10f; // Destroy projectile after 10 seconds if stuck/off-map + private Coroutine timeoutCoroutine; + #endregion #region Components @@ -181,6 +188,41 @@ namespace Minigames.FortFight.Projectiles // Fire event OnLaunched?.Invoke(this); + + // Start timeout - destroy projectile after configured time if it hasn't been destroyed + StartTimeoutTimer(); + } + + #endregion + + #region Timeout + + /// + /// Start timeout timer. Projectile will auto-destroy after timeout to prevent stuck/lost projectiles. + /// + private void StartTimeoutTimer() + { + if (timeoutCoroutine != null) + { + StopCoroutine(timeoutCoroutine); + } + + timeoutCoroutine = StartCoroutine(TimeoutCoroutine()); + } + + /// + /// Timeout coroutine - destroys projectile after configured time + /// + private System.Collections.IEnumerator TimeoutCoroutine() + { + yield return new WaitForSeconds(ProjectileTimeout); + + // Only destroy if still exists (might have been destroyed by collision already) + if (this != null && gameObject != null) + { + Logging.Debug($"[ProjectileBase] {gameObject.name} timed out after {ProjectileTimeout}s, destroying..."); + DestroyProjectile(); + } } #endregion @@ -305,6 +347,13 @@ namespace Minigames.FortFight.Projectiles { Logging.Debug($"[ProjectileBase] Destroying {gameObject.name}"); + // Stop timeout coroutine if running + if (timeoutCoroutine != null) + { + StopCoroutine(timeoutCoroutine); + timeoutCoroutine = null; + } + // Fire destroyed event OnDestroyed?.Invoke(this); diff --git a/Assets/Scripts/Minigames/FortFight/Projectiles/TrashPiece.cs b/Assets/Scripts/Minigames/FortFight/Projectiles/TrashPiece.cs index dedd71a8..6bf498f6 100644 --- a/Assets/Scripts/Minigames/FortFight/Projectiles/TrashPiece.cs +++ b/Assets/Scripts/Minigames/FortFight/Projectiles/TrashPiece.cs @@ -51,6 +51,9 @@ namespace Minigames.FortFight.Projectiles float lifetime = GetEffectLifetime(effect); Destroy(effect, lifetime); } + + // Destroy trash piece immediately after dealing damage + Destroy(gameObject); } } diff --git a/Assets/Scripts/Minigames/FortFight/UI/AmmunitionPanel.cs b/Assets/Scripts/Minigames/FortFight/UI/AmmunitionPanel.cs index a43c34b0..b502d51d 100644 --- a/Assets/Scripts/Minigames/FortFight/UI/AmmunitionPanel.cs +++ b/Assets/Scripts/Minigames/FortFight/UI/AmmunitionPanel.cs @@ -19,14 +19,10 @@ namespace Minigames.FortFight.UI [SerializeField] private int playerIndex = 0; [Header("References")] - [Tooltip("Ammunition manager (shared between both players)")] - [SerializeField] private AmmunitionManager ammunitionManager; - [Tooltip("This player's slingshot controller")] [SerializeField] private SlingshotController slingshotController; - [Tooltip("Turn manager to subscribe to turn events")] - [SerializeField] private TurnManager turnManager; + // Note: AmmunitionManager and TurnManager accessed via singletons [Header("UI")] [Tooltip("Array of ammo buttons in this panel")] @@ -44,21 +40,11 @@ namespace Minigames.FortFight.UI base.OnManagedAwake(); // Validate references - if (ammunitionManager == null) - { - Logging.Error($"[AmmunitionPanel] Player {playerIndex}: Ammunition manager not assigned!"); - } - if (slingshotController == null) { Logging.Error($"[AmmunitionPanel] Player {playerIndex}: Slingshot controller not assigned!"); } - if (turnManager == null) - { - Logging.Error($"[AmmunitionPanel] Player {playerIndex}: Turn manager not assigned!"); - } - if (ammoButtons == null || ammoButtons.Length == 0) { Logging.Warning($"[AmmunitionPanel] Player {playerIndex}: No ammo buttons assigned!"); @@ -78,10 +64,10 @@ namespace Minigames.FortFight.UI // Initialize ammo buttons with player context InitializeButtons(); - // Subscribe to turn events - if (turnManager != null) + // Subscribe to turn events via singleton + if (TurnManager.Instance != null) { - turnManager.OnTurnStarted += HandleTurnStarted; + TurnManager.Instance.OnTurnStarted += HandleTurnStarted; } // Start hidden @@ -93,9 +79,9 @@ namespace Minigames.FortFight.UI base.OnManagedDestroy(); // Unsubscribe from events - if (turnManager != null) + if (TurnManager.Instance != null) { - turnManager.OnTurnStarted -= HandleTurnStarted; + TurnManager.Instance.OnTurnStarted -= HandleTurnStarted; } } @@ -104,13 +90,13 @@ namespace Minigames.FortFight.UI /// private void InitializeButtons() { - if (ammunitionManager == null || slingshotController == null || ammoButtons == null) + if (AmmunitionManager.Instance == null || slingshotController == null || ammoButtons == null) { return; } // Get available projectile types from settings - var availableTypes = ammunitionManager.GetAvailableProjectileTypes(); + var availableTypes = AmmunitionManager.Instance.GetAvailableProjectileTypes(); var settings = GameManager.GetSettingsObject(); if (settings == null) @@ -126,7 +112,7 @@ namespace Minigames.FortFight.UI var config = settings.GetProjectileConfig(availableTypes[i]); if (config != null) { - ammoButtons[i].Initialize(config, ammunitionManager, slingshotController, playerIndex); + ammoButtons[i].Initialize(config, AmmunitionManager.Instance, slingshotController, playerIndex); Logging.Debug($"[AmmunitionPanel] Player {playerIndex}: Initialized button for {config.displayName}"); } } diff --git a/Assets/Scripts/Minigames/FortFight/UI/FortHealthUI.cs b/Assets/Scripts/Minigames/FortFight/UI/FortHealthUI.cs index 13435b81..3c1a7b28 100644 --- a/Assets/Scripts/Minigames/FortFight/UI/FortHealthUI.cs +++ b/Assets/Scripts/Minigames/FortFight/UI/FortHealthUI.cs @@ -31,6 +31,12 @@ namespace Minigames.FortFight.UI [Tooltip("Leave empty to auto-find")] [SerializeField] private Core.FortManager fortManager; + [Header("Debug Display")] + [Tooltip("Show numerical HP values (current/max)")] + [SerializeField] private bool debugDisplay = false; + [Tooltip("Text field to display 'current/max' HP values")] + [SerializeField] private TextMeshProUGUI debugHpText; + #endregion #region Private State @@ -45,11 +51,17 @@ namespace Minigames.FortFight.UI { base.OnManagedStart(); + Logging.Debug($"[FortHealthUI] OnManagedStart - autoBindToFort: {autoBindToFort}, isPlayerFort: {isPlayerFort}"); + // Auto-bind to dynamically spawned forts if (autoBindToFort) { SetupAutoBinding(); } + else + { + Logging.Warning($"[FortHealthUI] Auto-bind disabled! HP UI will not update."); + } } internal override void OnManagedDestroy() @@ -76,33 +88,53 @@ namespace Minigames.FortFight.UI private void SetupAutoBinding() { - // Find FortManager if not assigned - if (fortManager == null) - { - fortManager = FindFirstObjectByType(); - } + Logging.Debug($"[FortHealthUI] SetupAutoBinding called for {(isPlayerFort ? "PLAYER" : "ENEMY")} fort"); + + // Get FortManager via singleton + fortManager = Core.FortManager.Instance; if (fortManager == null) { - Logging.Warning($"[FortHealthUI] Cannot auto-bind: FortManager not found. HP UI will not update."); + Logging.Error($"[FortHealthUI] CRITICAL: FortManager.Instance is NULL! HP UI will not work."); return; } - // Subscribe to appropriate spawn event + Logging.Debug($"[FortHealthUI] FortManager found. Checking if fort already spawned..."); + + // Check if fort already spawned (missed the spawn event) + FortController existingFort = isPlayerFort ? fortManager.PlayerFort : fortManager.EnemyFort; + if (existingFort != null) + { + Logging.Debug($"[FortHealthUI] Fort already exists, binding immediately: {existingFort.FortName}"); + BindToFort(existingFort); + return; + } + + Logging.Debug($"[FortHealthUI] Fort not spawned yet. Subscribing to spawn events..."); + + // Subscribe to appropriate spawn event for future spawn if (isPlayerFort) { fortManager.OnPlayerFortSpawned += OnFortSpawned; - Logging.Debug($"[FortHealthUI] Subscribed to PLAYER fort spawn"); + Logging.Debug($"[FortHealthUI] ✅ Subscribed to OnPlayerFortSpawned event"); } else { fortManager.OnEnemyFortSpawned += OnFortSpawned; - Logging.Debug($"[FortHealthUI] Subscribed to ENEMY fort spawn"); + Logging.Debug($"[FortHealthUI] ✅ Subscribed to OnEnemyFortSpawned event"); } } private void OnFortSpawned(FortController fort) { + Logging.Debug($"[FortHealthUI] 🎯 OnFortSpawned event received! Fort: {fort?.FortName ?? "NULL"}"); + + if (fort == null) + { + Logging.Error($"[FortHealthUI] Fort is NULL in spawn callback!"); + return; + } + BindToFort(fort); } @@ -140,7 +172,7 @@ namespace Minigames.FortFight.UI UpdateDisplay(); - Logging.Debug($"[FortHealthUI] Bound to fort: {fort.FortName}"); + Logging.Debug($"[FortHealthUI] Bound to fort: {fort.FortName}. Event subscription successful."); } #endregion @@ -149,6 +181,7 @@ namespace Minigames.FortFight.UI private void OnFortDamaged(float damage, float hpPercentage) { + Logging.Debug($"[FortHealthUI] OnFortDamaged received! Damage: {damage}, HP%: {hpPercentage:F1}%, Fort: {trackedFort?.FortName}"); UpdateDisplay(); } @@ -158,20 +191,52 @@ namespace Minigames.FortFight.UI private void UpdateDisplay() { - if (trackedFort == null) return; + if (trackedFort == null) + { + Logging.Warning("[FortHealthUI] UpdateDisplay called but trackedFort is null!"); + return; + } float hpPercent = trackedFort.HpPercentage; + Logging.Debug($"[FortHealthUI] UpdateDisplay - Fort: {trackedFort.FortName}, HP: {hpPercent:F1}%"); + // Update slider if (hpSlider != null) { hpSlider.value = hpPercent / 100f; + Logging.Debug($"[FortHealthUI] Slider updated to {hpSlider.value:F2}"); + } + else + { + Logging.Warning("[FortHealthUI] hpSlider is null!"); } // Update text if (hpPercentageText != null) { hpPercentageText.text = $"{hpPercent:F0}%"; + Logging.Debug($"[FortHealthUI] Text updated to {hpPercentageText.text}"); + } + else + { + Logging.Warning("[FortHealthUI] hpPercentageText is null!"); + } + + // Update debug HP display (current/max) + if (debugHpText != null) + { + if (debugDisplay) + { + debugHpText.gameObject.SetActive(true); + float currentHp = trackedFort.CurrentHp; + float maxHp = trackedFort.MaxHp; + debugHpText.text = $"{currentHp:F0}/{maxHp:F0}"; + } + else + { + debugHpText.gameObject.SetActive(false); + } } // Update color based on HP diff --git a/Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs b/Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs new file mode 100644 index 00000000..2f4b3087 --- /dev/null +++ b/Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs @@ -0,0 +1,234 @@ +using Core; +using Core.Lifecycle; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace Minigames.FortFight.UI +{ + /// + /// Game Over UI - displays when a fort is defeated. + /// Shows match time, winner, and restart button. + /// + public class GameOverUI : ManagedBehaviour + { + #region Inspector Properties + + [Header("UI References")] + [Tooltip("Root GameObject to show/hide the entire UI")] + [SerializeField] private GameObject rootPanel; + + [Tooltip("Text showing elapsed time")] + [SerializeField] private TextMeshProUGUI elapsedTimeText; + + [Tooltip("Text showing winner")] + [SerializeField] private TextMeshProUGUI winnerText; + + [Tooltip("Restart button")] + [SerializeField] private Button restartButton; + + [Header("Optional Visuals")] + [Tooltip("Optional canvas group for fade-in")] + [SerializeField] private CanvasGroup canvasGroup; + + #endregion + + #region Lifecycle + + internal override void OnManagedAwake() + { + base.OnManagedAwake(); + + // Validate references + if (rootPanel == null) + { + Logging.Error("[GameOverUI] Root panel not assigned!"); + } + + if (elapsedTimeText == null) + { + Logging.Warning("[GameOverUI] Elapsed time text not assigned!"); + } + + if (winnerText == null) + { + Logging.Warning("[GameOverUI] Winner text not assigned!"); + } + + if (restartButton == null) + { + Logging.Error("[GameOverUI] Restart button not assigned!"); + } + + // Setup button listener + if (restartButton != null) + { + restartButton.onClick.AddListener(OnRestartClicked); + } + + // Ensure canvas group exists for fade + if (canvasGroup == null && rootPanel != null) + { + canvasGroup = rootPanel.GetComponent(); + } + + // Start hidden + Hide(); + } + + internal override void OnManagedDestroy() + { + base.OnManagedDestroy(); + + // Remove button listener + if (restartButton != null) + { + restartButton.onClick.RemoveListener(OnRestartClicked); + } + } + + #endregion + + #region Event Handlers + + private void OnRestartClicked() + { + Logging.Debug("[GameOverUI] Restart button clicked, reloading scene..."); + RestartGame(); + } + + #endregion + + #region Display + + /// + /// Show the game over UI with match results + /// Called by FortFightGameManager when game ends + /// + public void Show() + { + if (rootPanel != null) + { + rootPanel.SetActive(true); + } + + // Get game manager for elapsed time + var gameManager = Core.FortFightGameManager.Instance; + if (gameManager != null) + { + float elapsedTime = gameManager.ElapsedGameTime; + UpdateElapsedTime(elapsedTime); + + // Determine winner + DetermineWinner(); + } + + // Optional: Fade in + if (canvasGroup != null) + { + canvasGroup.alpha = 0f; + StartCoroutine(FadeIn()); + } + + Logging.Debug("[GameOverUI] Game over UI shown"); + } + + /// + /// Hide the game over UI + /// + public void Hide() + { + if (rootPanel != null) + { + rootPanel.SetActive(false); + } + } + + /// + /// Update the elapsed time display + /// + private void UpdateElapsedTime(float seconds) + { + if (elapsedTimeText == null) return; + + // Format as MM:SS + int minutes = Mathf.FloorToInt(seconds / 60f); + int secs = Mathf.FloorToInt(seconds % 60f); + + elapsedTimeText.text = $"{minutes:00}:{secs:00}"; + } + + /// + /// Determine and display the winner + /// + private void DetermineWinner() + { + if (winnerText == null) return; + + var fortManager = Core.FortManager.Instance; + if (fortManager == null) return; + + bool playerDefeated = fortManager.PlayerFort?.IsDefeated ?? false; + bool enemyDefeated = fortManager.EnemyFort?.IsDefeated ?? false; + + if (playerDefeated && enemyDefeated) + { + winnerText.text = "DRAW!"; + } + else if (playerDefeated) + { + winnerText.text = "PLAYER TWO WINS!"; + } + else if (enemyDefeated) + { + winnerText.text = "PLAYER ONE WINS!"; + } + else + { + winnerText.text = "GAME OVER"; + } + } + + /// + /// Fade in the UI over time + /// + private System.Collections.IEnumerator FadeIn() + { + float duration = 0.5f; + float elapsed = 0f; + + while (elapsed < duration) + { + elapsed += Time.deltaTime; + if (canvasGroup != null) + { + canvasGroup.alpha = Mathf.Lerp(0f, 1f, elapsed / duration); + } + yield return null; + } + + if (canvasGroup != null) + { + canvasGroup.alpha = 1f; + } + } + + #endregion + + #region Restart + + /// + /// Restart the game by reloading the current scene + /// + private void RestartGame() + { + // Use Unity's SceneManager to reload current scene + string currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; + Logging.Debug($"[GameOverUI] Reloading scene: {currentScene}"); + UnityEngine.SceneManagement.SceneManager.LoadScene(currentScene); + } + + #endregion + } +} + diff --git a/Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs.meta b/Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs.meta new file mode 100644 index 00000000..41c8b1a1 --- /dev/null +++ b/Assets/Scripts/Minigames/FortFight/UI/GameOverUI.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ffb13ad5109340eba06f9c02082ece94 +timeCreated: 1764806274 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/FortFight/UI/GameplayPage.cs b/Assets/Scripts/Minigames/FortFight/UI/GameplayPage.cs index aeda8978..d90b1855 100644 --- a/Assets/Scripts/Minigames/FortFight/UI/GameplayPage.cs +++ b/Assets/Scripts/Minigames/FortFight/UI/GameplayPage.cs @@ -1,6 +1,5 @@ using Core; using UnityEngine; -using UnityEngine.UI; using TMPro; using UI.Core; using Minigames.FortFight.Core; @@ -48,8 +47,8 @@ namespace Minigames.FortFight.UI { base.OnManagedStart(); - // Get turn manager reference - turnManager = FindFirstObjectByType(); + // Get turn manager reference via singleton + turnManager = TurnManager.Instance; if (turnManager != null) { diff --git a/Assets/Settings/FortFightSettings.asset b/Assets/Settings/FortFightSettings.asset index 11801f81..ea0d5962 100644 --- a/Assets/Settings/FortFightSettings.asset +++ b/Assets/Settings/FortFightSettings.asset @@ -35,7 +35,7 @@ MonoBehaviour: weakPointExplosionRadius: 5 weakPointExplosionDamage: 50 weakPointExplosionForce: 50 - fortDefeatThreshold: 0.3 + fortDefeatThreshold: 0 blockGravityScale: 2 projectileGravityScale: 1 projectileSettleDelay: 2.5 @@ -77,13 +77,17 @@ MonoBehaviour: description: damage: 20 mass: 5 - vacuumSlideForce: 15 + vacuumSlideSpeed: 10 vacuumDestroyBlockCount: 2 vacuumBlockDamage: 999 trashBagPieceCount: 5 trashBagPieceForce: 10 trashBagSpreadAngle: 60 + trashPieceDamage: 5 + trashPieceLifetime: 5 ceilingFanActivationDelay: 1 + ceilingFanDropDelay: 0.2 + ceilingFanDropSpeed: 20 baseLaunchForce: 150 minForceMultiplier: 0.1 maxForceMultiplier: 1