From ef3b4bf36986fc084708b8a1909fe1d3b7ef7ff8 Mon Sep 17 00:00:00 2001 From: Michal Adam Pikulski Date: Thu, 23 Oct 2025 09:31:09 +0200 Subject: [PATCH] Clean up IPausable interafaces a little bit and start refactoring the pause-game flow in the minigame --- Assets/Scripts/Core/GameManager.cs | 493 ++++++++---------- Assets/Scripts/Core/Interfaces/IPausable.cs | 5 - Assets/Scripts/Core/SettingsAccess.cs | 3 +- .../DivingForPictures/Bubbles/Bubble.cs | 18 +- .../Bubbles/BubbleSpawner.cs | 20 +- .../DivingForPictures/DivingGameManager.cs | 247 ++++----- .../Obstacles/FloatingObstacle.cs | 18 +- .../Obstacles/ObstacleSpawner.cs | 29 +- .../Player/PlayerController.cs | 112 ++-- .../Player/WobbleBehavior.cs | 1 + .../Tiles/TrenchTileSpawner.cs | 24 +- .../Utilities/BottlePauser.cs | 6 - .../DivingForPictures/Utilities/RockPauser.cs | 6 - Assets/Scripts/Movement/FollowerController.cs | 1 + Assets/Scripts/UI/PauseMenu.cs | 19 +- 15 files changed, 423 insertions(+), 579 deletions(-) diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs index daf66e07..b6db57ae 100644 --- a/Assets/Scripts/Core/GameManager.cs +++ b/Assets/Scripts/Core/GameManager.cs @@ -1,304 +1,255 @@ -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 UI; +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; - - [Header("Settings Status")] - [SerializeField] private bool _settingsLoaded = false; - [SerializeField] private bool _developerSettingsLoaded = false; - public bool SettingsLoaded => _settingsLoaded; - public bool DeveloperSettingsLoaded => _developerSettingsLoaded; - - [Header("Game State")] - [SerializeField] private bool _isPaused = false; - - /// - /// 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; - - void Awake() + public class GameManager : MonoBehaviour { - _instance = this; + // Singleton implementation + private static GameManager _instance; + public static GameManager Instance => _instance; + private static bool _isQuitting = false; - // Create settings provider if it doesn't exist - SettingsProvider.Instance.gameObject.name = "Settings Provider"; + private bool _settingsLoaded = false; + private bool _developerSettingsLoaded = false; - // Create developer settings provider if it doesn't exist - DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider"; - - // Load all settings synchronously during Awake - InitializeSettings(); - InitializeDeveloperSettings(); - - // Register for post-boot initialization - BootCompletionService.RegisterInitAction(InitializePostBoot); - - // DontDestroyOnLoad(gameObject); - } + // Pausable implementation + private bool _isPaused = false; + public bool IsPaused => _isPaused; - private void InitializePostBoot() - { - // Find and subscribe to PauseMenu events - PauseMenu pauseMenu = PauseMenu.Instance; - if (pauseMenu != null) + // 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; + + void Awake() { - pauseMenu.OnGamePaused += OnPauseMenuPaused; - pauseMenu.OnGameResumed += OnPauseMenuResumed; + _instance = this; + + // Create settings providers if it doesn't exist + SettingsProvider.Instance.gameObject.name = "Settings Provider"; + DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider"; + + // Load all settings synchronously during Awake + InitializeSettings(); + InitializeDeveloperSettings(); + + // Register for post-boot initialization + BootCompletionService.RegisterInitAction(InitializePostBoot); + + // DontDestroyOnLoad(gameObject); + } + + private void InitializePostBoot() + { + // For post-boot correct initialization order + } + + /// + /// 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)) + { + _pausableComponents.Add(component); - Logging.Debug("[GameManager] Subscribed to PauseMenu events"); - } - 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)) - { - _pausableComponents.Add(component); + // If the game is already paused, pause the component immediately + if (_isPaused) + { + component.Pause(); + } - // If the game is already paused, pause the component immediately - if (_isPaused) + 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"}"); + } + } + + // TODO: Revisit this with proper pause menu request implementation + public void RequestGamePause() + { + PauseGame(); + } + + public void RequestGameResume() + { + ResumeGame(); + } + + /// + /// Pause the game and notify all registered pausable components + /// + private 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 + /// + private 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."); + } + + 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) + { + ServiceLocator.Register(playerSettings); + Logging.Debug("PlayerFollowerSettings registered successfully"); + } + else + { + Debug.LogError("Failed to load PlayerFollowerSettings"); + } - 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"}"); - } - } - - /// - /// 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) - { - 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 + + void OnApplicationQuit() { - Logging.Warning("Some developer settings failed to load"); + _isQuitting = true; + ServiceLocator.Clear(); } - } - void OnApplicationQuit() - { - _isQuitting = true; - ServiceLocator.Clear(); - } + // Helper method to get settings + private T GetSettings() where T : class + { + return ServiceLocator.Get(); + } - // 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..bda726c8 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,8 @@ namespace Minigames.DivingForPictures /// public void Pause() { - if (_isPaused) return; // Already paused - - _isPaused = true; + if (GameManager.Instance.IsPaused) return; // Already paused + StopBubbleBehavior(); // Debug log for troubleshooting @@ -81,9 +74,8 @@ namespace Minigames.DivingForPictures /// public void DoResume() { - if (!_isPaused) return; // Already running - - _isPaused = false; + if (!GameManager.Instance.IsPaused) return; // Already running + StartBubbleBehavior(); // Debug log for troubleshooting @@ -95,7 +87,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..a75ae6b3 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,9 +81,7 @@ namespace Minigames.DivingForPictures /// public void Pause() { - if (_isPaused) return; // Already paused - - _isPaused = true; + if (GameManager.Instance.IsPaused) return; // Already paused // Stop spawning coroutine if (_spawnCoroutine != null) @@ -116,9 +108,7 @@ namespace Minigames.DivingForPictures /// public void DoResume() { - if (!_isPaused) return; // Already running - - _isPaused = false; + if (!GameManager.Instance.IsPaused) return; // Already running // Restart spawning coroutine StartSpawningCoroutine(); @@ -141,7 +131,7 @@ namespace Minigames.DivingForPictures /// private void StartSpawningCoroutine() { - if (_spawnCoroutine == null && !_isPaused) + if (_spawnCoroutine == null && !GameManager.Instance.IsPaused) { _spawnCoroutine = StartCoroutine(SpawnBubblesRoutine()); } @@ -219,7 +209,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 +252,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..617fb3ff 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs @@ -7,7 +7,7 @@ using Minigames.DivingForPictures.PictureCamera; using System; using System.Collections; using System.Collections.Generic; -using System.Linq; +using Bootstrap; using UI; using UnityEngine; using UnityEngine.Events; @@ -38,24 +38,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 +67,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 +77,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 +95,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 +106,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) { @@ -133,44 +126,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 +146,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 +155,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 +199,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 +221,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 +248,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 +264,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 +315,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 +331,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 +345,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 +357,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 +368,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 +381,7 @@ namespace Minigames.DivingForPictures /// public void ForceBreakRope() { - if (!isGameOver) + if (!_isGameOver) { OnPlayerDamageTaken(); } @@ -412,9 +392,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 +430,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) @@ -478,7 +458,7 @@ namespace Minigames.DivingForPictures _isSurfacing = true; // 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 +477,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 +545,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 +629,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 +666,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 +674,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 +682,7 @@ namespace Minigames.DivingForPictures } } - activeMonsters.Clear(); + _activeMonsters.Clear(); // 1) Call the booster pack giver if available bool completed = false; @@ -735,7 +714,7 @@ namespace Minigames.DivingForPictures 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 +723,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 +736,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 +772,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(); } @@ -825,9 +804,7 @@ namespace Minigames.DivingForPictures public void DoPause(bool turnOffGameInput = true) { - if (_isPaused) return; // Already paused - - _isPaused = true; + if (GameManager.Instance.IsPaused) return; // Already paused // Pause all registered components foreach (var component in _pausableComponents) @@ -847,9 +824,7 @@ namespace Minigames.DivingForPictures /// public void DoResume() { - if (!_isPaused) return; // Already running - - _isPaused = false; + if (!GameManager.Instance.IsPaused) return; // Already running // Resume all registered components foreach (var component in _pausableComponents) @@ -938,23 +913,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 +1036,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..8de4ecce 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,8 @@ namespace Minigames.DivingForPictures /// public void Pause() { - if (_isPaused) return; // Already paused - - _isPaused = true; + if (GameManager.Instance.IsPaused) return; // Already paused + StopObstacleCoroutines(); Logging.Debug($"[FloatingObstacle] Paused obstacle: {name}"); @@ -156,9 +149,8 @@ namespace Minigames.DivingForPictures /// public void DoResume() { - if (!_isPaused) return; // Already running - - _isPaused = false; + if (!GameManager.Instance.IsPaused) return; // Already running + 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..7ab4e7e4 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,9 +121,7 @@ namespace Minigames.DivingForPictures /// public void Pause() { - if (_isPaused) return; // Already paused - - _isPaused = true; + if (GameManager.Instance.IsPaused) return; // Already paused // Stop spawning coroutine if (_spawnCoroutine != null) @@ -159,9 +151,8 @@ namespace Minigames.DivingForPictures /// public void DoResume() { - if (!_isPaused) return; // Already running - - _isPaused = false; + if (!GameManager.Instance.IsPaused) return; // Already running + // Restart spawning coroutine if not in surfacing mode if (!_isSurfacing) @@ -190,7 +181,7 @@ namespace Minigames.DivingForPictures /// private void StartSpawnCoroutine() { - if (_spawnCoroutine == null && !_isPaused && !_isSurfacing) + if (_spawnCoroutine == null && !GameManager.Instance.IsPaused && !_isSurfacing) { _spawnCoroutine = StartCoroutine(SpawnObstacleRoutine()); } @@ -201,7 +192,7 @@ namespace Minigames.DivingForPictures /// private void StartMoveCoroutine() { - if (_moveCoroutine == null && !_isPaused) + if (_moveCoroutine == null && !GameManager.Instance.IsPaused) { _moveCoroutine = StartCoroutine(MoveObstaclesRoutine()); } @@ -212,7 +203,7 @@ namespace Minigames.DivingForPictures /// private void StartDespawnCoroutine() { - if (_despawnCoroutine == null && !_isPaused) + if (_despawnCoroutine == null && !GameManager.Instance.IsPaused) { _despawnCoroutine = StartCoroutine(DespawnObstaclesRoutine()); } @@ -553,7 +544,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 +668,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 +698,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 +720,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..ce747d2c 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,21 @@ 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 (GameManager.Instance.IsPaused) return; // 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 +300,9 @@ namespace Minigames.DivingForPictures.Player /// public void DoResume() { - if (!isPaused) return; - - isPaused = false; + if (!GameManager.Instance.IsPaused) return; 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..2ee5c50d 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,9 +185,7 @@ namespace Minigames.DivingForPictures /// public void Pause() { - if (_isPaused) return; // Already paused - - _isPaused = true; + if (GameManager.Instance.IsPaused) return; // Already paused // Stop all active coroutines but save their references if (_movementCoroutine != null) @@ -230,9 +220,7 @@ namespace Minigames.DivingForPictures /// public void DoResume() { - if (!_isPaused) return; // Already running - - _isPaused = false; + if (!GameManager.Instance.IsPaused) return; // Already running // Restart all necessary coroutines StartMovementCoroutine(); @@ -500,7 +488,7 @@ namespace Minigames.DivingForPictures /// private void StartMovementCoroutine() { - if (_movementCoroutine == null && !_isPaused) + if (_movementCoroutine == null && !GameManager.Instance.IsPaused) { _movementCoroutine = StartCoroutine(MoveActiveTilesRoutine()); } @@ -513,7 +501,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 +542,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/PauseMenu.cs b/Assets/Scripts/UI/PauseMenu.cs index 507d28ac..3046fac7 100644 --- a/Assets/Scripts/UI/PauseMenu.cs +++ b/Assets/Scripts/UI/PauseMenu.cs @@ -24,15 +24,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() { @@ -103,7 +94,7 @@ namespace UI /// public void ShowPauseMenu() { - if (_isPaused) return; + if (GameManager.Instance.IsPaused) return; if (UIPageController.Instance != null) { UIPageController.Instance.PushPage(this); @@ -130,7 +121,7 @@ namespace UI /// public void HidePauseMenu(bool resetInput = true) { - if (!_isPaused) + if (!GameManager.Instance.IsPaused) { // Ensure UI is hidden if somehow active without state if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false); @@ -169,19 +160,17 @@ namespace UI private void BeginPauseSideEffects() { - _isPaused = true; if (pauseButton != null) pauseButton.SetActive(false); InputManager.Instance.SetInputMode(InputMode.UI); - OnGamePaused?.Invoke(); + GameManager.Instance.RequestGamePause(); Logging.Debug("[PauseMenu] Game Paused"); } private void EndPauseSideEffects(bool invokeEvent) { - _isPaused = false; if (pauseButton != null) pauseButton.SetActive(true); InputManager.Instance.SetInputMode(InputMode.GameAndUI); - if (invokeEvent) OnGameResumed?.Invoke(); + GameManager.Instance.RequestGameResume(); Logging.Debug("[PauseMenu] Game Resumed"); }