diff --git a/Assets/Prefabs/UI/Cards/CardSystem.prefab b/Assets/Prefabs/UI/Cards/CardSystem.prefab
index da638723..6059321a 100644
--- a/Assets/Prefabs/UI/Cards/CardSystem.prefab
+++ b/Assets/Prefabs/UI/Cards/CardSystem.prefab
@@ -299,7 +299,7 @@ GameObject:
m_Component:
- component: {fileID: 8855931927481658112}
- component: {fileID: 5244731468946939147}
- - component: {fileID: 2860077094930428643}
+ - component: {fileID: 7848685733999064403}
m_Layer: 5
m_Name: Backback
m_TagString: Untagged
@@ -372,7 +372,7 @@ MonoBehaviour:
m_OnClick:
m_PersistentCalls:
m_Calls: []
---- !u!114 &2860077094930428643
+--- !u!114 &7848685733999064403
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -381,9 +381,9 @@ MonoBehaviour:
m_GameObject: {fileID: 7564017895147059150}
m_Enabled: 1
m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: e7ea50a695c58944799b4f27a9014301, type: 3}
+ m_Script: {fileID: 11500000, guid: 494d0aedce9744308499355006071138, type: 3}
m_Name:
- m_EditorClassIdentifier: '::'
+ m_EditorClassIdentifier: AppleHillsScripts::UI.DummyInput
--- !u!1 &8561999612656273135
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/Prefabs/UI/Tutorial.prefab b/Assets/Prefabs/UI/Tutorial.prefab
index 7d60f71d..c395a637 100644
--- a/Assets/Prefabs/UI/Tutorial.prefab
+++ b/Assets/Prefabs/UI/Tutorial.prefab
@@ -75,6 +75,135 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
+--- !u!1 &1188952073410115051
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 4893439260580271593}
+ - component: {fileID: 2903185199836080833}
+ m_Layer: 0
+ m_Name: TutorialAudio
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &4893439260580271593
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1188952073410115051}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: -80.867836, y: 74.80073, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 3183207532655435649}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!82 &2903185199836080833
+AudioSource:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1188952073410115051}
+ m_Enabled: 1
+ serializedVersion: 4
+ OutputAudioMixerGroup: {fileID: 3533147658878909314, guid: 727a7e4b6df4b0d47897f7d8ee7fa323, type: 2}
+ m_audioClip: {fileID: 0}
+ m_Resource: {fileID: 8300000, guid: fca641cdc8dcd074483fad3db1cbe24c, type: 3}
+ 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 &1590200553513530823
GameObject:
m_ObjectHideFlags: 0
@@ -242,7 +371,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 1
+ m_IsActive: 0
--- !u!4 &1831065641766120066
Transform:
m_ObjectHideFlags: 0
@@ -263,7 +392,7 @@ Transform:
- {fileID: 8442487091540635686}
- {fileID: 8879908034887781514}
- {fileID: 2211814522314670326}
- m_Father: {fileID: 4592376486413311028}
+ m_Father: {fileID: 9007881587001685567}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!111 &1617577586792587006
Animation:
@@ -312,7 +441,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 0
+ m_IsActive: 1
--- !u!4 &4249054603034392046
Transform:
m_ObjectHideFlags: 0
@@ -330,7 +459,7 @@ Transform:
- {fileID: 3606233682966098341}
- {fileID: 9050619600904836405}
- {fileID: 4757850631734005462}
- m_Father: {fileID: 4592376486413311028}
+ m_Father: {fileID: 9007881587001685567}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!111 &6215866005480392352
Animation:
@@ -393,6 +522,7 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4592376486413311028}
+ - {fileID: 4893439260580271593}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &4267886887244421663
@@ -407,8 +537,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: c0f21d12fb6a50242b483dbdc3a6a1df, type: 3}
m_Name:
m_EditorClassIdentifier: '::'
- divingGameManager: {fileID: 0}
- playTutorial: 0
+ playTutorial: 1
+ tapPrompt: {fileID: 6751368003081662277}
--- !u!1 &3503751741805984614
GameObject:
m_ObjectHideFlags: 0
@@ -443,8 +573,8 @@ RectTransform:
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: 13.456177, y: -2.627655}
- m_SizeDelta: {x: 1204.5154, y: 802.1875}
+ m_AnchoredPosition: {x: 22.853088, y: -89.07968}
+ m_SizeDelta: {x: 1185.7214, y: 975.0914}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3845799704385814770
CanvasRenderer:
@@ -860,6 +990,43 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
+--- !u!1 &5541992152058962912
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 9007881587001685567}
+ m_Layer: 5
+ m_Name: TutorialScreens
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &9007881587001685567
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5541992152058962912}
+ 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: 4249054603034392046}
+ - {fileID: 1831065641766120066}
+ m_Father: {fileID: 4592376486413311028}
+ 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: 100, y: 100}
+ m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &6118149484066388440
GameObject:
m_ObjectHideFlags: 0
@@ -894,8 +1061,8 @@ RectTransform:
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: 13.456177, y: -2.627655}
- m_SizeDelta: {x: 1204.5154, y: 802.1875}
+ m_AnchoredPosition: {x: 22.853088, y: -89.07971}
+ m_SizeDelta: {x: 1185.721, y: 975.0914}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4855560808002867609
CanvasRenderer:
@@ -1010,6 +1177,142 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
+--- !u!1 &6751368003081662277
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 5554143010115146741}
+ - component: {fileID: 3254928157304415694}
+ - component: {fileID: 490204079952288596}
+ 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 &5554143010115146741
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6751368003081662277}
+ 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: 4592376486413311028}
+ 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.000015258789, y: -51.398}
+ m_SizeDelta: {x: 658.8605, y: 102.796875}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &3254928157304415694
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6751368003081662277}
+ m_CullTransparentMesh: 1
+--- !u!114 &490204079952288596
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6751368003081662277}
+ 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: TAP TO SKIP
+ 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: 75
+ m_fontSizeBase: 75
+ 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!1 &7059429923783536925
GameObject:
m_ObjectHideFlags: 0
@@ -1043,8 +1346,8 @@ RectTransform:
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- - {fileID: 4249054603034392046}
- - {fileID: 1831065641766120066}
+ - {fileID: 9007881587001685567}
+ - {fileID: 5554143010115146741}
m_Father: {fileID: 3183207532655435649}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@@ -1070,7 +1373,7 @@ Canvas:
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
- m_AdditionalShaderChannelsFlag: 0
+ m_AdditionalShaderChannelsFlag: 25
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
diff --git a/Assets/Scenes/MiniGames/DivingForPictures.unity b/Assets/Scenes/MiniGames/DivingForPictures.unity
index 9189303a..356154fc 100644
--- a/Assets/Scenes/MiniGames/DivingForPictures.unity
+++ b/Assets/Scenes/MiniGames/DivingForPictures.unity
@@ -342,16 +342,16 @@ LineRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_Positions:
- - {x: -0.15602553, y: 4.0749445, z: 0}
- - {x: -0.1566351, y: 3.9736378, z: 0}
- - {x: -0.1572447, y: 3.8729858, z: 0}
+ - {x: -0.15602553, y: 4.074945, z: 0}
+ - {x: -0.1566351, y: 3.973638, z: 0}
+ - {x: -0.1572447, y: 3.8729856, z: 0}
- {x: -0.15785426, y: 3.7729874, z: 0}
- - {x: -0.15846384, y: 3.6736438, z: 0}
- - {x: -0.15907341, y: 3.5749545, z: 0}
- - {x: -0.15968299, y: 3.4769197, z: 0}
- - {x: -0.16029257, y: 3.379539, z: 0}
- - {x: -0.16090216, y: 3.2828128, z: 0}
- - {x: -0.16151173, y: 3.186741, z: 0}
+ - {x: -0.15846384, y: 3.6736436, z: 0}
+ - {x: -0.15907341, y: 3.574954, z: 0}
+ - {x: -0.15968299, y: 3.4769192, z: 0}
+ - {x: -0.16029257, y: 3.3795385, z: 0}
+ - {x: -0.16090216, y: 3.2828126, z: 0}
+ - {x: -0.16151173, y: 3.1867409, z: 0}
- {x: -0.16212131, y: 3.0913236, z: 0}
m_Parameters:
serializedVersion: 3
@@ -1149,7 +1149,7 @@ Transform:
m_GameObject: {fileID: 747976396}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 3.1975174, z: 0}
+ m_LocalPosition: {x: 0, y: 3.197517, z: 0}
m_LocalScale: {x: 0.57574, y: 0.57574, z: 0.57574}
m_ConstrainProportionsScale: 0
m_Children:
@@ -1544,6 +1544,59 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &999630160 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 5541992152058962912, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ m_PrefabInstance: {fileID: 8347532583749285323}
+ m_PrefabAsset: {fileID: 0}
+--- !u!114 &999630162
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 999630160}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 9e0b24e2f2ad54cc09940c320ed3cf4b, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: PixelplacementAssembly::Pixelplacement.StateMachine
+ defaultState: {fileID: 1211973842}
+ currentState: {fileID: 0}
+ _unityEventsFolded: 0
+ verbose: 1
+ allowReentry: 0
+ returnToDefaultOnDisable: 1
+ OnStateExited:
+ m_PersistentCalls:
+ m_Calls: []
+ OnStateEntered:
+ m_PersistentCalls:
+ m_Calls: []
+ OnFirstStateEntered:
+ m_PersistentCalls:
+ m_Calls: []
+ OnFirstStateExited:
+ m_PersistentCalls:
+ m_Calls: []
+ OnLastStateEntered:
+ m_PersistentCalls:
+ m_Calls: []
+ OnLastStateExited:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!114 &999630163
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 999630160}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 55938fb1577dd4ad3af7e994048c86f6, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: PixelplacementAssembly::Pixelplacement.Initialization
--- !u!1 &1003335103
GameObject:
m_ObjectHideFlags: 0
@@ -1701,7 +1754,7 @@ LineRenderer:
m_SortingOrder: 0
m_Positions:
- {x: -0.15602553, y: 4.0749445, z: 0}
- - {x: -0.11662118, y: 3.8796222, z: 0}
+ - {x: -0.11662118, y: 3.879622, z: 0}
- {x: -0.07721684, y: 3.7057445, z: 0}
- {x: -0.03781248, y: 3.5533106, z: 0}
- {x: 0.0015918687, y: 3.4223216, z: 0}
@@ -1709,7 +1762,7 @@ LineRenderer:
- {x: 0.08040057, y: 3.2246761, z: 0}
- {x: 0.11980491, y: 3.15802, z: 0}
- {x: 0.15920927, y: 3.1128082, z: 0}
- - {x: 0.1986136, y: 3.0890408, z: 0}
+ - {x: 0.1986136, y: 3.0890405, z: 0}
- {x: 0.23801796, y: 3.0867176, z: 0}
m_Parameters:
serializedVersion: 3
@@ -1971,6 +2024,51 @@ MonoBehaviour:
m_VarianceClampScale: 0.9
m_ContrastAdaptiveSharpening: 0
m_Version: 2
+--- !u!1 &1173818904 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 6751368003081662277, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ m_PrefabInstance: {fileID: 8347532583749285323}
+ m_PrefabAsset: {fileID: 0}
+--- !u!114 &1173818908
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1173818904}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b75de64fb2fd4ff0b869bf469e2becea, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: AppleHillsScripts::UI.BlinkingCanvasGroup
+ minAlpha: 0
+ maxAlpha: 1
+ legDuration: 0.5
+ startDelay: 0
+ obeyTimescale: 0
+ easeCurve:
+ serializedVersion: 2
+ m_Curve: []
+ m_PreInfinity: 2
+ m_PostInfinity: 2
+ m_RotationOrder: 4
+--- !u!225 &1173818909
+CanvasGroup:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1173818904}
+ m_Enabled: 1
+ m_Alpha: 1
+ m_Interactable: 1
+ m_BlocksRaycasts: 1
+ m_IgnoreParentGroups: 0
+--- !u!1 &1211973842 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 2271162218602898139, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ m_PrefabInstance: {fileID: 8347532583749285323}
+ m_PrefabAsset: {fileID: 0}
--- !u!1 &1224833348
GameObject:
m_ObjectHideFlags: 0
@@ -2138,135 +2236,6 @@ Transform:
m_Children: []
m_Father: {fileID: 2106431002}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!1 &1363116017
-GameObject:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- serializedVersion: 6
- m_Component:
- - component: {fileID: 1363116018}
- - component: {fileID: 1363116019}
- m_Layer: 0
- m_Name: TutorialAudio
- m_TagString: Untagged
- m_Icon: {fileID: 0}
- m_NavMeshLayer: 0
- m_StaticEditorFlags: 0
- m_IsActive: 1
---- !u!4 &1363116018
-Transform:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1363116017}
- serializedVersion: 2
- m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
- m_LocalPosition: {x: -80.867836, y: 74.80073, z: 0}
- m_LocalScale: {x: 1, y: 1, z: 1}
- m_ConstrainProportionsScale: 0
- m_Children: []
- m_Father: {fileID: 1849171394}
- m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!82 &1363116019
-AudioSource:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1363116017}
- m_Enabled: 1
- serializedVersion: 4
- OutputAudioMixerGroup: {fileID: 3533147658878909314, guid: 727a7e4b6df4b0d47897f7d8ee7fa323, type: 2}
- m_audioClip: {fileID: 0}
- m_Resource: {fileID: 8300000, guid: fca641cdc8dcd074483fad3db1cbe24c, type: 3}
- 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 &1376741227
GameObject:
m_ObjectHideFlags: 0
@@ -2549,10 +2518,10 @@ LineRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_Positions:
- - {x: -0.15602553, y: 4.074945, z: 0}
- - {x: -0.18956745, y: 3.8764977, z: 0}
- - {x: -0.22310936, y: 3.7000234, z: 0}
- - {x: -0.25665125, y: 3.5455208, z: 0}
+ - {x: -0.15602553, y: 4.0749445, z: 0}
+ - {x: -0.18956745, y: 3.8764973, z: 0}
+ - {x: -0.22310936, y: 3.7000232, z: 0}
+ - {x: -0.25665125, y: 3.5455203, z: 0}
- {x: -0.29019317, y: 3.412991, z: 0}
- {x: -0.32373506, y: 3.3024335, z: 0}
- {x: -0.35727698, y: 3.2138484, z: 0}
@@ -2926,11 +2895,6 @@ SpriteRenderer:
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
---- !u!4 &1849171394 stripped
-Transform:
- m_CorrespondingSourceObject: {fileID: 3183207532655435649, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
- m_PrefabInstance: {fileID: 8347532583749285323}
- m_PrefabAsset: {fileID: 0}
--- !u!1 &1916796529
GameObject:
m_ObjectHideFlags: 0
@@ -3440,25 +3404,24 @@ PrefabInstance:
propertyPath: m_Name
value: Tutorial
objectReference: {fileID: 0}
- - target: {fileID: 3332446944854334578, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
- propertyPath: m_IsActive
- value: 1
- objectReference: {fileID: 0}
- - target: {fileID: 4267886887244421663, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
- propertyPath: playTutorial
- value: 1
- objectReference: {fileID: 0}
- - target: {fileID: 4267886887244421663, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
- propertyPath: divingGameManager
- value:
- objectReference: {fileID: 424805725}
- m_RemovedComponents: []
+ m_RemovedComponents:
+ - {fileID: 8086909437439386099, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ - {fileID: 2002496630232568573, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
m_RemovedGameObjects: []
- m_AddedGameObjects:
- - targetCorrespondingSourceObject: {fileID: 3183207532655435649, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ m_AddedGameObjects: []
+ m_AddedComponents:
+ - targetCorrespondingSourceObject: {fileID: 5541992152058962912, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
insertIndex: -1
- addedObject: {fileID: 1363116018}
- m_AddedComponents: []
+ addedObject: {fileID: 999630163}
+ - targetCorrespondingSourceObject: {fileID: 5541992152058962912, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ insertIndex: -1
+ addedObject: {fileID: 999630162}
+ - targetCorrespondingSourceObject: {fileID: 6751368003081662277, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ insertIndex: -1
+ addedObject: {fileID: 1173818909}
+ - targetCorrespondingSourceObject: {fileID: 6751368003081662277, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
+ insertIndex: -1
+ addedObject: {fileID: 1173818908}
m_SourcePrefab: {fileID: 100100000, guid: a4dd78ff48942854ebb4c65025a8dc36, type: 3}
--- !u!1660057539 &9223372036854775807
SceneRoots:
diff --git a/Assets/Scripts/Cinematics/CinematicsManager.cs b/Assets/Scripts/Cinematics/CinematicsManager.cs
index ad4b1c34..9bd85c00 100644
--- a/Assets/Scripts/Cinematics/CinematicsManager.cs
+++ b/Assets/Scripts/Cinematics/CinematicsManager.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using Bootstrap;
using Core;
@@ -7,7 +6,6 @@ using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.Playables;
-using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UI.Core;
diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs
index daf66e07..a81b7940 100644
--- a/Assets/Scripts/Core/GameManager.cs
+++ b/Assets/Scripts/Core/GameManager.cs
@@ -1,304 +1,261 @@
-using UnityEngine;
-using AppleHills.Core.Settings;
-using System;
+using System;
using System.Collections.Generic;
using AppleHills.Core.Interfaces;
-using Core;
-using UI;
+using AppleHills.Core.Settings;
using Bootstrap;
+using Input;
+using UnityEngine;
-///
-/// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
-///
-public class GameManager : MonoBehaviour
+namespace Core
{
- private static GameManager _instance;
- private static bool _isQuitting = false;
-
///
- /// Singleton instance of the GameManager. No longer creates an instance if one doesn't exist.
+ /// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
///
- public static GameManager Instance => _instance;
+ public class GameManager : MonoBehaviour
+ {
+ // Singleton implementation
+ private static GameManager _instance;
+ public static GameManager Instance => _instance;
- [Header("Settings Status")]
- [SerializeField] private bool _settingsLoaded = false;
- [SerializeField] private bool _developerSettingsLoaded = false;
- public bool SettingsLoaded => _settingsLoaded;
- public bool DeveloperSettingsLoaded => _developerSettingsLoaded;
+ private bool _settingsLoaded;
+ private bool _developerSettingsLoaded;
+
+ // Pausable implementation (counter-based)
+ private int _pauseCount;
+ public bool IsPaused => _pauseCount > 0;
- [Header("Game State")]
- [SerializeField] private bool _isPaused = false;
+ // List of pausable components that have registered with the GameManager
+ private List _pausableComponents = new List();
- ///
- /// Current pause state of the game
- ///
- public bool IsPaused => _isPaused;
-
- // List of pausable components that have registered with the GameManager
- private List _pausableComponents = new List();
-
- // Events for pause state changes
- public event Action OnGamePaused;
- public event Action OnGameResumed;
+ // Events for pause state changes
+ public event Action OnGamePaused;
+ public event Action OnGameResumed;
- void Awake()
- {
- _instance = this;
+ void Awake()
+ {
+ _instance = this;
- // Create settings provider if it doesn't exist
- SettingsProvider.Instance.gameObject.name = "Settings Provider";
+ // Create settings providers if it doesn't exist
+ SettingsProvider.Instance.gameObject.name = "Settings Provider";
+ DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider";
- // Create developer settings provider if it doesn't exist
- DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider";
+ // Load all settings synchronously during Awake
+ InitializeSettings();
+ InitializeDeveloperSettings();
- // Load all settings synchronously during Awake
- InitializeSettings();
- InitializeDeveloperSettings();
+ // Register for post-boot initialization
+ BootCompletionService.RegisterInitAction(InitializePostBoot);
- // Register for post-boot initialization
- BootCompletionService.RegisterInitAction(InitializePostBoot);
-
- // DontDestroyOnLoad(gameObject);
- }
+ // DontDestroyOnLoad(gameObject);
+ }
- private void InitializePostBoot()
- {
- // Find and subscribe to PauseMenu events
- PauseMenu pauseMenu = PauseMenu.Instance;
- if (pauseMenu != null)
+ private void InitializePostBoot()
{
- pauseMenu.OnGamePaused += OnPauseMenuPaused;
- pauseMenu.OnGameResumed += OnPauseMenuResumed;
-
- Logging.Debug("[GameManager] Subscribed to PauseMenu events");
+ // For post-boot correct initialization order
}
- else
- {
- Logging.Warning("[GameManager] PauseMenu not found. Pause functionality won't work properly.");
- }
- }
-
- private void OnDestroy()
- {
- // Unsubscribe from PauseMenu events
- PauseMenu pauseMenu = FindFirstObjectByType();
- if (pauseMenu != null)
- {
- pauseMenu.OnGamePaused -= OnPauseMenuPaused;
- pauseMenu.OnGameResumed -= OnPauseMenuResumed;
- }
- }
- ///
- /// Register a component as pausable, so it receives pause/resume notifications
- ///
- /// The pausable component to register
- public void RegisterPausableComponent(IPausable component)
- {
- if (component != null && !_pausableComponents.Contains(component))
+ ///
+ /// Register a component as pausable, so it receives pause/resume notifications
+ ///
+ /// The pausable component to register
+ public void RegisterPausableComponent(IPausable component)
{
- _pausableComponents.Add(component);
-
- // If the game is already paused, pause the component immediately
- if (_isPaused)
+ if (component != null && !_pausableComponents.Contains(component))
{
- component.Pause();
+ _pausableComponents.Add(component);
+
+ // If the game is already paused, pause the component immediately
+ if (IsPaused)
+ {
+ component.Pause();
+ }
+
+ Logging.Debug($"[GameManager] Registered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
+ }
+ }
+
+ ///
+ /// Unregister a pausable component
+ ///
+ /// The pausable component to unregister
+ public void UnregisterPausableComponent(IPausable component)
+ {
+ if (component != null && _pausableComponents.Contains(component))
+ {
+ _pausableComponents.Remove(component);
+ Logging.Debug($"[GameManager] Unregistered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
+ }
+ }
+
+ ///
+ /// Request a pause. Multiple systems can request pause; the game only resumes when all requests are released.
+ ///
+ /// Optional object requesting the pause (for logging)
+ public void RequestPause(object requester = null)
+ {
+ _pauseCount++;
+ if (_pauseCount == 1)
+ {
+ ApplyPause(true);
+ }
+
+ Logging.Debug($"[GameManager] Pause requested by {requester?.ToString() ?? "Unknown"}. pauseCount = {_pauseCount}");
+ }
+
+ ///
+ /// Release a previously requested pause. If this brings the pause count to zero the game resumes.
+ ///
+ /// Optional object releasing the pause (for logging)
+ public void ReleasePause(object requester = null)
+ {
+ _pauseCount = Mathf.Max(0, _pauseCount - 1);
+ if (_pauseCount == 0)
+ {
+ ApplyPause(false);
+ }
+
+ Logging.Debug($"[GameManager] Pause released by {requester?.ToString() ?? "Unknown"}. pauseCount = {_pauseCount}");
+ }
+
+ ///
+ /// Apply pause/resume state to registered components and global systems.
+ ///
+ /// True to pause; false to resume
+ private void ApplyPause(bool shouldPause)
+ {
+ // TODO: Do we want to stop time?
+ // Time.timeScale = shouldPause ? 0f : 1f;
+
+ // Notify registered components
+ foreach (var component in _pausableComponents)
+ {
+ if (shouldPause)
+ component.Pause();
+ else
+ component.DoResume();
+ }
+
+ // Fire events
+ if (shouldPause)
+ {
+ // TODO: Stop input here?
+ InputManager.Instance.SetInputMode(InputMode.UI);
+ OnGamePaused?.Invoke();
+ }
+ else
+ {
+ // TODO: Release input here?
+ InputManager.Instance.SetInputMode(InputMode.GameAndUI);
+ OnGameResumed?.Invoke();
}
- Logging.Debug($"[GameManager] Registered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
+ Logging.Debug($"[GameManager] Game {(shouldPause ? "paused" : "resumed")}. Paused {_pausableComponents.Count} components.");
}
- }
-
- ///
- /// Unregister a pausable component
- ///
- /// The pausable component to unregister
- public void UnregisterPausableComponent(IPausable component)
- {
- if (component != null && _pausableComponents.Contains(component))
- {
- _pausableComponents.Remove(component);
- Logging.Debug($"[GameManager] Unregistered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
- }
- }
-
- ///
- /// Called when the PauseMenu broadcasts a pause event
- ///
- private void OnPauseMenuPaused()
- {
- PauseGame();
- }
-
- ///
- /// Called when the PauseMenu broadcasts a resume event
- ///
- private void OnPauseMenuResumed()
- {
- ResumeGame();
- }
-
- ///
- /// Pause the game and notify all registered pausable components
- ///
- public void PauseGame()
- {
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
-
- // Pause all registered components
- foreach (var component in _pausableComponents)
- {
- component.Pause();
- }
-
- // Broadcast pause event
- OnGamePaused?.Invoke();
-
- Logging.Debug($"[GameManager] Game paused. Paused {_pausableComponents.Count} components.");
- }
-
- ///
- /// Resume the game and notify all registered pausable components
- ///
- public void ResumeGame()
- {
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
-
- // Resume all registered components
- foreach (var component in _pausableComponents)
- {
- component.DoResume();
- }
-
- // Broadcast resume event
- OnGameResumed?.Invoke();
-
- Logging.Debug($"[GameManager] Game resumed. Resumed {_pausableComponents.Count} components.");
- }
-
- ///
- /// Toggle the pause state of the game
- ///
- public void TogglePause()
- {
- if (_isPaused)
- ResumeGame();
- else
- PauseGame();
- }
- private void InitializeSettings()
- {
- Logging.Debug("Starting settings initialization...");
-
- // Load settings synchronously
- var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous();
- var interactionSettings = SettingsProvider.Instance.LoadSettingsSynchronous();
- var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous();
-
- // Register settings with service locator
- if (playerSettings != null)
+ private void InitializeSettings()
{
- ServiceLocator.Register(playerSettings);
- Logging.Debug("PlayerFollowerSettings registered successfully");
- }
- else
- {
- Debug.LogError("Failed to load PlayerFollowerSettings");
- }
+ Logging.Debug("Starting settings initialization...");
+
+ // Load settings synchronously
+ var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous();
+ var interactionSettings = SettingsProvider.Instance.LoadSettingsSynchronous();
+ var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous();
+
+ // Register settings with service locator
+ if (playerSettings != null)
+ {
+ ServiceLocator.Register(playerSettings);
+ Logging.Debug("PlayerFollowerSettings registered successfully");
+ }
+ else
+ {
+ Debug.LogError("Failed to load PlayerFollowerSettings");
+ }
- if (interactionSettings != null)
- {
- ServiceLocator.Register(interactionSettings);
- Logging.Debug("InteractionSettings registered successfully");
- }
- else
- {
- Debug.LogError("Failed to load InteractionSettings");
- }
+ if (interactionSettings != null)
+ {
+ ServiceLocator.Register(interactionSettings);
+ Logging.Debug("InteractionSettings registered successfully");
+ }
+ else
+ {
+ Debug.LogError("Failed to load InteractionSettings");
+ }
- if (minigameSettings != null)
- {
- ServiceLocator.Register(minigameSettings);
- Logging.Debug("MinigameSettings registered successfully");
- }
- else
- {
- Debug.LogError("Failed to load MinigameSettings");
+ if (minigameSettings != null)
+ {
+ ServiceLocator.Register(minigameSettings);
+ Logging.Debug("MinigameSettings registered successfully");
+ }
+ else
+ {
+ Debug.LogError("Failed to load MinigameSettings");
+ }
+
+ // Log success
+ _settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null;
+ if (_settingsLoaded)
+ {
+ Logging.Debug("All settings loaded and registered with ServiceLocator");
+ }
+ else
+ {
+ Logging.Warning("Some settings failed to load - check that all settings assets exist and are marked as Addressables");
+ }
}
- // Log success
- _settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null;
- if (_settingsLoaded)
+ ///
+ /// Check for and initialize developer settings.
+ ///
+ private void InitializeDeveloperSettings()
{
- Logging.Debug("All settings loaded and registered with ServiceLocator");
- }
- else
- {
- Logging.Warning("Some settings failed to load - check that all settings assets exist and are marked as Addressables");
- }
- }
-
- ///
- /// Check for and initialize developer settings.
- ///
- private void InitializeDeveloperSettings()
- {
- Logging.Debug("Starting developer settings initialization...");
+ Logging.Debug("Starting developer settings initialization...");
- // Load developer settings
- var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings();
+ // Load developer settings
+ var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings();
- _developerSettingsLoaded = divingDevSettings != null;
+ _developerSettingsLoaded = divingDevSettings != null;
- if (_developerSettingsLoaded)
- {
- Logging.Debug("All developer settings loaded successfully");
+ if (_developerSettingsLoaded)
+ {
+ Logging.Debug("All developer settings loaded successfully");
+ }
+ else
+ {
+ Logging.Warning("Some developer settings failed to load");
+ }
}
- else
+
+
+ // Helper method to get settings
+ private T GetSettings() where T : class
{
- Logging.Warning("Some developer settings failed to load");
+ return ServiceLocator.Get();
}
- }
- void OnApplicationQuit()
- {
- _isQuitting = true;
- ServiceLocator.Clear();
- }
-
- // Helper method to get settings
- private T GetSettings() where T : class
- {
- return ServiceLocator.Get();
- }
-
- ///
- /// Returns the entire settings object of specified type.
- ///
- /// Type of settings to retrieve
- /// The settings object or null if not found
- public static T GetSettingsObject() where T : class
- {
- return Instance?.GetSettings();
- }
+ ///
+ /// Returns the entire settings object of specified type.
+ ///
+ /// Type of settings to retrieve
+ /// The settings object or null if not found
+ public static T GetSettingsObject() where T : class
+ {
+ return Instance?.GetSettings();
+ }
- ///
- /// Returns the developer settings object of specified type.
- ///
- /// Type of developer settings to retrieve
- /// The developer settings object or null if not found
- public static T GetDeveloperSettings() where T : BaseDeveloperSettings
- {
- return DeveloperSettingsProvider.Instance?.GetSettings();
- }
+ ///
+ /// Returns the developer settings object of specified type.
+ ///
+ /// Type of developer settings to retrieve
+ /// The developer settings object or null if not found
+ public static T GetDeveloperSettings() where T : BaseDeveloperSettings
+ {
+ return DeveloperSettingsProvider.Instance?.GetSettings();
+ }
- // LEFTOVER LEGACY SETTINGS
- public float PlayerStopDistance => GetSettings()?.PlayerStopDistance ?? 6.0f;
- public float PlayerStopDistanceDirectInteraction => GetSettings()?.PlayerStopDistanceDirectInteraction ?? 2.0f;
- public float DefaultPuzzlePromptRange => GetSettings()?.DefaultPuzzlePromptRange ?? 3.0f;
+ // LEFTOVER LEGACY SETTINGS
+ public float PlayerStopDistance => GetSettings()?.PlayerStopDistance ?? 6.0f;
+ public float PlayerStopDistanceDirectInteraction => GetSettings()?.PlayerStopDistanceDirectInteraction ?? 2.0f;
+ public float DefaultPuzzlePromptRange => GetSettings()?.DefaultPuzzlePromptRange ?? 3.0f;
+ }
}
diff --git a/Assets/Scripts/Core/Interfaces/IPausable.cs b/Assets/Scripts/Core/Interfaces/IPausable.cs
index 9347e157..90eec549 100644
--- a/Assets/Scripts/Core/Interfaces/IPausable.cs
+++ b/Assets/Scripts/Core/Interfaces/IPausable.cs
@@ -16,10 +16,5 @@ namespace AppleHills.Core.Interfaces
/// Resumes the component's functionality
///
void DoResume();
-
- ///
- /// Gets whether the component is currently paused
- ///
- bool IsPaused { get; }
}
}
diff --git a/Assets/Scripts/Core/SettingsAccess.cs b/Assets/Scripts/Core/SettingsAccess.cs
index 502ecb9b..f5d12c18 100644
--- a/Assets/Scripts/Core/SettingsAccess.cs
+++ b/Assets/Scripts/Core/SettingsAccess.cs
@@ -1,4 +1,5 @@
-using UnityEngine;
+using Core;
+using UnityEngine;
namespace AppleHills
{
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs
index a54d911e..1a32f241 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/Bubble.cs
@@ -29,12 +29,6 @@ namespace Minigames.DivingForPictures
private Coroutine _wobbleCoroutine;
private Coroutine _offScreenCheckCoroutine;
- // Pause state tracking
- private bool _isPaused = false;
-
- // IPausable implementation
- public bool IsPaused => _isPaused;
-
void Awake()
{
// Cache references and randomize time offset for wobble
@@ -67,9 +61,6 @@ namespace Minigames.DivingForPictures
///
public void Pause()
{
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
StopBubbleBehavior();
// Debug log for troubleshooting
@@ -81,9 +72,6 @@ namespace Minigames.DivingForPictures
///
public void DoResume()
{
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
StartBubbleBehavior();
// Debug log for troubleshooting
@@ -95,7 +83,7 @@ namespace Minigames.DivingForPictures
///
private void StartBubbleBehavior()
{
- if (_isPaused || !isActiveAndEnabled) return; // Don't start if paused
+ if (GameManager.Instance.IsPaused || !isActiveAndEnabled) return; // Don't start if paused
_movementCoroutine = StartCoroutine(MovementCoroutine());
_wobbleCoroutine = StartCoroutine(WobbleCoroutine());
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs
index 4f485b20..8d2b42c1 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs
@@ -25,15 +25,9 @@ namespace Minigames.DivingForPictures
private UnityEngine.Camera _mainCamera; // Cache camera reference
private bool _isSurfacing = false;
- // Pause state
- private bool _isPaused = false;
-
// Coroutines for pause/resume
private Coroutine _spawnCoroutine;
- // IPausable implementation
- public bool IsPaused => _isPaused;
-
void Awake()
{
_mainCamera = UnityEngine.Camera.main;
@@ -87,10 +81,6 @@ namespace Minigames.DivingForPictures
///
public void Pause()
{
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
-
// Stop spawning coroutine
if (_spawnCoroutine != null)
{
@@ -116,10 +106,6 @@ namespace Minigames.DivingForPictures
///
public void DoResume()
{
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
-
// Restart spawning coroutine
StartSpawningCoroutine();
@@ -141,7 +127,7 @@ namespace Minigames.DivingForPictures
///
private void StartSpawningCoroutine()
{
- if (_spawnCoroutine == null && !_isPaused)
+ if (_spawnCoroutine == null && !GameManager.Instance.IsPaused)
{
_spawnCoroutine = StartCoroutine(SpawnBubblesRoutine());
}
@@ -219,7 +205,7 @@ namespace Minigames.DivingForPictures
bubble.SetWobbleScaleLimits(_devSettings.BubbleWobbleMinScale, _devSettings.BubbleWobbleMaxScale);
// If the game is already paused, pause this bubble immediately
- if (_isPaused)
+ if (GameManager.Instance.IsPaused)
{
bubble.Pause();
}
@@ -262,7 +248,7 @@ namespace Minigames.DivingForPictures
{
Logging.Debug("[BubbleSpawner] Started bubble spawning coroutine");
- while (enabled && gameObject.activeInHierarchy && !_isPaused)
+ while (enabled && gameObject.activeInHierarchy && !GameManager.Instance.IsPaused)
{
SpawnBubble();
SetNextSpawnInterval(); // Set interval for next spawn
diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs
index ce4e31da..01c2fcfa 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs
@@ -7,8 +7,9 @@ using Minigames.DivingForPictures.PictureCamera;
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq;
+using Bootstrap;
using UI;
+using UI.Core;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;
@@ -38,24 +39,24 @@ namespace Minigames.DivingForPictures
public CameraViewfinderManager viewfinderManager;
// Settings reference
- private IDivingMinigameSettings settings;
+ private IDivingMinigameSettings _settings;
// Private state variables
- private int playerScore = 0;
- private float currentSpawnProbability;
- private float lastSpawnTime = -100f;
- private float timeSinceLastSpawn = 0f;
- private List activeMonsters = new List();
+ private int _playerScore = 0;
+ private float _currentSpawnProbability;
+ private float _lastSpawnTime = -100f;
+ private float _timeSinceLastSpawn = 0f;
+ private List _activeMonsters = new List();
// Velocity management
// Velocity state tracking
- private float currentVelocityFactor = 1.0f; // 1.0 = normal descent speed, -1.0 * surfacingSpeedFactor = full surfacing speed
- private Coroutine velocityTransitionCoroutine;
- private Coroutine surfacingSequenceCoroutine;
+ private float _currentVelocityFactor = 1.0f; // 1.0 = normal descent speed, -1.0 * surfacingSpeedFactor = full surfacing speed
+ private Coroutine _velocityTransitionCoroutine;
+ private Coroutine _surfacingSequenceCoroutine;
// Public properties
- public int PlayerScore => playerScore;
- public float CurrentVelocityFactor => currentVelocityFactor;
+ public int PlayerScore => _playerScore;
+ public float CurrentVelocityFactor => _currentVelocityFactor;
// Events
public event Action OnScoreChanged;
@@ -67,8 +68,8 @@ namespace Minigames.DivingForPictures
public event Action OnVelocityFactorChanged;
// Private state variables for rope system
- private int currentRopeIndex = 0;
- private bool isGameOver = false;
+ private int _currentRopeIndex = 0;
+ private bool _isGameOver = false;
private bool _isSurfacing = false;
// Initialization state
@@ -77,23 +78,17 @@ namespace Minigames.DivingForPictures
// Used to track if we're currently surfacing
public bool IsSurfacing => _isSurfacing;
- // Event for game components to subscribe to
+ // TODO: Get rid of this in favor of proper game pausing?
public event Action OnGameInitialized;
- // Pause state
- private bool _isPaused = false;
// List of pausable components controlled by this manager
private List _pausableComponents = new List();
-
- // IPausable implementation
- public bool IsPaused => _isPaused;
// Photo sequence state
private bool _isPhotoSequenceActive = false;
private Monster _currentPhotoTarget = null;
- private Dictionary _pauseStateBackup = new Dictionary();
- private float _capturedProximity = 0f; // New: tracks how close to target the photo was taken (0-1)
+ private float _capturedProximity = 0f;
// List of components to exempt from pausing during photo sequence
private List _exemptFromPhotoSequencePausing = new List();
@@ -101,7 +96,6 @@ namespace Minigames.DivingForPictures
// Photo sequence events
public event Action OnPhotoSequenceStarted;
public event Action OnPhotoSequenceCompleted; // Now includes proximity score
- public event Action OnPhotoSequenceProgressUpdated;
private static DivingGameManager _instance = null;
private static bool _isQuitting = false;
@@ -113,8 +107,8 @@ namespace Minigames.DivingForPictures
private void Awake()
{
- settings = GameManager.GetSettingsObject();
- currentSpawnProbability = settings?.BaseSpawnProbability ?? 0.2f;
+ _settings = GameManager.GetSettingsObject();
+ _currentSpawnProbability = _settings?.BaseSpawnProbability ?? 0.2f;
if (_instance == null)
{
@@ -124,6 +118,9 @@ namespace Minigames.DivingForPictures
{
Destroy(gameObject);
}
+
+ // Ensure any previous run state is reset when this manager awakes
+ _isGameOver = false;
}
private void OnApplicationQuit()
@@ -133,44 +130,8 @@ namespace Minigames.DivingForPictures
private void Start()
{
- // Find PauseMenu and subscribe to its events
- PauseMenu pauseMenu = PauseMenu.Instance;
- if (pauseMenu != null)
- {
- pauseMenu.OnGamePaused += Pause;
- pauseMenu.OnGameResumed += DoResume;
-
- Logging.Debug("[DivingGameManager] Subscribed to PauseMenu events");
- }
- else
- {
- Logging.Warning("[DivingGameManager] PauseMenu not found. Pause functionality won't work properly.");
- }
-
- // Register this manager with the global GameManager
- if (GameManager.Instance != null)
- {
- GameManager.Instance.RegisterPausableComponent(this);
- }
-
- // Subscribe to SceneOrientationEnforcer's event
- if (SceneOrientationEnforcer.Instance != null)
- {
- SceneOrientationEnforcer.Instance.OnOrientationCorrect += InitializeGame;
- SceneOrientationEnforcer.Instance.OnOrientationIncorrect += Pause;
-
- // If orientation is already correct, initialize right away
- // This prevents issues if the orientation was already correct before subscription
- if (SceneOrientationEnforcer.Instance.IsOrientationCorrect())
- {
- InitializeGame();
- }
- }
- else
- {
- Logging.Warning("[DivingGameManager] SceneOrientationEnforcer not found. Initializing game immediately.");
- InitializeGame();
- }
+ // Register for post-boot initialization
+ BootCompletionService.RegisterInitAction(InitializePostBoot);
// Subscribe to player damage events (this doesn't depend on initialization)
PlayerCollisionBehavior.OnDamageTaken += OnPlayerDamageTaken;
@@ -189,6 +150,7 @@ namespace Minigames.DivingForPictures
viewfinderManager.OnViewfinderTappedDuringAnimation += OnViewfinderTappedDuringAnimation;
viewfinderManager.OnReverseAnimationStarted += OnReverseAnimationStarted;
+ // TODO: Give this a second look and make sure this is correct
// Add the viewfinder manager to exempt list to ensure it keeps working during photo sequences
if (viewfinderManager is IPausable viewfinderPausable)
{
@@ -197,6 +159,36 @@ namespace Minigames.DivingForPictures
}
OnMonsterSpawned += DoMonsterSpawned;
+ }
+
+ private void InitializePostBoot()
+ {
+ // Register this manager with the global GameManager
+ if (GameManager.Instance != null)
+ {
+ GameManager.Instance.RegisterPausableComponent(this);
+ }
+
+ // Subscribe to SceneOrientationEnforcer's event
+ if (SceneOrientationEnforcer.Instance != null)
+ {
+ // TODO: This is a bit of a hack to make sure the game is initialized after the orientation is correct
+ SceneOrientationEnforcer.Instance.OnOrientationCorrect += InitializeGame;
+ SceneOrientationEnforcer.Instance.OnOrientationIncorrect += Pause;
+
+ // If orientation is already correct, initialize right away
+ // This prevents issues if the orientation was already correct before subscription
+ if (SceneOrientationEnforcer.Instance.IsOrientationCorrect())
+ {
+ InitializeGame();
+ }
+ }
+ else
+ {
+ Logging.Warning("[DivingGameManager] SceneOrientationEnforcer not found. Initializing game immediately.");
+ InitializeGame();
+ }
+
CinematicsManager.Instance.OnCinematicStopped += EndGame;
}
@@ -211,14 +203,6 @@ namespace Minigames.DivingForPictures
SceneOrientationEnforcer.Instance.OnOrientationIncorrect -= Pause;
}
- // Unsubscribe from PauseMenu events
- PauseMenu pauseMenu = PauseMenu.Instance;
- if (pauseMenu != null)
- {
- pauseMenu.OnGamePaused -= Pause;
- pauseMenu.OnGameResumed -= DoResume;
- }
-
// Unregister from GameManager
if (GameManager.Instance != null)
{
@@ -241,19 +225,19 @@ namespace Minigames.DivingForPictures
private void Update()
{
- timeSinceLastSpawn += Time.deltaTime;
+ _timeSinceLastSpawn += Time.deltaTime;
// Gradually increase spawn probability over time
- float previousProbability = currentSpawnProbability;
- if (currentSpawnProbability < settings.MaxSpawnProbability)
+ float previousProbability = _currentSpawnProbability;
+ if (_currentSpawnProbability < _settings.MaxSpawnProbability)
{
- currentSpawnProbability += settings.ProbabilityIncreaseRate * Time.deltaTime;
- currentSpawnProbability = Mathf.Min(currentSpawnProbability, settings.MaxSpawnProbability);
+ _currentSpawnProbability += _settings.ProbabilityIncreaseRate * Time.deltaTime;
+ _currentSpawnProbability = Mathf.Min(_currentSpawnProbability, _settings.MaxSpawnProbability);
// Only fire event if probability changed significantly
- if (Mathf.Abs(currentSpawnProbability - previousProbability) > 0.01f)
+ if (Mathf.Abs(_currentSpawnProbability - previousProbability) > 0.01f)
{
- OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability);
+ OnSpawnProbabilityChanged?.Invoke(_currentSpawnProbability);
}
}
}
@@ -268,14 +252,14 @@ namespace Minigames.DivingForPictures
// If we're surfacing, don't spawn new monsters
if (_isSurfacing) return;
- bool forceSpawn = timeSinceLastSpawn >= settings.GuaranteedSpawnTime;
- bool onCooldown = timeSinceLastSpawn < settings.SpawnCooldown;
+ bool forceSpawn = _timeSinceLastSpawn >= _settings.GuaranteedSpawnTime;
+ bool onCooldown = _timeSinceLastSpawn < _settings.SpawnCooldown;
// Don't spawn if on cooldown, unless forced
if (onCooldown && !forceSpawn) return;
// Check probability or forced spawn
- if (forceSpawn || UnityEngine.Random.value <= currentSpawnProbability)
+ if (forceSpawn || UnityEngine.Random.value <= _currentSpawnProbability)
{
// Pick a random spawn point from this tile
MonsterSpawnPoint spawnPoint = spawnPoints[UnityEngine.Random.Range(0, spawnPoints.Length)];
@@ -284,10 +268,10 @@ namespace Minigames.DivingForPictures
SpawnMonster(spawnPoint.transform);
// Reset timer and adjust probability
- lastSpawnTime = Time.time;
- timeSinceLastSpawn = 0f;
- currentSpawnProbability = settings.BaseSpawnProbability;
- OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability);
+ _lastSpawnTime = Time.time;
+ _timeSinceLastSpawn = 0f;
+ _currentSpawnProbability = _settings.BaseSpawnProbability;
+ OnSpawnProbabilityChanged?.Invoke(_currentSpawnProbability);
}
}
@@ -335,14 +319,14 @@ namespace Minigames.DivingForPictures
private void DoPictureTaken(Monster monster)
{
// Calculate points based on depth
- int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * settings.DepthMultiplier);
- int pointsAwarded = settings.BasePoints + depthBonus;
+ int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.DepthMultiplier);
+ int pointsAwarded = _settings.BasePoints + depthBonus;
// Add score
- playerScore += pointsAwarded;
+ _playerScore += pointsAwarded;
// Fire events
- OnScoreChanged?.Invoke(playerScore);
+ OnScoreChanged?.Invoke(_playerScore);
OnPictureTaken?.Invoke(monster, pointsAwarded);
}
@@ -351,13 +335,13 @@ namespace Minigames.DivingForPictures
///
private void OnPlayerDamageTaken()
{
- if (isGameOver) return;
+ if (_isGameOver) return;
// Break the next rope in sequence
BreakNextRope();
// Check if all ropes are broken
- if (currentRopeIndex >= playerRopes.Length)
+ if (_currentRopeIndex >= playerRopes.Length)
{
TriggerGameOver();
deathAudioPlayer.Play();
@@ -365,7 +349,7 @@ namespace Minigames.DivingForPictures
else
{
// Notify listeners about rope break and remaining ropes
- int remainingRopes = playerRopes.Length - currentRopeIndex;
+ int remainingRopes = playerRopes.Length - _currentRopeIndex;
OnRopeBroken?.Invoke(remainingRopes);
Logging.Debug($"[DivingGameManager] Rope broken! {remainingRopes} ropes remaining.");
@@ -377,9 +361,9 @@ namespace Minigames.DivingForPictures
///
private void BreakNextRope()
{
- if (currentRopeIndex < playerRopes.Length)
+ if (_currentRopeIndex < playerRopes.Length)
{
- RopeBreaker ropeToBreak = playerRopes[currentRopeIndex];
+ RopeBreaker ropeToBreak = playerRopes[_currentRopeIndex];
if (ropeToBreak != null)
{
@@ -388,11 +372,11 @@ namespace Minigames.DivingForPictures
}
else
{
- Logging.Warning($"[DivingGameManager] Rope at index {currentRopeIndex} is null!");
+ Logging.Warning($"[DivingGameManager] Rope at index {_currentRopeIndex} is null!");
}
// Move to the next rope regardless if current was null
- currentRopeIndex++;
+ _currentRopeIndex++;
}
}
@@ -401,7 +385,7 @@ namespace Minigames.DivingForPictures
///
public void ForceBreakRope()
{
- if (!isGameOver)
+ if (!_isGameOver)
{
OnPlayerDamageTaken();
}
@@ -412,9 +396,9 @@ namespace Minigames.DivingForPictures
///
private void TriggerGameOver()
{
- if (isGameOver) return;
+ if (_isGameOver) return;
- isGameOver = true;
+ _isGameOver = true;
Logging.Debug("[DivingGameManager] Game Over! All ropes broken. Starting surfacing sequence...");
// Fire game over event
@@ -450,8 +434,8 @@ namespace Minigames.DivingForPictures
public void ResetRopeSystem()
{
// Reset rope state
- currentRopeIndex = 0;
- isGameOver = false;
+ _currentRopeIndex = 0;
+ _isGameOver = false;
// Restore all broken ropes
if (playerRopes != null)
@@ -477,8 +461,11 @@ namespace Minigames.DivingForPictures
_isSurfacing = true;
+ // TODO: Call it here?
+ UIPageController.Instance.HideAllUI();
+
// 1. Initiate smooth velocity transition to surfacing speed
- float targetVelocityFactor = -1.0f * settings.SurfacingSpeedFactor;
+ float targetVelocityFactor = -1.0f * _settings.SurfacingSpeedFactor;
SetVelocityFactor(targetVelocityFactor);
// 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic)
@@ -497,7 +484,7 @@ namespace Minigames.DivingForPictures
tileSpawner.StartSurfacing();
// Immediately send current velocity factor
- tileSpawner.OnVelocityFactorChanged(currentVelocityFactor);
+ tileSpawner.OnVelocityFactorChanged(_currentVelocityFactor);
}
// Handle the Rock object - disable components and animate it falling offscreen
@@ -565,15 +552,15 @@ namespace Minigames.DivingForPictures
obstacleSpawner.StartSurfacing();
// Immediately send current velocity factor
- obstacleSpawner.OnVelocityFactorChanged(currentVelocityFactor);
+ obstacleSpawner.OnVelocityFactorChanged(_currentVelocityFactor);
}
// Start the surfacing sequence coroutine
- if (surfacingSequenceCoroutine != null)
+ if (_surfacingSequenceCoroutine != null)
{
- StopCoroutine(surfacingSequenceCoroutine);
+ StopCoroutine(_surfacingSequenceCoroutine);
}
- surfacingSequenceCoroutine = StartCoroutine(SurfacingSequence());
+ _surfacingSequenceCoroutine = StartCoroutine(SurfacingSequence());
Logging.Debug($"[DivingGameManager] Started surfacing with target velocity factor: {targetVelocityFactor}");
}
@@ -649,7 +636,7 @@ namespace Minigames.DivingForPictures
private IEnumerator SurfacingSequence()
{
// Wait for the configured delay
- yield return new WaitForSeconds(settings.SurfacingSpawnDelay);
+ yield return new WaitForSeconds(_settings.SurfacingSpawnDelay);
// Find tile spawner and tell it to stop spawning
TrenchTileSpawner tileSpawner = FindFirstObjectByType();
@@ -686,7 +673,6 @@ namespace Minigames.DivingForPictures
// Call this when the game ends
public void EndGame()
{
- // TODO: Investigate why called twice
CinematicsManager.Instance.OnCinematicStopped -= EndGame;
// Start the end game sequence that grants a booster, waits for the UI animation, then shows Game Over.
StartCoroutine(EndGameSequence());
@@ -695,7 +681,7 @@ namespace Minigames.DivingForPictures
private IEnumerator EndGameSequence()
{
// Clean up active monsters
- foreach (var monster in activeMonsters.ToArray())
+ foreach (var monster in _activeMonsters.ToArray())
{
if (monster != null)
{
@@ -703,7 +689,7 @@ namespace Minigames.DivingForPictures
}
}
- activeMonsters.Clear();
+ _activeMonsters.Clear();
// 1) Call the booster pack giver if available
bool completed = false;
@@ -714,6 +700,7 @@ namespace Minigames.DivingForPictures
UnityAction onDone = null;
onDone = () => { completed = true; giver.OnCompleted.RemoveListener(onDone); };
giver.OnCompleted.AddListener(onDone);
+ UIPageController.Instance.ShowAllUI();
giver.GiveBoosterPack();
// 2) Wait for it to finish (with a safety timeout in case it's not wired)
@@ -733,9 +720,9 @@ namespace Minigames.DivingForPictures
// 3) Only then show the game over screen
CinematicsManager.Instance.ShowGameOverScreen();
-
+
// Final score could be saved to player prefs or other persistence
- Logging.Debug($"Final Score: {playerScore}");
+ Logging.Debug($"Final Score: {_playerScore}");
}
///
@@ -744,12 +731,12 @@ namespace Minigames.DivingForPictures
/// Target velocity factor (e.g., -1.0 for surfacing speed)
public void SetVelocityFactor(float targetFactor)
{
- if (velocityTransitionCoroutine != null)
+ if (_velocityTransitionCoroutine != null)
{
- StopCoroutine(velocityTransitionCoroutine);
+ StopCoroutine(_velocityTransitionCoroutine);
}
- velocityTransitionCoroutine = StartCoroutine(TransitionVelocityFactor(targetFactor));
+ _velocityTransitionCoroutine = StartCoroutine(TransitionVelocityFactor(targetFactor));
}
///
@@ -757,29 +744,29 @@ namespace Minigames.DivingForPictures
///
private IEnumerator TransitionVelocityFactor(float targetFactor)
{
- float startFactor = currentVelocityFactor;
+ float startFactor = _currentVelocityFactor;
float elapsed = 0f;
- while (elapsed < settings.SpeedTransitionDuration)
+ while (elapsed < _settings.SpeedTransitionDuration)
{
elapsed += Time.deltaTime;
- float t = Mathf.Clamp01(elapsed / settings.SpeedTransitionDuration);
+ float t = Mathf.Clamp01(elapsed / _settings.SpeedTransitionDuration);
// Smooth step interpolation
float smoothStep = t * t * (3f - 2f * t);
- currentVelocityFactor = Mathf.Lerp(startFactor, targetFactor, smoothStep);
+ _currentVelocityFactor = Mathf.Lerp(startFactor, targetFactor, smoothStep);
// Notify listeners about the velocity factor change
- OnVelocityFactorChanged?.Invoke(currentVelocityFactor);
+ OnVelocityFactorChanged?.Invoke(_currentVelocityFactor);
yield return null;
}
- currentVelocityFactor = targetFactor;
+ _currentVelocityFactor = targetFactor;
// Final assignment to ensure exact target value
- OnVelocityFactorChanged?.Invoke(currentVelocityFactor);
+ OnVelocityFactorChanged?.Invoke(_currentVelocityFactor);
}
///
@@ -793,7 +780,7 @@ namespace Minigames.DivingForPictures
_pausableComponents.Add(component);
// If the game is already paused, pause the component immediately
- if (_isPaused)
+ if (GameManager.Instance.IsPaused)
{
component.Pause();
}
@@ -820,48 +807,46 @@ namespace Minigames.DivingForPictures
///
public void Pause()
{
+ // Ignore pause requests once the game has reached Game Over
+ if (_isGameOver) return;
DoPause();
- }
-
- public void DoPause(bool turnOffGameInput = true)
- {
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
-
- // Pause all registered components
- foreach (var component in _pausableComponents)
- {
- component.Pause();
- }
-
- // Change input mode to UI when menu is open
- if(turnOffGameInput)
- InputManager.Instance.SetInputMode(InputMode.GameAndUI);
-
- Logging.Debug($"[DivingGameManager] Game paused. Paused {_pausableComponents.Count} components.");
- }
-
- ///
- /// Resume the game and all registered components
- ///
- public void DoResume()
- {
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
-
- // Resume all registered components
- foreach (var component in _pausableComponents)
- {
- component.DoResume();
- }
-
- // Change input mode to UI when menu is open
- InputManager.Instance.SetInputMode(InputMode.GameAndUI);
-
- Logging.Debug($"[DivingGameManager] Game resumed. Resumed {_pausableComponents.Count} components.");
- }
+ }
+
+ public void DoPause(bool turnOffGameInput = true)
+ {
+ // Ignore pause requests once the game has ended
+ if (_isGameOver) return;
+ // Pause all registered components
+ foreach (var component in _pausableComponents)
+ {
+ component.Pause();
+ }
+
+ // Change input mode to UI when menu is open
+ if(turnOffGameInput)
+ InputManager.Instance.SetInputMode(InputMode.GameAndUI);
+
+ Logging.Debug($"[DivingGameManager] Game paused. Paused {_pausableComponents.Count} components.");
+ }
+
+ ///
+ /// Resume the game and all registered components
+ ///
+ public void DoResume()
+ {
+ // Ignore resume requests once the game has ended
+ if (_isGameOver) return;
+ // Resume all registered components
+ foreach (var component in _pausableComponents)
+ {
+ component.DoResume();
+ }
+
+ // Change input mode to UI when menu is open
+ InputManager.Instance.SetInputMode(InputMode.GameAndUI);
+
+ Logging.Debug($"[DivingGameManager] Game resumed. Resumed {_pausableComponents.Count} components.");
+ }
#region Photo Sequence Methods
@@ -938,23 +923,23 @@ namespace Minigames.DivingForPictures
if (monster == null) return;
// Calculate base points from depth
- int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * settings.DepthMultiplier);
+ int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.DepthMultiplier);
// Apply proximity multiplier (0-100%)
float proximityMultiplier = Mathf.Clamp01(proximity); // Ensure it's in 0-1 range
- int proximityBonus = Mathf.RoundToInt(settings.BasePoints * proximityMultiplier);
+ int proximityBonus = Mathf.RoundToInt(_settings.BasePoints * proximityMultiplier);
// Calculate total score
- int pointsAwarded = settings.BasePoints + proximityBonus + depthBonus;
+ int pointsAwarded = _settings.BasePoints + proximityBonus + depthBonus;
Logging.Debug($"[DivingGameManager] Picture score calculation: base={proximityBonus} (proximity={proximity:F2}), " +
$"depth bonus={depthBonus}, total={pointsAwarded}");
// Add score
- playerScore += pointsAwarded;
+ _playerScore += pointsAwarded;
// Fire events
- OnScoreChanged?.Invoke(playerScore);
+ OnScoreChanged?.Invoke(_playerScore);
OnPictureTaken?.Invoke(monster, pointsAwarded);
}
@@ -1061,14 +1046,14 @@ namespace Minigames.DivingForPictures
monster.OnMonsterDespawned += DoMonsterDespawned;
// Add to active monsters list
- activeMonsters.Add(monster);
+ _activeMonsters.Add(monster);
}
}
private void DoMonsterDespawned(Monster monster)
{
// Remove from active list
- activeMonsters.Remove(monster);
+ _activeMonsters.Remove(monster);
// Unsubscribe from monster events
if (monster != null)
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs
index df5a7c4e..1b41fd2d 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/FloatingObstacle.cs
@@ -59,12 +59,6 @@ namespace Minigames.DivingForPictures
private float _screenNormalizationFactor = 1.0f;
private IDivingMinigameSettings _settings;
- // Pause state
- private bool _isPaused = false;
-
- // IPausable implementation
- public bool IsPaused => _isPaused;
-
private void Awake()
{
_collider = GetComponent();
@@ -124,7 +118,7 @@ namespace Minigames.DivingForPictures
private void OnEnable()
{
// Only start coroutines if not paused
- if (!_isPaused)
+ if (!GameManager.Instance.IsPaused)
{
StartObstacleCoroutines();
}
@@ -143,9 +137,6 @@ namespace Minigames.DivingForPictures
///
public void Pause()
{
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
StopObstacleCoroutines();
Logging.Debug($"[FloatingObstacle] Paused obstacle: {name}");
@@ -156,9 +147,6 @@ namespace Minigames.DivingForPictures
///
public void DoResume()
{
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
StartObstacleCoroutines();
Logging.Debug($"[FloatingObstacle] Resumed obstacle: {name}");
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs
index 3efe33f1..ed03de3f 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs
@@ -43,12 +43,6 @@ namespace Minigames.DivingForPictures
private bool _isSurfacing = false; // Flag to track surfacing state
private float _velocityFactor = 1.0f; // Current velocity factor from the game manager
- // Pause state
- private bool _isPaused = false;
-
- // IPausable implementation
- public bool IsPaused => _isPaused;
-
private void Awake()
{
_mainCamera = UnityEngine.Camera.main;
@@ -127,10 +121,6 @@ namespace Minigames.DivingForPictures
///
public void Pause()
{
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
-
// Stop spawning coroutine
if (_spawnCoroutine != null)
{
@@ -159,10 +149,6 @@ namespace Minigames.DivingForPictures
///
public void DoResume()
{
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
-
// Restart spawning coroutine if not in surfacing mode
if (!_isSurfacing)
{
@@ -190,7 +176,7 @@ namespace Minigames.DivingForPictures
///
private void StartSpawnCoroutine()
{
- if (_spawnCoroutine == null && !_isPaused && !_isSurfacing)
+ if (_spawnCoroutine == null && !GameManager.Instance.IsPaused && !_isSurfacing)
{
_spawnCoroutine = StartCoroutine(SpawnObstacleRoutine());
}
@@ -201,7 +187,7 @@ namespace Minigames.DivingForPictures
///
private void StartMoveCoroutine()
{
- if (_moveCoroutine == null && !_isPaused)
+ if (_moveCoroutine == null && !GameManager.Instance.IsPaused)
{
_moveCoroutine = StartCoroutine(MoveObstaclesRoutine());
}
@@ -212,7 +198,7 @@ namespace Minigames.DivingForPictures
///
private void StartDespawnCoroutine()
{
- if (_despawnCoroutine == null && !_isPaused)
+ if (_despawnCoroutine == null && !GameManager.Instance.IsPaused)
{
_despawnCoroutine = StartCoroutine(DespawnObstaclesRoutine());
}
@@ -553,7 +539,7 @@ namespace Minigames.DivingForPictures
obstacleComponent.SetSpawner(this);
// If spawner is already paused, pause the obstacle immediately
- if (_isPaused)
+ if (GameManager.Instance.IsPaused)
{
obstacleComponent.Pause();
}
@@ -677,7 +663,7 @@ namespace Minigames.DivingForPictures
{
Logging.Debug("[ObstacleSpawner] Started spawning coroutine");
- while (enabled && gameObject.activeInHierarchy && !_isPaused && !_isSurfacing)
+ while (enabled && gameObject.activeInHierarchy && !GameManager.Instance.IsPaused && !_isSurfacing)
{
// Calculate next spawn time with variation
float nextSpawnTime = _settings.ObstacleSpawnInterval +
@@ -707,7 +693,7 @@ namespace Minigames.DivingForPictures
Logging.Debug("[ObstacleSpawner] Started obstacle monitoring coroutine");
// This coroutine now just monitors obstacles, not moves them
- while (enabled && gameObject.activeInHierarchy && !_isPaused)
+ while (enabled && gameObject.activeInHierarchy && !GameManager.Instance.IsPaused)
{
// Clean up any null references in the active obstacles list
_activeObstacles.RemoveAll(obstacle => obstacle == null);
@@ -729,7 +715,7 @@ namespace Minigames.DivingForPictures
const float checkInterval = 0.5f; // Check every half second
Logging.Debug("[ObstacleSpawner] Started despawn coroutine with interval: " + checkInterval);
- while (enabled && gameObject.activeInHierarchy && !_isPaused)
+ while (enabled && gameObject.activeInHierarchy && !GameManager.Instance.IsPaused)
{
// Calculate screen bounds for despawning
float despawnBuffer = 2f; // Extra buffer beyond screen edges
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs
index 6766e42b..2e1615fd 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs
@@ -18,26 +18,26 @@ namespace Minigames.DivingForPictures.Player
[SerializeField] private EdgeAnchor edgeAnchor;
// Settings reference
- private IDivingMinigameSettings settings;
+ private IDivingMinigameSettings _settings;
- private float targetFingerX;
- private bool isTouchActive;
- private float originY;
+ private float _targetFingerX;
+ private bool _isTouchActive;
+ private float _originY;
// Tap impulse system variables
- private float tapImpulseStrength = 0f;
- private float tapDirection = 0f;
+ private float _tapImpulseStrength = 0f;
+ private float _tapDirection = 0f;
// Initialization flag
- private bool isInitialized = false;
+ private bool _isInitialized = false;
void Awake()
{
- originY = transform.position.y;
+ _originY = transform.position.y;
// Get settings from GameManager
- settings = GameManager.GetSettingsObject();
- if (settings == null)
+ _settings = GameManager.GetSettingsObject();
+ if (_settings == null)
{
Debug.LogError("[PlayerController] Failed to load diving minigame settings!");
}
@@ -49,8 +49,8 @@ namespace Minigames.DivingForPictures.Player
DivingGameManager.Instance.RegisterPausableComponent(this);
// Initialize target to current position
- targetFingerX = transform.position.x;
- isTouchActive = false;
+ _targetFingerX = transform.position.x;
+ _isTouchActive = false;
// Try to find edge anchor if not assigned
if (edgeAnchor == null)
@@ -100,12 +100,12 @@ namespace Minigames.DivingForPictures.Player
///
private void Initialize()
{
- if (isInitialized) return;
+ if (_isInitialized) return;
// Register as default consumer for input
InputManager.Instance?.SetDefaultConsumer(this);
- isInitialized = true;
+ _isInitialized = true;
Logging.Debug("[PlayerController] Initialized");
}
@@ -130,19 +130,19 @@ namespace Minigames.DivingForPictures.Player
public void OnTap(Vector2 worldPosition)
{
// Ignore input when paused
- if (isPaused) return;
+ if (GameManager.Instance.IsPaused) return;
// Logging.Debug($"[EndlessDescenderController] OnTap at {worldPosition}");
- float targetX = Mathf.Clamp(worldPosition.x, settings.ClampXMin, settings.ClampXMax);
+ float targetX = Mathf.Clamp(worldPosition.x, _settings.ClampXMin, _settings.ClampXMax);
// Calculate tap direction (+1 for right, -1 for left)
- tapDirection = Mathf.Sign(targetX - transform.position.x);
+ _tapDirection = Mathf.Sign(targetX - transform.position.x);
// Set impulse strength to full
- tapImpulseStrength = 1.0f;
+ _tapImpulseStrength = 1.0f;
// Store target X for animation purposes
- targetFingerX = targetX;
+ _targetFingerX = targetX;
// Do not set _isTouchActive for taps anymore
// _isTouchActive = true; - Removed to prevent continuous movement
@@ -154,11 +154,11 @@ namespace Minigames.DivingForPictures.Player
public void OnHoldStart(Vector2 worldPosition)
{
// Ignore input when paused
- if (isPaused) return;
+ if (GameManager.Instance.IsPaused) return;
// Logging.Debug($"[EndlessDescenderController] OnHoldStart at {worldPosition}");
- targetFingerX = Mathf.Clamp(worldPosition.x, settings.ClampXMin, settings.ClampXMax);
- isTouchActive = true;
+ _targetFingerX = Mathf.Clamp(worldPosition.x, _settings.ClampXMin, _settings.ClampXMax);
+ _isTouchActive = true;
}
///
@@ -167,10 +167,10 @@ namespace Minigames.DivingForPictures.Player
public void OnHoldMove(Vector2 worldPosition)
{
// Ignore input when paused
- if (isPaused) return;
+ if (GameManager.Instance.IsPaused) return;
// Logging.Debug($"[EndlessDescenderController] OnHoldMove at {worldPosition}");
- targetFingerX = Mathf.Clamp(worldPosition.x, settings.ClampXMin, settings.ClampXMax);
+ _targetFingerX = Mathf.Clamp(worldPosition.x, _settings.ClampXMin, _settings.ClampXMax);
}
///
@@ -179,25 +179,25 @@ namespace Minigames.DivingForPictures.Player
public void OnHoldEnd(Vector2 worldPosition)
{
// Ignore input when paused
- if (isPaused) return;
+ if (GameManager.Instance.IsPaused) return;
// Logging.Debug($"[EndlessDescenderController] OnHoldEnd at {worldPosition}");
- isTouchActive = false;
+ _isTouchActive = false;
}
void Update()
{
// Skip movement processing if paused
- if (isPaused) return;
+ if (GameManager.Instance.IsPaused) return;
// Handle hold movement
- if (isTouchActive)
+ if (_isTouchActive)
{
float currentX = transform.position.x;
- float lerpSpeed = settings.LerpSpeed;
- float maxOffset = settings.MaxOffset;
- float exponent = settings.SpeedExponent;
- float targetX = targetFingerX;
+ float lerpSpeed = _settings.LerpSpeed;
+ float maxOffset = _settings.MaxOffset;
+ float exponent = _settings.SpeedExponent;
+ float targetX = _targetFingerX;
float offset = targetX - currentX;
offset = Mathf.Clamp(offset, -maxOffset, maxOffset);
float absOffset = Mathf.Abs(offset);
@@ -206,32 +206,32 @@ namespace Minigames.DivingForPictures.Player
// Prevent overshooting
moveStep = Mathf.Clamp(moveStep, -absOffset, absOffset);
float newX = currentX + moveStep;
- newX = Mathf.Clamp(newX, settings.ClampXMin, settings.ClampXMax);
+ newX = Mathf.Clamp(newX, _settings.ClampXMin, _settings.ClampXMax);
UpdatePosition(newX);
}
// Handle tap impulse movement
- else if (tapImpulseStrength > 0)
+ else if (_tapImpulseStrength > 0)
{
float currentX = transform.position.x;
- float maxOffset = settings.MaxOffset;
- float lerpSpeed = settings.LerpSpeed;
+ float maxOffset = _settings.MaxOffset;
+ float lerpSpeed = _settings.LerpSpeed;
// Calculate move distance based on impulse strength
- float moveDistance = maxOffset * tapImpulseStrength * Time.deltaTime * lerpSpeed;
+ float moveDistance = maxOffset * _tapImpulseStrength * Time.deltaTime * lerpSpeed;
// Limit total movement from single tap
- moveDistance = Mathf.Min(moveDistance, settings.TapMaxDistance * tapImpulseStrength);
+ moveDistance = Mathf.Min(moveDistance, _settings.TapMaxDistance * _tapImpulseStrength);
// Apply movement in tap direction
- float newX = currentX + (moveDistance * tapDirection);
- newX = Mathf.Clamp(newX, settings.ClampXMin, settings.ClampXMax);
+ float newX = currentX + (moveDistance * _tapDirection);
+ newX = Mathf.Clamp(newX, _settings.ClampXMin, _settings.ClampXMax);
// Reduce impulse strength over time
- tapImpulseStrength -= Time.deltaTime * settings.TapDecelerationRate;
- if (tapImpulseStrength < 0.01f)
+ _tapImpulseStrength -= Time.deltaTime * _settings.TapDecelerationRate;
+ if (_tapImpulseStrength < 0.01f)
{
- tapImpulseStrength = 0f;
+ _tapImpulseStrength = 0f;
}
UpdatePosition(newX);
@@ -243,7 +243,7 @@ namespace Minigames.DivingForPictures.Player
///
private void UpdatePosition(float newX)
{
- float newY = originY;
+ float newY = _originY;
// Add vertical offset from WobbleBehavior if present
WobbleBehavior wobble = GetComponent();
if (wobble != null)
@@ -258,7 +258,7 @@ namespace Minigames.DivingForPictures.Player
///
public void UpdateOriginY(float newOriginY)
{
- originY = newOriginY;
+ _originY = newOriginY;
}
///
@@ -267,7 +267,7 @@ namespace Minigames.DivingForPictures.Player
///
private void UpdateOriginYFromCurrentPosition()
{
- originY = transform.position.y;
+ _originY = transform.position.y;
}
///
@@ -276,24 +276,19 @@ namespace Minigames.DivingForPictures.Player
///
private void UpdateOriginYFromAnchor()
{
- originY = edgeAnchor.transform.position.y;
+ _originY = edgeAnchor.transform.position.y;
}
#region IPausable Implementation
- private bool isPaused = false;
///
/// Pauses the player controller, blocking all input processing
///
public void Pause()
{
- if (isPaused) return;
-
- isPaused = true;
-
// If we're being paused, stop any active touch and tap impulse
- isTouchActive = false;
- tapImpulseStrength = 0f;
+ _isTouchActive = false;
+ _tapImpulseStrength = 0f;
Logging.Debug("[PlayerController] Paused");
}
@@ -303,16 +298,8 @@ namespace Minigames.DivingForPictures.Player
///
public void DoResume()
{
- if (!isPaused) return;
-
- isPaused = false;
Logging.Debug("[PlayerController] Resumed");
}
-
- ///
- /// Returns whether the player controller is currently paused
- ///
- public bool IsPaused => isPaused;
#endregion
}
}
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/WobbleBehavior.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/WobbleBehavior.cs
index 469d38e3..c6755b84 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Player/WobbleBehavior.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Player/WobbleBehavior.cs
@@ -1,5 +1,6 @@
using UnityEngine;
using AppleHills.Core.Settings;
+using Core;
///
/// Adds a wobble (rocking and vertical movement) effect to the object, based on speed and time.
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs
index 2d66b080..bc4950d4 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs
@@ -1,10 +1,8 @@
-using System;
-using System.Collections;
+using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
-using Pooling;
using AppleHills.Core.Settings;
using Utils;
using AppleHills.Core.Interfaces;
@@ -113,12 +111,6 @@ namespace Minigames.DivingForPictures
}
}
- // Pause state
- private bool _isPaused = false;
-
- // IPausable implementation
- public bool IsPaused => _isPaused;
-
private void Awake()
{
_mainCamera = UnityEngine.Camera.main;
@@ -193,10 +185,6 @@ namespace Minigames.DivingForPictures
///
public void Pause()
{
- if (_isPaused) return; // Already paused
-
- _isPaused = true;
-
// Stop all active coroutines but save their references
if (_movementCoroutine != null)
{
@@ -230,10 +218,6 @@ namespace Minigames.DivingForPictures
///
public void DoResume()
{
- if (!_isPaused) return; // Already running
-
- _isPaused = false;
-
// Restart all necessary coroutines
StartMovementCoroutine();
StartTileDestructionCoroutine();
@@ -500,7 +484,7 @@ namespace Minigames.DivingForPictures
///
private void StartMovementCoroutine()
{
- if (_movementCoroutine == null && !_isPaused)
+ if (_movementCoroutine == null && !GameManager.Instance.IsPaused)
{
_movementCoroutine = StartCoroutine(MoveActiveTilesRoutine());
}
@@ -513,7 +497,7 @@ namespace Minigames.DivingForPictures
{
Logging.Debug($"[TrenchTileSpawner] Started movement coroutine with normalized speed: {_baseMoveSpeed:F3}");
- while (enabled && gameObject.activeInHierarchy && !_isPaused)
+ while (enabled && gameObject.activeInHierarchy && !GameManager.Instance.IsPaused)
{
// Skip if no active tiles
if (_activeTiles.Count == 0)
@@ -554,7 +538,7 @@ namespace Minigames.DivingForPictures
const float checkInterval = 1.0f; // Check once per second
Logging.Debug($"[TrenchTileSpawner] Started speed ramping coroutine with interval: {checkInterval}s");
- while (enabled && gameObject.activeInHierarchy && !_isPaused)
+ while (enabled && gameObject.activeInHierarchy && !GameManager.Instance.IsPaused)
{
// Increase the base move speed up to the maximum
_baseMoveSpeed = Mathf.Min(_baseMoveSpeed + _settings.SpeedUpFactor, _settings.MaxNormalizedMoveSpeed);
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs b/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs
index 81146531..0efc9b9b 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities/BottlePauser.cs
@@ -7,8 +7,6 @@ namespace Minigames.DivingForPictures.Utilities
{
[SerializeField] private WobbleBehavior wobbleReference;
- private bool isPaused = false;
-
private void Start()
{
DivingGameManager.Instance.RegisterPausableComponent(this);
@@ -17,15 +15,11 @@ namespace Minigames.DivingForPictures.Utilities
public void Pause()
{
wobbleReference.enabled = false;
- isPaused = true;
}
public void DoResume()
{
wobbleReference.enabled = true;
- isPaused = false;
}
-
- public bool IsPaused => isPaused;
}
}
diff --git a/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs b/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs
index ce143f6f..9203bed7 100644
--- a/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs
+++ b/Assets/Scripts/Minigames/DivingForPictures/Utilities/RockPauser.cs
@@ -8,8 +8,6 @@ namespace Minigames.DivingForPictures.Utilities
[SerializeField] private RockFollower rockReference;
[SerializeField] private WobbleBehavior rockWobbleReference;
- private bool isPaused = false;
-
private void Start()
{
DivingGameManager.Instance.RegisterPausableComponent(this);
@@ -19,16 +17,12 @@ namespace Minigames.DivingForPictures.Utilities
{
rockReference.enabled = false;
rockWobbleReference.enabled = false;
- isPaused = true;
}
public void DoResume()
{
rockReference.enabled = true;
rockWobbleReference.enabled = true;
- isPaused = false;
}
-
- public bool IsPaused => isPaused;
}
}
diff --git a/Assets/Scripts/Movement/FollowerController.cs b/Assets/Scripts/Movement/FollowerController.cs
index 3aba4b8b..dc4b0238 100644
--- a/Assets/Scripts/Movement/FollowerController.cs
+++ b/Assets/Scripts/Movement/FollowerController.cs
@@ -4,6 +4,7 @@ using Pathfinding;
using UnityEngine.SceneManagement;
using Utils;
using AppleHills.Core.Settings;
+using Core;
///
/// Controls the follower character, including following the player, handling pickups, and managing held items.
diff --git a/Assets/Scripts/UI/BlinkingCanvasGroup.cs b/Assets/Scripts/UI/BlinkingCanvasGroup.cs
new file mode 100644
index 00000000..e59ecb55
--- /dev/null
+++ b/Assets/Scripts/UI/BlinkingCanvasGroup.cs
@@ -0,0 +1,112 @@
+using Pixelplacement;
+using UnityEngine;
+
+namespace UI
+{
+ ///
+ /// Adds a CanvasGroup (if missing) and plays a continuous blinking tween on its alpha.
+ /// Attach to any GameObject to make it pulse/fade in and out.
+ ///
+ [DisallowMultipleComponent]
+ [RequireComponent(typeof(CanvasGroup))]
+ public class BlinkingCanvasGroup : MonoBehaviour
+ {
+ [Header("Blink Settings")] [Tooltip("Minimum alpha value during blink")] [Range(0f, 1f)]
+ public float minAlpha;
+
+ [Tooltip("Maximum alpha value during blink")] [Range(0f, 1f)]
+ public float maxAlpha = 1f;
+
+ [Tooltip("Duration of one leg (min->max or max->min)")]
+ public float legDuration = 0.5f;
+
+ [Tooltip("Delay before starting the blinking")]
+ public float startDelay;
+
+ [Tooltip("Whether the tween should obey Time.timeScale (false = unscaled)")]
+ public bool obeyTimescale;
+
+ [Tooltip("Optional animation curve for easing. Leave null for default ease in/out.")]
+ public AnimationCurve easeCurve;
+
+ // Internal
+ private CanvasGroup _canvasGroup;
+ private Pixelplacement.TweenSystem.TweenBase _activeTween;
+
+ void Awake()
+ {
+ // Ensure we have a CanvasGroup
+ _canvasGroup = GetComponent();
+ if (_canvasGroup == null)
+ {
+ _canvasGroup = gameObject.AddComponent();
+ }
+
+ // Ensure starting alpha
+ _canvasGroup.alpha = minAlpha;
+ }
+
+ void Start()
+ {
+ StartBlinking();
+ }
+
+ void OnEnable()
+ {
+ // If re-enabled, ensure tween is running
+ if (_activeTween == null)
+ StartBlinking();
+ }
+
+ void OnDisable()
+ {
+ StopBlinking();
+ }
+
+ void OnDestroy()
+ {
+ StopBlinking();
+ }
+
+ ///
+ /// Start the continuous blinking tween.
+ ///
+ public void StartBlinking()
+ {
+ StopBlinking();
+
+ if (_canvasGroup == null) return;
+
+ // Use PingPong-like behavior by chaining two opposite legs with LoopType.Loop
+ // Simpler: Tween.CanvasGroupAlpha has an overload that sets startAlpha then end.
+ // We'll tween min->max then set LoopType.PingPong if available. The API supports LoopType.PingPong.
+
+ // Start from minAlpha to maxAlpha
+ _canvasGroup.alpha = minAlpha;
+
+ // Use the Tween.Value overload for float with obeyTimescale parameter
+ _activeTween = Tween.Value(minAlpha, maxAlpha, v => _canvasGroup.alpha = v, legDuration, startDelay,
+ easeCurve ?? Tween.EaseInOut, Tween.LoopType.PingPong, null, null, obeyTimescale);
+ }
+
+ ///
+ /// Stops the blinking tween if running.
+ ///
+ public void StopBlinking()
+ {
+ if (_activeTween != null)
+ {
+ try
+ {
+ _activeTween.Cancel();
+ }
+ catch
+ {
+ // Some versions of the tween API may not expose Cancel; ignore safely.
+ }
+
+ _activeTween = null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/UI/BlinkingCanvasGroup.cs.meta b/Assets/Scripts/UI/BlinkingCanvasGroup.cs.meta
new file mode 100644
index 00000000..1d0d116a
--- /dev/null
+++ b/Assets/Scripts/UI/BlinkingCanvasGroup.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b75de64fb2fd4ff0b869bf469e2becea
+timeCreated: 1761299308
\ No newline at end of file
diff --git a/Assets/Scripts/UI/CardSystem/BackpackInput.cs b/Assets/Scripts/UI/CardSystem/BackpackInput.cs
deleted file mode 100644
index 018bc4d7..00000000
--- a/Assets/Scripts/UI/CardSystem/BackpackInput.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using UnityEngine;
-
-namespace UI.CardSystem
-{
- public class BackpackInput : MonoBehaviour, ITouchInputConsumer
- {
- // Start is called once before the first execution of Update after the MonoBehaviour is created
- void Start()
- {
-
- }
-
- // Update is called once per frame
- void Update()
- {
-
- }
-
- public void OnTap(Vector2 position)
- {
- return;
- }
-
- public void OnHoldStart(Vector2 position)
- {
- return;
- }
-
- public void OnHoldMove(Vector2 position)
- {
- return;
- }
-
- public void OnHoldEnd(Vector2 position)
- {
- return;
- }
- }
-}
diff --git a/Assets/Scripts/UI/CardSystem/BackpackInput.cs.meta b/Assets/Scripts/UI/CardSystem/BackpackInput.cs.meta
deleted file mode 100644
index 5809875e..00000000
--- a/Assets/Scripts/UI/CardSystem/BackpackInput.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: e7ea50a695c58944799b4f27a9014301
\ No newline at end of file
diff --git a/Assets/Scripts/UI/CardSystem/CardAlbumUI.cs b/Assets/Scripts/UI/CardSystem/CardAlbumUI.cs
index d728cafb..3bcafcc4 100644
--- a/Assets/Scripts/UI/CardSystem/CardAlbumUI.cs
+++ b/Assets/Scripts/UI/CardSystem/CardAlbumUI.cs
@@ -2,7 +2,6 @@
using Bootstrap;
using Core;
using Data.CardSystem;
-using Input;
using Pixelplacement;
using UI.Core;
using UnityEngine;
@@ -33,8 +32,7 @@ namespace UI.CardSystem
public GameObject BackpackIcon => backpackIcon;
private UIPageController PageController => UIPageController.Instance;
private CardSystemManager _cardManager;
- private bool _isInitialized = false;
- private bool _hasUnseenCards = false;
+ private bool _hasUnseenCards;
private void Awake()
{
@@ -44,9 +42,6 @@ namespace UI.CardSystem
backpackButton.onClick.AddListener(OnBackpackButtonClicked);
}
- // Initially show only the backpack icon
- ShowOnlyBackpackIcon();
-
// Hide notification dot initially
if (boosterNotificationDot != null)
boosterNotificationDot.gameObject.SetActive(false);
@@ -57,8 +52,18 @@ namespace UI.CardSystem
private void InitializePostBoot()
{
+ // Initially show only the backpack icon
+ ShowOnlyBackpackIcon();
+
// Initialize pages and hide them
InitializePages();
+
+ // React to global UI hide/show events (top-page only) by toggling this GameObject
+ if (UIPageController.Instance != null)
+ {
+ UIPageController.Instance.OnAllUIHidden += HandleAllUIHidden;
+ UIPageController.Instance.OnAllUIShown += HandleAllUIShown;
+ }
}
private void Start()
@@ -77,8 +82,6 @@ namespace UI.CardSystem
// Initialize UI with current values
UpdateBoosterCount(_cardManager.GetBoosterPackCount());
}
-
- _isInitialized = true;
}
private void OnDestroy()
@@ -103,6 +106,13 @@ namespace UI.CardSystem
{
PageController.OnPageChanged -= OnPageChanged;
}
+
+ // Unsubscribe from global UI hide/show events
+ if (UIPageController.Instance != null)
+ {
+ UIPageController.Instance.OnAllUIHidden -= HandleAllUIHidden;
+ UIPageController.Instance.OnAllUIShown -= HandleAllUIShown;
+ }
}
///
@@ -142,10 +152,6 @@ namespace UI.CardSystem
if (notificationSound != null)
notificationSound.Play();
- // Eat input so the characters don't walk around
- var backpackInput = backpackIcon.gameObject.GetComponentInParent();
- InputManager.Instance.RegisterOverrideConsumer(backpackInput);
-
PageController.PushPage(mainMenuPage);
// Clear notification for unseen cards when opening menu
@@ -159,6 +165,8 @@ namespace UI.CardSystem
{
backpackButton.gameObject.SetActive(false);
}
+
+ GameManager.Instance.RequestPause(this);
}
///
@@ -170,8 +178,7 @@ namespace UI.CardSystem
if (newPage == null)
{
ShowOnlyBackpackIcon();
- var backpackInput = backpackIcon.gameObject.GetComponentInParent();
- InputManager.Instance.UnregisterOverrideConsumer(backpackInput);
+ GameManager.Instance.ReleasePause(this);
}
else
{
@@ -315,5 +322,19 @@ namespace UI.CardSystem
// Just log the upgrade event without showing a notification
Logging.Debug($"[CardAlbumUI] Card upgraded: {card.Name} to {card.Rarity}");
}
+
+ // Handlers for UI controller hide/show events — toggle this GameObject active state
+ private void HandleAllUIHidden()
+ {
+ // Ensure UI returns to backpack-only state before deactivating so we don't leave the game paused
+ ShowOnlyBackpackIcon();
+ backpackButton.gameObject.SetActive(false);
+
+ }
+
+ private void HandleAllUIShown()
+ {
+ backpackButton.gameObject.SetActive(true);
+ }
}
}
diff --git a/Assets/Scripts/UI/Core/UIPageController.cs b/Assets/Scripts/UI/Core/UIPageController.cs
index 9966f216..808ca9fd 100644
--- a/Assets/Scripts/UI/Core/UIPageController.cs
+++ b/Assets/Scripts/UI/Core/UIPageController.cs
@@ -23,6 +23,10 @@ namespace UI.Core
// Event fired when the page stack changes
public event Action OnPageChanged;
+ // Events fired when the controller hides or shows all UI pages
+ public event Action OnAllUIHidden;
+ public event Action OnAllUIShown;
+
private PlayerInput _playerInput;
private InputAction _cancelAction;
@@ -141,5 +145,39 @@ namespace UI.Core
OnPageChanged?.Invoke(null);
Logging.Debug("[UIPageController] Cleared page stack");
}
+
+ ///
+ /// Hide all currently stacked UI pages by calling TransitionOut on each.
+ /// This does not modify the page stack; it simply asks pages to transition out
+ /// so UI elements can be hidden. Subscribers can react to .
+ ///
+ public void HideAllUI()
+ {
+ // Only transition out the top (active) page — maintains stack semantics.
+ var current = CurrentPage;
+ if (current != null)
+ {
+ current.TransitionOut();
+ }
+
+ OnAllUIHidden?.Invoke();
+ }
+
+ ///
+ /// Show all currently stacked UI pages by calling TransitionIn on each from bottom to top.
+ /// This does not modify the page stack; it asks pages to transition in so UI elements become visible.
+ /// Subscribers can react to .
+ ///
+ public void ShowAllUI()
+ {
+ // Only transition in the top (active) page — maintains stack semantics.
+ var current = CurrentPage;
+ if (current != null)
+ {
+ current.TransitionIn();
+ }
+
+ OnAllUIShown?.Invoke();
+ }
}
}
diff --git a/Assets/Scripts/UI/PauseMenu.cs b/Assets/Scripts/UI/PauseMenu.cs
index 507d28ac..db8b500d 100644
--- a/Assets/Scripts/UI/PauseMenu.cs
+++ b/Assets/Scripts/UI/PauseMenu.cs
@@ -2,7 +2,6 @@ using System;
using Core;
using UnityEngine;
using UnityEngine.SceneManagement;
-using Input;
using Bootstrap;
using UI.Core;
using Pixelplacement;
@@ -12,7 +11,6 @@ namespace UI
public class PauseMenu : UIPage
{
private static PauseMenu _instance;
- private static bool _isQuitting;
///
/// Singleton instance of the PauseMenu. No longer creates an instance if one doesn't exist.
@@ -24,15 +22,6 @@ namespace UI
[SerializeField] private GameObject pauseButton;
[SerializeField] private CanvasGroup canvasGroup;
- public event Action OnGamePaused;
- public event Action OnGameResumed;
-
- private bool _isPaused = false;
-
- ///
- /// Returns whether the game is currently paused
- ///
- public bool IsPaused => _isPaused;
private void Awake()
{
@@ -57,6 +46,13 @@ namespace UI
// Subscribe to scene loaded events
SceneManagerService.Instance.SceneLoadCompleted += SetPauseMenuByLevel;
+ // Also react to global UI hide/show events from the page controller
+ if (UIPageController.Instance != null)
+ {
+ UIPageController.Instance.OnAllUIHidden += HandleAllUIHidden;
+ UIPageController.Instance.OnAllUIShown += HandleAllUIShown;
+ }
+
// SceneManagerService subscription moved to InitializePostBoot
// Set initial state based on current scene
@@ -72,11 +68,11 @@ namespace UI
{
SceneManagerService.Instance.SceneLoadCompleted -= SetPauseMenuByLevel;
}
- }
-
- void OnApplicationQuit()
- {
- _isQuitting = true;
+ if (UIPageController.Instance != null)
+ {
+ UIPageController.Instance.OnAllUIHidden -= HandleAllUIHidden;
+ UIPageController.Instance.OnAllUIShown -= HandleAllUIShown;
+ }
}
///
@@ -85,7 +81,7 @@ namespace UI
/// The name of the level/scene
public void SetPauseMenuByLevel(string levelName)
{
- HidePauseMenu(false);
+ HidePauseMenu();
// TODO: Implement level-based pause menu visibility logic if needed
/*if (string.IsNullOrEmpty(levelName))
return;
@@ -103,7 +99,6 @@ namespace UI
///
public void ShowPauseMenu()
{
- if (_isPaused) return;
if (UIPageController.Instance != null)
{
UIPageController.Instance.PushPage(this);
@@ -128,9 +123,9 @@ namespace UI
///
/// Hides the pause menu and shows the pause button. Sets input mode to Game.
///
- public void HidePauseMenu(bool resetInput = true)
+ public void HidePauseMenu()
{
- if (!_isPaused)
+ if (!GameManager.Instance.IsPaused)
{
// Ensure UI is hidden if somehow active without state
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
@@ -148,7 +143,6 @@ namespace UI
pauseMenuPanel.SetActive(false);
if (pauseButton != null)
pauseButton.SetActive(true);
- EndPauseSideEffects(resetInput);
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
@@ -159,29 +153,31 @@ namespace UI
}
}
+ public void HidePauseMenuAndResumeGame()
+ {
+ HidePauseMenu();
+ EndPauseSideEffects();
+ }
+
///
/// Resumes the game by hiding the pause menu.
///
public void ResumeGame()
{
- HidePauseMenu();
+ HidePauseMenuAndResumeGame();
}
private void BeginPauseSideEffects()
{
- _isPaused = true;
if (pauseButton != null) pauseButton.SetActive(false);
- InputManager.Instance.SetInputMode(InputMode.UI);
- OnGamePaused?.Invoke();
+ GameManager.Instance.RequestPause(this);
Logging.Debug("[PauseMenu] Game Paused");
}
- private void EndPauseSideEffects(bool invokeEvent)
+ private void EndPauseSideEffects()
{
- _isPaused = false;
if (pauseButton != null) pauseButton.SetActive(true);
- InputManager.Instance.SetInputMode(InputMode.GameAndUI);
- if (invokeEvent) OnGameResumed?.Invoke();
+ GameManager.Instance.ReleasePause(this);
Logging.Debug("[PauseMenu] Game Resumed");
}
@@ -189,6 +185,8 @@ namespace UI
{
// Ensure the panel root is active
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(true);
+ // Pause side effects should run immediately (hide button, set input mode, etc.).
+ // The tween itself must run in unscaled time so it still animates while the game is paused.
BeginPauseSideEffects();
if (canvasGroup != null)
@@ -196,7 +194,16 @@ namespace UI
canvasGroup.interactable = true;
canvasGroup.blocksRaycasts = true;
canvasGroup.alpha = 0f;
- Tween.Value(0f, 1f, v => canvasGroup.alpha = v, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
+ // pass obeyTimescale = false so this tween runs even when Time.timeScale == 0
+ Tween.Value(0f, 1f, (v) =>
+ {
+ Logging.Debug($"[PauseMenu] Tweening pause menu alpha: {v}");
+ canvasGroup.alpha = v;
+ }, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, () =>
+ {
+ Logging.Debug("[PauseMenu] Finished tweening pause menu in.");
+ onComplete?.Invoke();
+ }, false);
}
else
{
@@ -210,16 +217,17 @@ namespace UI
{
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
+ // Run out-tween in unscaled time as well so the fade completes while paused.
Tween.Value(canvasGroup.alpha, 0f, v => canvasGroup.alpha = v, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, () =>
- {
- EndPauseSideEffects(true);
- if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
- onComplete?.Invoke();
- });
+ {
+ EndPauseSideEffects();
+ if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
+ onComplete?.Invoke();
+ }, false);
}
else
{
- EndPauseSideEffects(true);
+ EndPauseSideEffects();
if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false);
onComplete?.Invoke();
}
@@ -261,7 +269,7 @@ namespace UI
public async void LoadLevel(int levelSelection)
{
// Hide the pause menu before loading a new level
- HidePauseMenu();
+ HidePauseMenuAndResumeGame();
// Replace with the actual scene name as set in Build Settings
var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%"));
@@ -278,5 +286,42 @@ namespace UI
break;
}
}
+
+ // Handlers for UI controller hide/show events — make these safe with respect to transitions and pause state
+ private void HandleAllUIHidden()
+ {
+ var parent = transform.parent?.gameObject ?? gameObject;
+
+ // If we're currently transitioning, wait for the transition out to complete before deactivating
+ if (_isTransitioning)
+ {
+ Action handler = null;
+ handler = () =>
+ {
+ OnTransitionOutCompleted -= handler;
+ parent.SetActive(false);
+ };
+ OnTransitionOutCompleted += handler;
+ return;
+ }
+
+ // If this page is visible, request a proper hide so transition/out side-effects run (e.g. releasing pause)
+ if (_isVisible)
+ {
+ HidePauseMenu();
+ return;
+ }
+
+ // Otherwise it's safe to immediately deactivate
+ parent.SetActive(false);
+ }
+
+ private void HandleAllUIShown()
+ {
+ var parent = transform.parent?.gameObject ?? gameObject;
+
+ // Just ensure the parent is active. Do not force pause or transitions here.
+ parent.SetActive(true);
+ }
}
}
diff --git a/Assets/Scripts/UI/Tutorial/DivingTutorial.cs b/Assets/Scripts/UI/Tutorial/DivingTutorial.cs
index 3063a3ac..56b4e1e7 100644
--- a/Assets/Scripts/UI/Tutorial/DivingTutorial.cs
+++ b/Assets/Scripts/UI/Tutorial/DivingTutorial.cs
@@ -1,175 +1,205 @@
using System.Collections;
-using System.Linq;
-using UnityEngine;
-using Pixelplacement;
-using Minigames.DivingForPictures;
+using Bootstrap;
+using Core;
using Input;
-using UnityEngine.Events;
+using Pixelplacement;
+using UI.Core;
+using UnityEngine;
-public class DivingTutorial : MonoBehaviour, ITouchInputConsumer
+namespace UI.Tutorial
{
- private StateMachine stateMachine;
- public DivingGameManager divingGameManager;
- public bool playTutorial;
-
- // gating for input until current state's animation finishes first loop
- private bool canAcceptInput = false;
- private Coroutine waitLoopCoroutine;
-
- // Start is called once before the first execution of Update after the MonoBehaviour is created
- void Start()
+ public class DivingTutorial : MonoBehaviour, ITouchInputConsumer
{
- if (playTutorial == true)
+ private StateMachine _stateMachine;
+ public bool playTutorial;
+
+ // gating for input until current state's animation finishes first loop
+ [SerializeField] private GameObject tapPrompt;
+
+ private bool _canAcceptInput;
+ private Coroutine _waitLoopCoroutine;
+
+ // Start is called once before the first execution of Update after the MonoBehaviour is created
+ void Start()
{
- InitializeTutorial();
+ BootCompletionService.RegisterInitAction(InitializeTutorial);
+
+ // Ensure prompt is hidden initially (even before tutorial initialization)
+ if (tapPrompt != null)
+ tapPrompt.SetActive(false);
}
- else { RemoveTutorial(); }
- }
- void InitializeTutorial()
- {
- stateMachine = GetComponentInChildren();
- divingGameManager.Pause();
- InputManager.Instance.RegisterOverrideConsumer(this);
- stateMachine.OnLastStateExited.AddListener(RemoveTutorial);
-
- // prepare gating for the initial active state
- SetupInputGateForCurrentState();
- }
-
- void RemoveTutorial()
- {
- Debug.Log("Remove me!");
- if (waitLoopCoroutine != null)
+ void InitializeTutorial()
{
- StopCoroutine(waitLoopCoroutine);
- waitLoopCoroutine = null;
- }
- InputManager.Instance.UnregisterOverrideConsumer(this);
- divingGameManager.DoResume();
- Destroy(gameObject);
- }
-
- public void OnTap(Vector2 position)
- {
- if (!canAcceptInput) return; // block taps until allowed
-
- // consume this tap and immediately block further taps
- canAcceptInput = false;
-
- // move to next state
- stateMachine.Next(true);
-
- // after the state changes, set up gating for the new active state's animation
- SetupInputGateForCurrentState();
- }
-
- public void OnHoldStart(Vector2 position)
- {
- return;
- }
-
- public void OnHoldMove(Vector2 position)
- {
- return;
- }
-
- public void OnHoldEnd(Vector2 position)
- {
- return;
- }
-
- private void SetupInputGateForCurrentState()
- {
- if (waitLoopCoroutine != null)
- {
- StopCoroutine(waitLoopCoroutine);
- waitLoopCoroutine = null;
- }
- waitLoopCoroutine = StartCoroutine(WaitForFirstLoopOnActiveState());
- }
-
- private IEnumerator WaitForFirstLoopOnActiveState()
- {
- // wait a frame to ensure StateMachine has activated the correct state GameObject
- yield return null;
-
- // find the active child under the StateMachine (the current state)
- Transform smTransform = stateMachine != null ? stateMachine.transform : transform;
- Transform activeState = null;
- for (int i = 0; i < smTransform.childCount; i++)
- {
- var child = smTransform.GetChild(i);
- if (child.gameObject.activeInHierarchy)
+ if (playTutorial)
{
- activeState = child;
- break;
+ // pause the game, hide UI, and register for input overrides
+ GameManager.Instance.RequestPause(this);
+ UIPageController.Instance.HideAllUI();
+ InputManager.Instance.RegisterOverrideConsumer(this);
+
+ // Setup references
+ _stateMachine = GetComponentInChildren();
+ _stateMachine.OnLastStateExited.AddListener(RemoveTutorial);
+
+ // prepare gating for the initial active state
+ SetupInputGateForCurrentState();
+ }
+ else
+ {
+ RemoveTutorial();
}
}
- if (activeState == null)
+ void RemoveTutorial()
{
- // if we can't find an active state, fail open: allow input
- canAcceptInput = true;
- yield break;
- }
-
- // look for a legacy Animation component on the active state
- var anim = activeState.GetComponent();
- if (anim == null)
- {
- // no animation to wait for; allow input immediately
- canAcceptInput = true;
- yield break;
- }
-
- // determine a clip/state to observe
- string clipName = anim.clip != null ? anim.clip.name : null;
- AnimationState observedState = null;
-
- if (!string.IsNullOrEmpty(clipName))
- {
- observedState = anim[clipName];
- }
- else
- {
- // fallback: take the first enabled state in the Animation
- foreach (AnimationState st in anim)
+ Debug.Log("Remove me!");
+ if (_waitLoopCoroutine != null)
{
- observedState = st;
- break;
+ StopCoroutine(_waitLoopCoroutine);
+ _waitLoopCoroutine = null;
+ }
+
+ // Unpause, unregister input, and show UI
+ InputManager.Instance.UnregisterOverrideConsumer(this);
+ UIPageController.Instance.ShowAllUI();
+ GameManager.Instance.ReleasePause(this);
+
+ // hide prompt if present
+ if (tapPrompt != null)
+ tapPrompt.SetActive(false);
+
+ Destroy(gameObject);
+ }
+
+ public void OnTap(Vector2 position)
+ {
+ if (!_canAcceptInput) return; // block taps until allowed
+
+ // consume this tap and immediately block further taps
+ SetInputEnabled(false);
+
+ // move to next state
+ _stateMachine.Next(true);
+
+ // after the state changes, set up gating for the new active state's animation
+ SetupInputGateForCurrentState();
+ }
+
+ public void OnHoldStart(Vector2 position)
+ {
+ }
+
+ public void OnHoldMove(Vector2 position)
+ {
+ }
+
+ public void OnHoldEnd(Vector2 position)
+ {
+ }
+
+ // centralize enabling/disabling input and the tap prompt
+ private void SetInputEnabled(bool allow)
+ {
+ _canAcceptInput = allow;
+ if (tapPrompt != null)
+ {
+ tapPrompt.SetActive(allow);
}
}
- if (observedState == null)
+ private void SetupInputGateForCurrentState()
{
- // nothing to observe; allow input
- canAcceptInput = true;
- yield break;
+ if (_waitLoopCoroutine != null)
+ {
+ StopCoroutine(_waitLoopCoroutine);
+ _waitLoopCoroutine = null;
+ }
+ _waitLoopCoroutine = StartCoroutine(WaitForFirstLoopOnActiveState());
}
- // wait until the animation starts playing the observed clip
- float safetyTimer = 0f;
- while (anim.isActiveAndEnabled && activeState.gameObject.activeInHierarchy && !anim.IsPlaying(observedState.name) && safetyTimer < 2f)
+ private IEnumerator WaitForFirstLoopOnActiveState()
{
- safetyTimer += Time.deltaTime;
+ // wait a frame to ensure StateMachine has activated the correct state GameObject
yield return null;
- }
- // wait until the first loop completes (normalizedTime >= 1)
- while (anim.isActiveAndEnabled && activeState.gameObject.activeInHierarchy)
- {
- // if state changed (not playing anymore), allow input to avoid deadlock
- if (!anim.IsPlaying(observedState.name)) break;
-
- if (observedState.normalizedTime >= 1f)
+ // find the active child under the StateMachine (the current state)
+ Transform smTransform = _stateMachine != null ? _stateMachine.transform : transform;
+ Transform activeState = null;
+ for (int i = 0; i < smTransform.childCount; i++)
{
- break;
+ var child = smTransform.GetChild(i);
+ if (child.gameObject.activeInHierarchy)
+ {
+ activeState = child;
+ break;
+ }
}
- yield return null;
- }
- canAcceptInput = true;
- waitLoopCoroutine = null;
+ if (activeState == null)
+ {
+ // if we can't find an active state, fail open: allow input
+ SetInputEnabled(true);
+ yield break;
+ }
+
+ // look for a legacy Animation component on the active state
+ var anim = activeState.GetComponent();
+ if (anim == null)
+ {
+ // no animation to wait for; allow input immediately
+ SetInputEnabled(true);
+ yield break;
+ }
+
+ // determine a clip/state to observe
+ string clipName = anim.clip != null ? anim.clip.name : null;
+ AnimationState observedState = null;
+
+ if (!string.IsNullOrEmpty(clipName))
+ {
+ observedState = anim[clipName];
+ }
+ else
+ {
+ // fallback: take the first enabled state in the Animation
+ foreach (AnimationState st in anim)
+ {
+ observedState = st;
+ break;
+ }
+ }
+
+ if (observedState == null)
+ {
+ // nothing to observe; allow input
+ SetInputEnabled(true);
+ yield break;
+ }
+
+ // wait until the animation starts playing the observed clip
+ float safetyTimer = 0f;
+ while (anim.isActiveAndEnabled && activeState.gameObject.activeInHierarchy && !anim.IsPlaying(observedState.name) && safetyTimer < 2f)
+ {
+ safetyTimer += Time.deltaTime;
+ yield return null;
+ }
+
+ // wait until the first loop completes (normalizedTime >= 1)
+ while (anim.isActiveAndEnabled && activeState.gameObject.activeInHierarchy)
+ {
+ // if state changed (not playing anymore), allow input to avoid deadlock
+ if (!anim.IsPlaying(observedState.name)) break;
+
+ if (observedState.normalizedTime >= 1f)
+ {
+ break;
+ }
+ yield return null;
+ }
+
+ SetInputEnabled(true);
+ _waitLoopCoroutine = null;
+ }
}
}