From 8b96a5d0c321eaaa31a98cb98bf664cce3e78208 Mon Sep 17 00:00:00 2001 From: AlexanderT Date: Wed, 24 Sep 2025 12:21:21 +0200 Subject: [PATCH] IMplement basic Developer Settings --- Assets/Editor/EditorSettingsProvider.cs | 8 +- Assets/Editor/SettingsEditorWindow.cs | 4 +- Assets/Scripts/Core/GameManager.cs | 71 +++++- .../Core/Settings/BaseDeveloperSettings.cs | 19 ++ .../Settings/BaseDeveloperSettings.cs.meta | 3 + .../Settings/DeveloperSettingsProvider.cs | 95 ++++++++ .../DeveloperSettingsProvider.cs.meta | 3 + .../Core/Settings/DivingDeveloperSettings.cs | 127 +++++++++++ .../Settings/DivingDeveloperSettings.cs.meta | 3 + .../Core/Settings/DivingMinigameSettings.cs | 210 ++++++++++++++++++ ...cs.meta => DivingMinigameSettings.cs.meta} | 0 .../Scripts/Core/Settings/MinigameSettings.cs | 49 ---- .../Core/Settings/SettingsInterfaces.cs | 41 +++- .../Bubbles/BubbleSpawner.cs | 61 +++-- .../DivingForPictures/DivingGameManager.cs | 64 +++--- .../Obstacles/ObstacleSpawner.cs | 118 +++++----- .../Player/PlayerController.cs | 39 ++-- .../Tiles/TrenchTileSpawner.cs | 72 +++--- 18 files changed, 739 insertions(+), 248 deletions(-) create mode 100644 Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs create mode 100644 Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs.meta create mode 100644 Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs create mode 100644 Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs.meta create mode 100644 Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs create mode 100644 Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs.meta create mode 100644 Assets/Scripts/Core/Settings/DivingMinigameSettings.cs rename Assets/Scripts/Core/Settings/{MinigameSettings.cs.meta => DivingMinigameSettings.cs.meta} (100%) delete mode 100644 Assets/Scripts/Core/Settings/MinigameSettings.cs diff --git a/Assets/Editor/EditorSettingsProvider.cs b/Assets/Editor/EditorSettingsProvider.cs index de6121b1..6c102515 100644 --- a/Assets/Editor/EditorSettingsProvider.cs +++ b/Assets/Editor/EditorSettingsProvider.cs @@ -12,7 +12,7 @@ namespace AppleHills.Editor { private static PlayerFollowerSettings _playerFollowerSettings; private static InteractionSettings _interactionSettings; - private static MinigameSettings _minigameSettings; + private static DivingMinigameSettings _divingMinigameSettings; // Static constructor will be called when Unity loads/reloads scripts static EditorSettingsProvider() @@ -53,7 +53,7 @@ namespace AppleHills.Editor { _playerFollowerSettings = AssetDatabase.LoadAssetAtPath("Assets/Settings/PlayerFollowerSettings.asset"); _interactionSettings = AssetDatabase.LoadAssetAtPath("Assets/Settings/InteractionSettings.asset"); - _minigameSettings = AssetDatabase.LoadAssetAtPath("Assets/Settings/MinigameSettings.asset"); + _divingMinigameSettings = AssetDatabase.LoadAssetAtPath("Assets/Settings/MinigameSettings.asset"); // Re-register the delegates in case they were lost AppleHills.SettingsAccess.SetupEditorProviders( @@ -88,8 +88,8 @@ namespace AppleHills.Editor return _playerFollowerSettings as T; else if (typeof(T) == typeof(InteractionSettings)) return _interactionSettings as T; - else if (typeof(T) == typeof(MinigameSettings)) - return _minigameSettings as T; + else if (typeof(T) == typeof(DivingMinigameSettings)) + return _divingMinigameSettings as T; return null; } diff --git a/Assets/Editor/SettingsEditorWindow.cs b/Assets/Editor/SettingsEditorWindow.cs index 03a92475..c5c32407 100644 --- a/Assets/Editor/SettingsEditorWindow.cs +++ b/Assets/Editor/SettingsEditorWindow.cs @@ -47,7 +47,7 @@ namespace AppleHills.Core.Settings.Editor // If any settings are missing, create them CreateSettingsIfMissing("PlayerFollowerSettings"); CreateSettingsIfMissing("InteractionSettings"); - CreateSettingsIfMissing("MinigameSettings"); + CreateSettingsIfMissing("MinigameSettings"); } private void CreateSettingsIfMissing(string fileName) where T : BaseSettings @@ -112,7 +112,7 @@ namespace AppleHills.Core.Settings.Editor DrawSettingsEditor(); break; case 2: // Minigames - DrawSettingsEditor(); + DrawSettingsEditor(); break; } diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs index 8061edf9..de19a105 100644 --- a/Assets/Scripts/Core/GameManager.cs +++ b/Assets/Scripts/Core/GameManager.cs @@ -33,7 +33,9 @@ public class GameManager : MonoBehaviour [Header("Settings Status")] [SerializeField] private bool _settingsLoaded = false; + [SerializeField] private bool _developerSettingsLoaded = false; public bool SettingsLoaded => _settingsLoaded; + public bool DeveloperSettingsLoaded => _developerSettingsLoaded; void Awake() { @@ -42,8 +44,12 @@ public class GameManager : MonoBehaviour // Create settings provider if it doesn't exist SettingsProvider.Instance.gameObject.name = "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(); // DontDestroyOnLoad(gameObject); } @@ -55,7 +61,7 @@ public class GameManager : MonoBehaviour // Load settings synchronously var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); var interactionSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); - var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); + var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); // Register settings with service locator if (playerSettings != null) @@ -80,7 +86,7 @@ public class GameManager : MonoBehaviour if (minigameSettings != null) { - ServiceLocator.Register(minigameSettings); + ServiceLocator.Register(minigameSettings); Debug.Log("MinigameSettings registered successfully"); } else @@ -100,6 +106,28 @@ public class GameManager : MonoBehaviour } } + /// + /// Check for and initialize developer settings. + /// + private void InitializeDeveloperSettings() + { + Debug.Log("Starting developer settings initialization..."); + + // Load developer settings + var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings(); + + _developerSettingsLoaded = divingDevSettings != null; + + if (_developerSettingsLoaded) + { + Debug.Log("All developer settings loaded successfully"); + } + else + { + Debug.LogWarning("Some developer settings failed to load"); + } + } + void OnApplicationQuit() { _isQuitting = true; @@ -112,6 +140,26 @@ public class GameManager : MonoBehaviour 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 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(); + } + // PLAYER & FOLLOWER SETTINGS // Player settings @@ -178,9 +226,18 @@ public class GameManager : MonoBehaviour // MINIGAME SETTINGS // Endless Descender settings - public float EndlessDescenderLerpSpeed => GetSettings()?.EndlessDescenderLerpSpeed ?? 12f; - public float EndlessDescenderMaxOffset => GetSettings()?.EndlessDescenderMaxOffset ?? 3f; - public float EndlessDescenderClampXMin => GetSettings()?.EndlessDescenderClampXMin ?? -3.5f; - public float EndlessDescenderClampXMax => GetSettings()?.EndlessDescenderClampXMax ?? 3.5f; - public float EndlessDescenderSpeedExponent => GetSettings()?.EndlessDescenderSpeedExponent ?? 2.5f; + public float EndlessDescenderLerpSpeed => GetSettings()?.EndlessDescenderLerpSpeed ?? 12f; + public float EndlessDescenderMaxOffset => GetSettings()?.EndlessDescenderMaxOffset ?? 3f; + public float EndlessDescenderClampXMin => GetSettings()?.EndlessDescenderClampXMin ?? -3.5f; + public float EndlessDescenderClampXMax => GetSettings()?.EndlessDescenderClampXMax ?? 3.5f; + public float EndlessDescenderSpeedExponent => GetSettings()?.EndlessDescenderSpeedExponent ?? 2.5f; + public float EndlessDescenderTapMaxDistance => GetSettings()?.EndlessDescenderTapMaxDistance ?? 0.5f; + public float EndlessDescenderTapDecelerationRate => GetSettings()?.EndlessDescenderTapDecelerationRate ?? 5.0f; + public int EndlessDescenderInitialTileCount => GetSettings()?.EndlessDescenderInitialTileCount ?? 3; + public float EndlessDescenderTileSpawnBuffer => GetSettings()?.EndlessDescenderTileSpawnBuffer ?? 1f; + public float EndlessDescenderMoveSpeed => GetSettings()?.EndlessDescenderMoveSpeed ?? 3f; + public float EndlessDescenderSpeedUpFactor => GetSettings()?.EndlessDescenderSpeedUpFactor ?? 0.2f; + public float EndlessDescenderSpeedUpInterval => GetSettings()?.EndlessDescenderSpeedUpInterval ?? 10f; + public float EndlessDescenderMaxMoveSpeed => GetSettings()?.EndlessDescenderMaxMoveSpeed ?? 12f; + public float EndlessDescenderVelocityCalculationInterval => GetSettings()?.EndlessDescenderVelocityCalculationInterval ?? 0.5f; } diff --git a/Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs b/Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs new file mode 100644 index 00000000..d75dc495 --- /dev/null +++ b/Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace AppleHills.Core.Settings +{ + /// + /// Base abstract class for all developer settings. + /// Developer settings are intended for technical configuration rather than gameplay/design values. + /// + public abstract class BaseDeveloperSettings : ScriptableObject + { + /// + /// Called to validate settings values when they are changed in the inspector. + /// + public virtual void OnValidate() + { + // Base implementation does nothing, override in derived classes + } + } +} diff --git a/Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs.meta b/Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs.meta new file mode 100644 index 00000000..ced7cb46 --- /dev/null +++ b/Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 50def2e6e95a4830b57f3e1b76a4df51 +timeCreated: 1758707161 \ No newline at end of file diff --git a/Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs b/Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs new file mode 100644 index 00000000..2612ed08 --- /dev/null +++ b/Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace AppleHills.Core.Settings +{ + /// + /// Provides access to developer settings for technical configuration rather than gameplay parameters. + /// Follows the singleton pattern for global access. + /// + public class DeveloperSettingsProvider : MonoBehaviour + { + private static DeveloperSettingsProvider _instance; + + /// + /// Singleton instance of the provider. + /// + public static DeveloperSettingsProvider Instance + { + get + { + if (_instance == null && Application.isPlaying) + { + _instance = FindFirstObjectByType(); + + if (_instance == null) + { + GameObject go = new GameObject("DeveloperSettingsProvider"); + _instance = go.AddComponent(); + // Don't destroy between scenes + DontDestroyOnLoad(go); + } + } + + return _instance; + } + } + + // Dictionary to cache loaded settings + private Dictionary _settingsCache = new Dictionary(); + + // Default developer settings stored in the Resources folder + [SerializeField] private string _resourcesPath = "Settings/Developer"; + + private void Awake() + { + if (_instance != null && _instance != this) + { + Destroy(gameObject); + return; + } + + _instance = this; + DontDestroyOnLoad(gameObject); + + // Initialize settings cache + _settingsCache = new Dictionary(); + } + + /// + /// Gets or loads developer settings of the specified type. + /// + /// Type of developer settings to retrieve + /// The settings instance or null if not found + public T GetSettings() where T : BaseDeveloperSettings + { + System.Type type = typeof(T); + + // Return from cache if available + if (_settingsCache.TryGetValue(type, out BaseDeveloperSettings cachedSettings)) + { + return cachedSettings as T; + } + + // Load from Resources if not cached + T settings = Resources.Load($"{_resourcesPath}/{type.Name}"); + + if (settings != null) + { + _settingsCache[type] = settings; + return settings; + } + + Debug.LogWarning($"Developer settings of type {type.Name} not found in Resources/{_resourcesPath}"); + return null; + } + + /// + /// Clears the settings cache, forcing settings to be reloaded. + /// + public void ClearCache() + { + _settingsCache.Clear(); + } + } +} diff --git a/Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs.meta b/Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs.meta new file mode 100644 index 00000000..f3f739f7 --- /dev/null +++ b/Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f9945aa4a563434e973ab49176259150 +timeCreated: 1758707186 \ No newline at end of file diff --git a/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs b/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs new file mode 100644 index 00000000..708bd41e --- /dev/null +++ b/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs @@ -0,0 +1,127 @@ +using UnityEngine; + +namespace AppleHills.Core.Settings +{ + /// + /// Developer settings for the diving minigame technical configuration. + /// These settings are separate from gameplay/design settings and focus on technical implementation details. + /// + [CreateAssetMenu(fileName = "DivingDeveloperSettings", menuName = "AppleHills/Developer Settings/Diving", order = 1)] + public class DivingDeveloperSettings : BaseDeveloperSettings + { + [Header("Bubble System")] + [Tooltip("Object pooling enabled for bubbles")] + [SerializeField] private bool bubbleUseObjectPooling = true; + + [Tooltip("Initial number of bubbles to pre-allocate in pool")] + [SerializeField] private int bubbleInitialPoolSize = 10; + + [Tooltip("Maximum number of bubbles allowed in pool")] + [SerializeField] private int bubbleMaxPoolSize = 30; + + [Tooltip("Default spawn interval for bubbles in seconds")] + [SerializeField] private float bubbleSpawnInterval = 0.3f; + + [Tooltip("Range of possible bubble movement speeds (min, max)")] + [SerializeField] private Vector2 bubbleSpeedRange = new Vector2(0.5f, 2f); + + [Tooltip("Range of possible bubble scale factors (min, max)")] + [SerializeField] private Vector2 bubbleScaleRange = new Vector2(0.3f, 0.7f); + + [Tooltip("Range of possible bubble wobble speeds (min, max)")] + [SerializeField] private Vector2 bubbleWobbleSpeedRange = new Vector2(1f, 3f); + + [Tooltip("Range of possible bubble wobble amounts (min, max)")] + [SerializeField] private Vector2 bubbleWobbleAmountRange = new Vector2(0.05f, 0.15f); + + [Tooltip("Minimum X position for bubble spawning")] + [SerializeField] private float bubbleSpawnXMin = -3.5f; + + [Tooltip("Maximum X position for bubble spawning")] + [SerializeField] private float bubbleSpawnXMax = 3.5f; + + [Tooltip("Y position for bubble spawning")] + [SerializeField] private float bubbleSpawnY = -5f; + + [Tooltip("Minimum scale factor during wobble animation")] + [SerializeField] private float bubbleWobbleMinScale = 0.2f; + + [Tooltip("Maximum scale factor during wobble animation")] + [SerializeField] private float bubbleWobbleMaxScale = 1.2f; + + [Tooltip("Factor to multiply bubble speed by when surfacing")] + [SerializeField] private float bubbleSurfacingSpeedFactor = 0.5f; + + [Header("Obstacle System")] + [Tooltip("Layer for obstacles to be placed on")] + [SerializeField] private int obstacleLayer = 9; + + [Tooltip("Layer mask for tile collision detection during obstacle spawn validation")] + [SerializeField] private LayerMask obstacleTileLayerMask = -1; + + [Tooltip("Whether to use object pooling for obstacles")] + [SerializeField] private bool obstacleUseObjectPooling = true; + + [Tooltip("Maximum objects per prefab type in obstacle pool")] + [SerializeField] private int obstacleMaxPerPrefabPoolSize = 3; + + [Tooltip("Total maximum size of obstacle pool across all prefab types")] + [SerializeField] private int obstacleTotalMaxPoolSize = 15; + + // Bubble properties access + public bool BubbleUseObjectPooling => bubbleUseObjectPooling; + public int BubbleInitialPoolSize => bubbleInitialPoolSize; + public int BubbleMaxPoolSize => bubbleMaxPoolSize; + public float BubbleSpawnInterval => bubbleSpawnInterval; + public Vector2 BubbleSpeedRange => bubbleSpeedRange; + public Vector2 BubbleScaleRange => bubbleScaleRange; + public Vector2 BubbleWobbleSpeedRange => bubbleWobbleSpeedRange; + public Vector2 BubbleWobbleAmountRange => bubbleWobbleAmountRange; + public float BubbleSpawnXMin => bubbleSpawnXMin; + public float BubbleSpawnXMax => bubbleSpawnXMax; + public float BubbleSpawnY => bubbleSpawnY; + public float BubbleWobbleMinScale => bubbleWobbleMinScale; + public float BubbleWobbleMaxScale => bubbleWobbleMaxScale; + public float BubbleSurfacingSpeedFactor => bubbleSurfacingSpeedFactor; + + // Obstacle properties access + public int ObstacleLayer => obstacleLayer; + public LayerMask ObstacleTileLayerMask => obstacleTileLayerMask; + public bool ObstacleUseObjectPooling => obstacleUseObjectPooling; + public int ObstacleMaxPerPrefabPoolSize => obstacleMaxPerPrefabPoolSize; + public int ObstacleTotalMaxPoolSize => obstacleTotalMaxPoolSize; + + public override void OnValidate() + { + base.OnValidate(); + + // Validate bubble settings + bubbleInitialPoolSize = Mathf.Max(1, bubbleInitialPoolSize); + bubbleMaxPoolSize = Mathf.Max(bubbleInitialPoolSize, bubbleMaxPoolSize); + bubbleSpawnInterval = Mathf.Max(0.05f, bubbleSpawnInterval); + bubbleSpeedRange = new Vector2( + Mathf.Max(0.1f, bubbleSpeedRange.x), + Mathf.Max(bubbleSpeedRange.x, bubbleSpeedRange.y) + ); + bubbleScaleRange = new Vector2( + Mathf.Max(0.1f, bubbleScaleRange.x), + Mathf.Max(bubbleScaleRange.x, bubbleScaleRange.y) + ); + bubbleWobbleSpeedRange = new Vector2( + Mathf.Max(0.1f, bubbleWobbleSpeedRange.x), + Mathf.Max(bubbleWobbleSpeedRange.x, bubbleWobbleSpeedRange.y) + ); + bubbleWobbleAmountRange = new Vector2( + Mathf.Max(0.01f, bubbleWobbleAmountRange.x), + Mathf.Max(bubbleWobbleAmountRange.x, bubbleWobbleAmountRange.y) + ); + bubbleWobbleMinScale = Mathf.Max(0.01f, bubbleWobbleMinScale); + bubbleWobbleMaxScale = Mathf.Max(bubbleWobbleMinScale, bubbleWobbleMaxScale); + bubbleSurfacingSpeedFactor = Mathf.Max(0.01f, bubbleSurfacingSpeedFactor); + + // Validate obstacle settings + obstacleMaxPerPrefabPoolSize = Mathf.Max(1, obstacleMaxPerPrefabPoolSize); + obstacleTotalMaxPoolSize = Mathf.Max(obstacleMaxPerPrefabPoolSize, obstacleTotalMaxPoolSize); + } + } +} diff --git a/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs.meta b/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs.meta new file mode 100644 index 00000000..d3387e02 --- /dev/null +++ b/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 033961b12e7b4289838d554c2264bacd +timeCreated: 1758707215 \ No newline at end of file diff --git a/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs new file mode 100644 index 00000000..769f9618 --- /dev/null +++ b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs @@ -0,0 +1,210 @@ +using UnityEngine; + +namespace AppleHills.Core.Settings +{ + /// + /// Settings related to minigames + /// + [CreateAssetMenu(fileName = "MinigameSettings", menuName = "AppleHills/Settings/Minigames", order = 3)] + public class DivingMinigameSettings : BaseSettings, IDivingMinigameSettings + { + [Header("Endless Descender - Basic Movement")] + [Tooltip("How quickly the character follows the finger horizontally (higher = more responsive)")] + [SerializeField] private float endlessDescenderLerpSpeed = 12f; + + [Tooltip("Maximum horizontal offset allowed between character and finger position")] + [SerializeField] private float endlessDescenderMaxOffset = 3f; + + [Tooltip("Minimum allowed X position for endless descender movement")] + [SerializeField] private float endlessDescenderClampXMin = -3.5f; + + [Tooltip("Maximum allowed X position for endless descender movement")] + [SerializeField] private float endlessDescenderClampXMax = 3.5f; + + [Tooltip("Exponent for speed drop-off curve (higher = sharper drop near target)")] + [SerializeField] private float endlessDescenderSpeedExponent = 2.5f; + + [Header("Endless Descender - Player Movement")] + [Tooltip("Maximum distance the player can move from a single tap")] + [SerializeField] private float endlessDescenderTapMaxDistance = 0.5f; + + [Tooltip("How quickly the tap impulse fades (higher = faster stop)")] + [SerializeField] private float endlessDescenderTapDecelerationRate = 5.0f; + + [Header("Endless Descender - Monster Spawning")] + [Tooltip("Base chance (0-1) of spawning a monster on each tile")] + [SerializeField] private float endlessDescenderBaseSpawnProbability = 0.2f; + + [Tooltip("Maximum chance (0-1) of spawning a monster")] + [SerializeField] private float endlessDescenderMaxSpawnProbability = 0.5f; + + [Tooltip("How fast the probability increases per second")] + [SerializeField] private float endlessDescenderProbabilityIncreaseRate = 0.01f; + + [Tooltip("Force a spawn after this many seconds without spawns")] + [SerializeField] private float endlessDescenderGuaranteedSpawnTime = 30f; + + [Tooltip("Minimum time between monster spawns")] + [SerializeField] private float endlessDescenderSpawnCooldown = 5f; + + [Header("Endless Descender - Scoring")] + [Tooltip("Base points for taking a picture")] + [SerializeField] private int endlessDescenderBasePoints = 100; + + [Tooltip("Additional points per depth unit")] + [SerializeField] private int endlessDescenderDepthMultiplier = 10; + + [Header("Endless Descender - Surfacing")] + [Tooltip("Duration in seconds for speed transition when surfacing")] + [SerializeField] private float endlessDescenderSpeedTransitionDuration = 2.0f; + + [Tooltip("Factor to multiply speed by when surfacing (usually 1.0 for same speed)")] + [SerializeField] private float endlessDescenderSurfacingSpeedFactor = 3.0f; + + [Tooltip("How long to continue spawning tiles after surfacing begins (seconds)")] + [SerializeField] private float endlessDescenderSurfacingSpawnDelay = 5.0f; + + [Header("Endless Descender - Tile Generation")] + [Tooltip("Initial number of tiles to create at start")] + [SerializeField] private int endlessDescenderInitialTileCount = 3; + + [Tooltip("Buffer distance for spawning new tiles")] + [SerializeField] private float endlessDescenderTileSpawnBuffer = 1f; + + [Tooltip("Base movement speed for tiles")] + [SerializeField] private float endlessDescenderMoveSpeed = 3f; + + [Tooltip("Factor to increase speed by each interval")] + [SerializeField] private float endlessDescenderSpeedUpFactor = 0.2f; + + [Tooltip("Time interval between speed increases (seconds)")] + [SerializeField] private float endlessDescenderSpeedUpInterval = 10f; + + [Tooltip("Maximum movement speed allowed")] + [SerializeField] private float endlessDescenderMaxMoveSpeed = 12f; + + [Tooltip("Interval for velocity calculations (seconds)")] + [SerializeField] private float endlessDescenderVelocityCalculationInterval = 0.5f; + + [Header("Endless Descender - Obstacles")] + [Tooltip("Time interval between obstacle spawn attempts (in seconds)")] + [SerializeField] private float endlessDescenderObstacleSpawnInterval = 2f; + + [Tooltip("Random variation in obstacle spawn timing (+/- seconds)")] + [SerializeField] private float endlessDescenderObstacleSpawnIntervalVariation = 0.5f; + + [Tooltip("Maximum number of obstacle spawn position attempts before skipping")] + [SerializeField] private int endlessDescenderObstacleMaxSpawnAttempts = 10; + + [Tooltip("Radius around obstacle spawn point to check for tile collisions")] + [SerializeField] private float endlessDescenderObstacleSpawnCollisionRadius = 1f; + + [Tooltip("Minimum movement speed for spawned obstacles")] + [SerializeField] private float endlessDescenderObstacleMinMoveSpeed = 1f; + + [Tooltip("Maximum movement speed for spawned obstacles")] + [SerializeField] private float endlessDescenderObstacleMaxMoveSpeed = 4f; + + // IMinigameSettings implementation - Basic Movement + public float EndlessDescenderLerpSpeed => endlessDescenderLerpSpeed; + public float EndlessDescenderMaxOffset => endlessDescenderMaxOffset; + public float EndlessDescenderClampXMin => endlessDescenderClampXMin; + public float EndlessDescenderClampXMax => endlessDescenderClampXMax; + public float EndlessDescenderSpeedExponent => endlessDescenderSpeedExponent; + + // IMinigameSettings implementation - Player Movement + public float EndlessDescenderTapMaxDistance => endlessDescenderTapMaxDistance; + public float EndlessDescenderTapDecelerationRate => endlessDescenderTapDecelerationRate; + + // IMinigameSettings implementation - Monster Spawning + public float EndlessDescenderBaseSpawnProbability => endlessDescenderBaseSpawnProbability; + public float EndlessDescenderMaxSpawnProbability => endlessDescenderMaxSpawnProbability; + public float EndlessDescenderProbabilityIncreaseRate => endlessDescenderProbabilityIncreaseRate; + public float EndlessDescenderGuaranteedSpawnTime => endlessDescenderGuaranteedSpawnTime; + public float EndlessDescenderSpawnCooldown => endlessDescenderSpawnCooldown; + + // IMinigameSettings implementation - Scoring + public int EndlessDescenderBasePoints => endlessDescenderBasePoints; + public int EndlessDescenderDepthMultiplier => endlessDescenderDepthMultiplier; + + // IMinigameSettings implementation - Surfacing + public float EndlessDescenderSpeedTransitionDuration => endlessDescenderSpeedTransitionDuration; + public float EndlessDescenderSurfacingSpeedFactor => endlessDescenderSurfacingSpeedFactor; + public float EndlessDescenderSurfacingSpawnDelay => endlessDescenderSurfacingSpawnDelay; + + // IMinigameSettings implementation - Tile Generation + public int EndlessDescenderInitialTileCount => endlessDescenderInitialTileCount; + public float EndlessDescenderTileSpawnBuffer => endlessDescenderTileSpawnBuffer; + public float EndlessDescenderMoveSpeed => endlessDescenderMoveSpeed; + public float EndlessDescenderSpeedUpFactor => endlessDescenderSpeedUpFactor; + public float EndlessDescenderSpeedUpInterval => endlessDescenderSpeedUpInterval; + public float EndlessDescenderMaxMoveSpeed => endlessDescenderMaxMoveSpeed; + public float EndlessDescenderVelocityCalculationInterval => endlessDescenderVelocityCalculationInterval; + + // IMinigameSettings implementation - Obstacles + public float EndlessDescenderObstacleSpawnInterval => endlessDescenderObstacleSpawnInterval; + public float EndlessDescenderObstacleSpawnIntervalVariation => endlessDescenderObstacleSpawnIntervalVariation; + public int EndlessDescenderObstacleMaxSpawnAttempts => endlessDescenderObstacleMaxSpawnAttempts; + public float EndlessDescenderObstacleSpawnCollisionRadius => endlessDescenderObstacleSpawnCollisionRadius; + public float EndlessDescenderObstacleMinMoveSpeed => endlessDescenderObstacleMinMoveSpeed; + public float EndlessDescenderObstacleMaxMoveSpeed => endlessDescenderObstacleMaxMoveSpeed; + + public override void OnValidate() + { + base.OnValidate(); + + // Validate basic movement values + endlessDescenderLerpSpeed = Mathf.Max(0.1f, endlessDescenderLerpSpeed); + endlessDescenderMaxOffset = Mathf.Max(0.1f, endlessDescenderMaxOffset); + endlessDescenderSpeedExponent = Mathf.Max(0.1f, endlessDescenderSpeedExponent); + + // Ensure min is less than max for clamping + if (endlessDescenderClampXMin >= endlessDescenderClampXMax) + { + endlessDescenderClampXMin = endlessDescenderClampXMax - 0.1f; + } + + // Validate player movement + endlessDescenderTapMaxDistance = Mathf.Max(0.01f, endlessDescenderTapMaxDistance); + endlessDescenderTapDecelerationRate = Mathf.Max(0.1f, endlessDescenderTapDecelerationRate); + + // Validate probability values + endlessDescenderBaseSpawnProbability = Mathf.Clamp01(endlessDescenderBaseSpawnProbability); + endlessDescenderMaxSpawnProbability = Mathf.Clamp01(endlessDescenderMaxSpawnProbability); + endlessDescenderProbabilityIncreaseRate = Mathf.Max(0f, endlessDescenderProbabilityIncreaseRate); + + // Ensure max probability is at least base probability + if (endlessDescenderMaxSpawnProbability < endlessDescenderBaseSpawnProbability) + { + endlessDescenderMaxSpawnProbability = endlessDescenderBaseSpawnProbability; + } + + // Validate time values + endlessDescenderGuaranteedSpawnTime = Mathf.Max(0.1f, endlessDescenderGuaranteedSpawnTime); + endlessDescenderSpawnCooldown = Mathf.Max(0.1f, endlessDescenderSpawnCooldown); + endlessDescenderSpeedTransitionDuration = Mathf.Max(0.1f, endlessDescenderSpeedTransitionDuration); + endlessDescenderSurfacingSpawnDelay = Mathf.Max(0f, endlessDescenderSurfacingSpawnDelay); + + // Validate scoring + endlessDescenderBasePoints = Mathf.Max(0, endlessDescenderBasePoints); + endlessDescenderDepthMultiplier = Mathf.Max(0, endlessDescenderDepthMultiplier); + + // Validate tile generation + endlessDescenderInitialTileCount = Mathf.Max(1, endlessDescenderInitialTileCount); + endlessDescenderTileSpawnBuffer = Mathf.Max(0f, endlessDescenderTileSpawnBuffer); + endlessDescenderMoveSpeed = Mathf.Max(0.1f, endlessDescenderMoveSpeed); + endlessDescenderSpeedUpFactor = Mathf.Max(0f, endlessDescenderSpeedUpFactor); + endlessDescenderSpeedUpInterval = Mathf.Max(0.1f, endlessDescenderSpeedUpInterval); + endlessDescenderMaxMoveSpeed = Mathf.Max(endlessDescenderMoveSpeed, endlessDescenderMaxMoveSpeed); + endlessDescenderVelocityCalculationInterval = Mathf.Max(0.01f, endlessDescenderVelocityCalculationInterval); + + // Validate obstacle values + endlessDescenderObstacleSpawnInterval = Mathf.Max(0.1f, endlessDescenderObstacleSpawnInterval); + endlessDescenderObstacleSpawnIntervalVariation = Mathf.Max(0f, endlessDescenderObstacleSpawnIntervalVariation); + endlessDescenderObstacleMaxSpawnAttempts = Mathf.Max(1, endlessDescenderObstacleMaxSpawnAttempts); + endlessDescenderObstacleSpawnCollisionRadius = Mathf.Max(0.1f, endlessDescenderObstacleSpawnCollisionRadius); + endlessDescenderObstacleMinMoveSpeed = Mathf.Max(0.1f, endlessDescenderObstacleMinMoveSpeed); + endlessDescenderObstacleMaxMoveSpeed = Mathf.Max(endlessDescenderObstacleMinMoveSpeed, endlessDescenderObstacleMaxMoveSpeed); + } + } +} diff --git a/Assets/Scripts/Core/Settings/MinigameSettings.cs.meta b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs.meta similarity index 100% rename from Assets/Scripts/Core/Settings/MinigameSettings.cs.meta rename to Assets/Scripts/Core/Settings/DivingMinigameSettings.cs.meta diff --git a/Assets/Scripts/Core/Settings/MinigameSettings.cs b/Assets/Scripts/Core/Settings/MinigameSettings.cs deleted file mode 100644 index c37a7945..00000000 --- a/Assets/Scripts/Core/Settings/MinigameSettings.cs +++ /dev/null @@ -1,49 +0,0 @@ -using UnityEngine; - -namespace AppleHills.Core.Settings -{ - /// - /// Settings related to minigames - /// - [CreateAssetMenu(fileName = "MinigameSettings", menuName = "AppleHills/Settings/Minigames", order = 3)] - public class MinigameSettings : BaseSettings, IMinigameSettings - { - [Header("Endless Descender Settings")] - [Tooltip("How quickly the character follows the finger horizontally (higher = more responsive)")] - [SerializeField] private float endlessDescenderLerpSpeed = 12f; - - [Tooltip("Maximum horizontal offset allowed between character and finger position")] - [SerializeField] private float endlessDescenderMaxOffset = 3f; - - [Tooltip("Minimum allowed X position for endless descender movement")] - [SerializeField] private float endlessDescenderClampXMin = -3.5f; - - [Tooltip("Maximum allowed X position for endless descender movement")] - [SerializeField] private float endlessDescenderClampXMax = 3.5f; - - [Tooltip("Exponent for speed drop-off curve (higher = sharper drop near target)")] - [SerializeField] private float endlessDescenderSpeedExponent = 2.5f; - - // IMinigameSettings implementation - public float EndlessDescenderLerpSpeed => endlessDescenderLerpSpeed; - public float EndlessDescenderMaxOffset => endlessDescenderMaxOffset; - public float EndlessDescenderClampXMin => endlessDescenderClampXMin; - public float EndlessDescenderClampXMax => endlessDescenderClampXMax; - public float EndlessDescenderSpeedExponent => endlessDescenderSpeedExponent; - - public override void OnValidate() - { - base.OnValidate(); - // Validate values - endlessDescenderLerpSpeed = Mathf.Max(0.1f, endlessDescenderLerpSpeed); - endlessDescenderMaxOffset = Mathf.Max(0.1f, endlessDescenderMaxOffset); - endlessDescenderSpeedExponent = Mathf.Max(0.1f, endlessDescenderSpeedExponent); - - // Ensure min is less than max - if (endlessDescenderClampXMin >= endlessDescenderClampXMax) - { - endlessDescenderClampXMin = endlessDescenderClampXMax - 0.1f; - } - } - } -} diff --git a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs index a767da84..71a10c64 100644 --- a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs +++ b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs @@ -43,13 +43,50 @@ namespace AppleHills.Core.Settings /// /// Interface for minigame settings /// - public interface IMinigameSettings + public interface IDivingMinigameSettings { - // Endless Descender settings + // Endless Descender settings - Basic Movement float EndlessDescenderLerpSpeed { get; } float EndlessDescenderMaxOffset { get; } float EndlessDescenderClampXMin { get; } float EndlessDescenderClampXMax { get; } float EndlessDescenderSpeedExponent { get; } + + // Endless Descender - Player Movement + float EndlessDescenderTapMaxDistance { get; } + float EndlessDescenderTapDecelerationRate { get; } + + // Endless Descender - Monster Spawning + float EndlessDescenderBaseSpawnProbability { get; } + float EndlessDescenderMaxSpawnProbability { get; } + float EndlessDescenderProbabilityIncreaseRate { get; } + float EndlessDescenderGuaranteedSpawnTime { get; } + float EndlessDescenderSpawnCooldown { get; } + + // Endless Descender - Scoring + int EndlessDescenderBasePoints { get; } + int EndlessDescenderDepthMultiplier { get; } + + // Endless Descender - Surfacing + float EndlessDescenderSpeedTransitionDuration { get; } + float EndlessDescenderSurfacingSpeedFactor { get; } + float EndlessDescenderSurfacingSpawnDelay { get; } + + // Endless Descender - Tile Generation + int EndlessDescenderInitialTileCount { get; } + float EndlessDescenderTileSpawnBuffer { get; } + float EndlessDescenderMoveSpeed { get; } + float EndlessDescenderSpeedUpFactor { get; } + float EndlessDescenderSpeedUpInterval { get; } + float EndlessDescenderMaxMoveSpeed { get; } + float EndlessDescenderVelocityCalculationInterval { get; } + + // Endless Descender - Obstacles + float EndlessDescenderObstacleSpawnInterval { get; } + float EndlessDescenderObstacleSpawnIntervalVariation { get; } + int EndlessDescenderObstacleMaxSpawnAttempts { get; } + float EndlessDescenderObstacleSpawnCollisionRadius { get; } + float EndlessDescenderObstacleMinMoveSpeed { get; } + float EndlessDescenderObstacleMaxMoveSpeed { get; } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs index 65823896..66aae15b 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Bubbles/BubbleSpawner.cs @@ -1,5 +1,6 @@ using UnityEngine; using Pooling; +using AppleHills.Core.Settings; namespace Minigames.DivingForPictures { @@ -10,25 +11,9 @@ namespace Minigames.DivingForPictures { public Bubble bubblePrefab; public Sprite[] bubbleSprites; // Assign in inspector - public float spawnInterval = 0.3f; - public Vector2 speedRange = new Vector2(0.5f, 2f); - public Vector2 scaleRange = new Vector2(0.3f, 0.7f); - public Vector2 wobbleSpeedRange = new Vector2(1f, 3f); - public Vector2 wobbleAmountRange = new Vector2(0.05f, 0.15f); - public float spawnXMin = -3.5f; - public float spawnXMax = 3.5f; - public float spawnY = -5f; - public float wobbleMinScale = 0.2f; - public float wobbleMaxScale = 1.2f; - [Header("Object Pooling")] - public bool useObjectPooling = true; - public int initialPoolSize = 10; - public int maxPoolSize = 30; - - [Header("Surfacing Settings")] - [Tooltip("Factor to multiply bubble speed by when surfacing (0.5 = half speed)")] - [SerializeField] private float surfacingSpeedFactor = 0.5f; + private DivingDeveloperSettings _devSettings; + private IDivingMinigameSettings _gameSettings; private float _timer; private float _nextSpawnInterval; @@ -40,14 +25,24 @@ namespace Minigames.DivingForPictures { _mainCamera = Camera.main; - if (useObjectPooling) + // Get developer settings and game settings + _devSettings = GameManager.GetDeveloperSettings(); + _gameSettings = GameManager.GetSettingsObject(); + + if (_devSettings == null) + { + Debug.LogError("[BubbleSpawner] Failed to load developer settings!"); + return; + } + + if (_devSettings.BubbleUseObjectPooling) { // Create the bubble pool GameObject poolGO = new GameObject("BubblePool"); poolGO.transform.SetParent(transform); _bubblePool = poolGO.AddComponent(); - _bubblePool.initialPoolSize = initialPoolSize; - _bubblePool.maxPoolSize = maxPoolSize; + _bubblePool.initialPoolSize = _devSettings.BubbleInitialPoolSize; + _bubblePool.maxPoolSize = _devSettings.BubbleMaxPoolSize; _bubblePool.Initialize(bubblePrefab); // Periodically check for pool statistics in debug builds @@ -80,7 +75,7 @@ namespace Minigames.DivingForPictures /// Randomized interval in seconds. float GetRandomizedInterval() { - return spawnInterval * Random.Range(0.8f, 1.2f); + return _devSettings.BubbleSpawnInterval * Random.Range(0.8f, 1.2f); } /// @@ -88,11 +83,11 @@ namespace Minigames.DivingForPictures /// void SpawnBubble() { - float x = Random.Range(spawnXMin, spawnXMax); - Vector3 spawnPos = new Vector3(x, spawnY, 0f); + float x = Random.Range(_devSettings.BubbleSpawnXMin, _devSettings.BubbleSpawnXMax); + Vector3 spawnPos = new Vector3(x, _devSettings.BubbleSpawnY, 0f); Bubble bubble; - if (useObjectPooling && _bubblePool != null) + if (_devSettings.BubbleUseObjectPooling && _bubblePool != null) { bubble = _bubblePool.GetBubble(); bubble.transform.position = spawnPos; @@ -103,25 +98,25 @@ namespace Minigames.DivingForPictures } // Randomize bubble properties - float baseSpeed = Random.Range(speedRange.x, speedRange.y); + float baseSpeed = Random.Range(_devSettings.BubbleSpeedRange.x, _devSettings.BubbleSpeedRange.y); // Apply surfacing speed reduction if needed if (_isSurfacing) { - bubble.speed = baseSpeed * surfacingSpeedFactor; + bubble.speed = baseSpeed * _devSettings.BubbleSurfacingSpeedFactor; } else { bubble.speed = baseSpeed; } - bubble.wobbleSpeed = Random.Range(wobbleSpeedRange.x, wobbleSpeedRange.y); + bubble.wobbleSpeed = Random.Range(_devSettings.BubbleWobbleSpeedRange.x, _devSettings.BubbleWobbleSpeedRange.y); // Set base scale (initial size) for the bubble - float baseScale = Random.Range(scaleRange.x, scaleRange.y); + float baseScale = Random.Range(_devSettings.BubbleScaleRange.x, _devSettings.BubbleScaleRange.y); bubble.SetBaseScale(baseScale); - // Assign random sprite to BubbleSprite (fixed naming from BottleSprite) + // Assign random sprite to BubbleSprite if (bubbleSprites != null && bubbleSprites.Length > 0) { Sprite randomSprite = bubbleSprites[Random.Range(0, bubbleSprites.Length)]; @@ -132,7 +127,7 @@ namespace Minigames.DivingForPictures bubble.transform.rotation = Quaternion.Euler(0f, 0f, Random.Range(0f, 360f)); // Pass min/max scale for wobble clamping - bubble.SetWobbleScaleLimits(wobbleMinScale, wobbleMaxScale); + bubble.SetWobbleScaleLimits(_devSettings.BubbleWobbleMinScale, _devSettings.BubbleWobbleMaxScale); } /// @@ -148,10 +143,10 @@ namespace Minigames.DivingForPictures Bubble[] activeBubbles = FindObjectsByType(FindObjectsSortMode.None); foreach (Bubble bubble in activeBubbles) { - bubble.speed *= surfacingSpeedFactor; + bubble.speed *= _devSettings.BubbleSurfacingSpeedFactor; } - Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {surfacingSpeedFactor * 100}% speed."); + Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {_devSettings.BubbleSurfacingSpeedFactor * 100}% speed."); } /// diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs index d97285b4..1d3ddc1d 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using UnityEngine.Events; using UnityEngine.Playables; +using AppleHills.Core.Settings; namespace Minigames.DivingForPictures { @@ -13,40 +14,17 @@ namespace Minigames.DivingForPictures [Tooltip("Array of monster prefabs to spawn randomly")] [SerializeField] private GameObject[] monsterPrefabs; - [Header("Spawn Probability")] - [Tooltip("Base chance (0-1) of spawning a monster on each tile")] - [SerializeField] private float baseSpawnProbability = 0.2f; - [Tooltip("Maximum chance (0-1) of spawning a monster")] - [SerializeField] private float maxSpawnProbability = 0.5f; - [Tooltip("How fast the probability increases per second")] - [SerializeField] private float probabilityIncreaseRate = 0.01f; - - [Header("Spawn Timing")] - [Tooltip("Force a spawn after this many seconds without spawns")] - [SerializeField] private float guaranteedSpawnTime = 30f; - [Tooltip("Minimum time between monster spawns")] - [SerializeField] private float spawnCooldown = 5f; - - [Header("Scoring")] - [Tooltip("Base points for taking a picture")] - [SerializeField] private int basePoints = 100; - [Tooltip("Additional points per depth unit")] - [SerializeField] private int depthMultiplier = 10; - [Header("Rope Damage System")] [Tooltip("Ropes that will break one by one as player takes damage")] [SerializeField] private RopeBreaker[] playerRopes; [Header("Surfacing Settings")] - [Tooltip("Duration in seconds for speed transition when surfacing")] - [SerializeField] private float speedTransitionDuration = 2.0f; - [Tooltip("Factor to multiply speed by when surfacing (usually 1.0 for same speed)")] - [SerializeField] private float surfacingSpeedFactor = 3.0f; - [Tooltip("How long to continue spawning tiles after surfacing begins (seconds)")] - [SerializeField] private float surfacingSpawnDelay = 5.0f; [Tooltip("Reference to the PlayableDirector that will play the surfacing timeline")] [SerializeField] private PlayableDirector surfacingTimeline; + // Settings reference + private IDivingMinigameSettings _settings; + // Private state variables private int playerScore = 0; private float currentSpawnProbability; @@ -83,7 +61,15 @@ namespace Minigames.DivingForPictures private void Awake() { - currentSpawnProbability = baseSpawnProbability; + // Get settings from GameManager + _settings = GameManager.GetSettingsObject(); + if (_settings == null) + { + Debug.LogError("[DivingGameManager] Failed to load diving minigame settings!"); + } + + // Initialize with base probability from settings + currentSpawnProbability = _settings?.EndlessDescenderBaseSpawnProbability ?? 0.2f; } private void Start() @@ -118,10 +104,10 @@ namespace Minigames.DivingForPictures // Gradually increase spawn probability over time float previousProbability = currentSpawnProbability; - if (currentSpawnProbability < maxSpawnProbability) + if (currentSpawnProbability < _settings.EndlessDescenderMaxSpawnProbability) { - currentSpawnProbability += probabilityIncreaseRate * Time.deltaTime; - currentSpawnProbability = Mathf.Min(currentSpawnProbability, maxSpawnProbability); + currentSpawnProbability += _settings.EndlessDescenderProbabilityIncreaseRate * Time.deltaTime; + currentSpawnProbability = Mathf.Min(currentSpawnProbability, _settings.EndlessDescenderMaxSpawnProbability); // Only fire event if probability changed significantly if (Mathf.Abs(currentSpawnProbability - previousProbability) > 0.01f) @@ -141,8 +127,8 @@ namespace Minigames.DivingForPictures // If we're surfacing, don't spawn new monsters if (_isSurfacing) return; - bool forceSpawn = timeSinceLastSpawn >= guaranteedSpawnTime; - bool onCooldown = timeSinceLastSpawn < spawnCooldown; + bool forceSpawn = timeSinceLastSpawn >= _settings.EndlessDescenderGuaranteedSpawnTime; + bool onCooldown = timeSinceLastSpawn < _settings.EndlessDescenderSpawnCooldown; // Don't spawn if on cooldown, unless forced if (onCooldown && !forceSpawn) return; @@ -159,7 +145,7 @@ namespace Minigames.DivingForPictures // Reset timer and adjust probability lastSpawnTime = Time.time; timeSinceLastSpawn = 0f; - currentSpawnProbability = baseSpawnProbability; + currentSpawnProbability = _settings.EndlessDescenderBaseSpawnProbability; OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability); } } @@ -204,8 +190,8 @@ namespace Minigames.DivingForPictures private void OnMonsterPictureTaken(Monster monster) { // Calculate points based on depth - int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * depthMultiplier); - int pointsAwarded = basePoints + depthBonus; + int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.EndlessDescenderDepthMultiplier); + int pointsAwarded = _settings.EndlessDescenderBasePoints + depthBonus; // Add score playerScore += pointsAwarded; @@ -356,7 +342,7 @@ namespace Minigames.DivingForPictures _isSurfacing = true; // 1. Initiate smooth velocity transition to surfacing speed - float targetVelocityFactor = -1.0f * surfacingSpeedFactor; + float targetVelocityFactor = -1.0f * _settings.EndlessDescenderSurfacingSpeedFactor; SetVelocityFactor(targetVelocityFactor); // 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic) @@ -525,7 +511,7 @@ namespace Minigames.DivingForPictures private IEnumerator SurfacingSequence() { // Wait for the configured delay - yield return new WaitForSeconds(surfacingSpawnDelay); + yield return new WaitForSeconds(_settings.EndlessDescenderSurfacingSpawnDelay); // Find tile spawner and tell it to stop spawning TrenchTileSpawner tileSpawner = FindFirstObjectByType(); @@ -594,10 +580,10 @@ namespace Minigames.DivingForPictures float startFactor = _currentVelocityFactor; float elapsed = 0f; - while (elapsed < speedTransitionDuration) + while (elapsed < _settings.EndlessDescenderSpeedTransitionDuration) { elapsed += Time.deltaTime; - float t = Mathf.Clamp01(elapsed / speedTransitionDuration); + float t = Mathf.Clamp01(elapsed / _settings.EndlessDescenderSpeedTransitionDuration); // Smooth step interpolation float smoothStep = t * t * (3f - 2f * t); diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs index d34adc04..0e48d095 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using Pooling; +using AppleHills.Core.Settings; namespace Minigames.DivingForPictures { @@ -16,50 +17,17 @@ namespace Minigames.DivingForPictures [Tooltip("List of possible obstacle prefabs to spawn")] [SerializeField] private List obstaclePrefabs; - [Header("Spawn Settings")] - [Tooltip("Time interval between spawn attempts (in seconds)")] - [SerializeField] private float spawnInterval = 2f; - - [Tooltip("Random variation in spawn timing (+/- seconds)")] - [SerializeField] private float spawnIntervalVariation = 0.5f; - - [Tooltip("Maximum number of spawn position attempts before skipping")] - [SerializeField] private int maxSpawnAttempts = 10; - - [Tooltip("Radius around spawn point to check for tile collisions")] - [SerializeField] private float spawnCollisionRadius = 1f; - - [Header("Obstacle Properties Randomization")] - [Tooltip("Minimum movement speed for spawned obstacles")] - [SerializeField] private float minMoveSpeed = 1f; - - [Tooltip("Maximum movement speed for spawned obstacles")] - [SerializeField] private float maxMoveSpeed = 4f; - - [Header("Object Pooling")] - [Tooltip("Whether to use object pooling for obstacles")] - [SerializeField] private bool useObjectPooling = true; - - [Tooltip("Maximum objects per prefab type in pool")] - [SerializeField] private int maxPerPrefabPoolSize = 3; - - [Tooltip("Total maximum pool size across all prefab types")] - [SerializeField] private int totalMaxPoolSize = 15; - - [Header("Layer Settings")] - [Tooltip("Layer mask for tile collision detection during spawn position validation")] - [SerializeField] private LayerMask tileLayerMask = -1; // Let user configure which layers to avoid - - [Tooltip("Target layer for spawned obstacles - obstacles will be placed on this layer")] - [SerializeField] private int obstacleLayer = 11; // Default to layer 11, but configurable - [Header("Events")] - [Tooltip("Called when an obstacle is spawned")] + [Tooltip("Invoked when a new obstacle is spawned")] public UnityEvent onObstacleSpawned; - [Tooltip("Called when an obstacle is returned to pool")] + [Tooltip("Invoked when an obstacle is destroyed or returned to pool")] public UnityEvent onObstacleDestroyed; + // Settings references + private IDivingMinigameSettings _settings; + private DivingDeveloperSettings _devSettings; + // Private fields private ObstaclePool _obstaclePool; private Camera _mainCamera; @@ -75,13 +43,34 @@ namespace Minigames.DivingForPictures { _mainCamera = Camera.main; + // Get settings from GameManager + _settings = GameManager.GetSettingsObject(); + _devSettings = GameManager.GetDeveloperSettings(); + + if (_settings == null) + { + Debug.LogError("[ObstacleSpawner] Failed to load diving minigame settings!"); + } + + if (_devSettings == null) + { + Debug.LogError("[ObstacleSpawner] Failed to load diving developer settings!"); + } + // Validate obstacle prefabs ValidateObstaclePrefabs(); - if (useObjectPooling) + if (_devSettings?.ObstacleUseObjectPooling ?? false) { InitializeObjectPool(); } + + // Initialize events if null + if (onObstacleSpawned == null) + onObstacleSpawned = new UnityEvent(); + + if (onObstacleDestroyed == null) + onObstacleDestroyed = new UnityEvent(); } private void Start() @@ -100,6 +89,8 @@ namespace Minigames.DivingForPictures /// private void ValidateObstaclePrefabs() { + if (_devSettings == null) return; + for (int i = 0; i < obstaclePrefabs.Count; i++) { if (obstaclePrefabs[i] == null) continue; @@ -112,10 +103,10 @@ namespace Minigames.DivingForPictures } // Ensure the prefab is on the correct layer (using configurable obstacleLayer) - if (obstaclePrefabs[i].layer != obstacleLayer) + if (obstaclePrefabs[i].layer != _devSettings.ObstacleLayer) { - Debug.LogWarning($"Obstacle prefab {obstaclePrefabs[i].name} is not on the configured obstacle layer ({obstacleLayer}). Setting layer automatically."); - SetLayerRecursively(obstaclePrefabs[i], obstacleLayer); + Debug.LogWarning($"Obstacle prefab {obstaclePrefabs[i].name} is not on the configured obstacle layer ({_devSettings.ObstacleLayer}). Setting layer automatically."); + SetLayerRecursively(obstaclePrefabs[i], _devSettings.ObstacleLayer); } } } @@ -142,8 +133,8 @@ namespace Minigames.DivingForPictures _obstaclePool = poolGO.AddComponent(); // Set up pool configuration - _obstaclePool.maxPerPrefabPoolSize = maxPerPrefabPoolSize; - _obstaclePool.totalMaxPoolSize = totalMaxPoolSize; + _obstaclePool.maxPerPrefabPoolSize = _devSettings.ObstacleMaxPerPrefabPoolSize; + _obstaclePool.totalMaxPoolSize = _devSettings.ObstacleTotalMaxPoolSize; // Convert GameObject list to FloatingObstacle list List prefabObstacles = new List(obstaclePrefabs.Count); @@ -230,7 +221,9 @@ namespace Minigames.DivingForPictures while (true) { // Calculate next spawn time with variation - float nextSpawnTime = spawnInterval + Random.Range(-spawnIntervalVariation, spawnIntervalVariation); + float nextSpawnTime = _settings.EndlessDescenderObstacleSpawnInterval + + Random.Range(-_settings.EndlessDescenderObstacleSpawnIntervalVariation, + _settings.EndlessDescenderObstacleSpawnIntervalVariation); nextSpawnTime = Mathf.Max(0.1f, nextSpawnTime); // Ensure minimum interval yield return new WaitForSeconds(nextSpawnTime); @@ -264,7 +257,7 @@ namespace Minigames.DivingForPictures bool foundValidPosition = false; // Try to find a valid spawn position - for (int attempts = 0; attempts < maxSpawnAttempts; attempts++) + for (int attempts = 0; attempts < _settings.EndlessDescenderObstacleMaxSpawnAttempts; attempts++) { spawnPosition = GetRandomSpawnPosition(); @@ -277,13 +270,13 @@ namespace Minigames.DivingForPictures } else { - Debug.Log($"[ObstacleSpawner] Position {spawnPosition} invalid (attempt {attempts + 1}/{maxSpawnAttempts})"); + Debug.Log($"[ObstacleSpawner] Position {spawnPosition} invalid (attempt {attempts + 1}/{_settings.EndlessDescenderObstacleMaxSpawnAttempts})"); } } if (!foundValidPosition) { - Debug.LogWarning($"[ObstacleSpawner] SPAWN MISSED: Could not find valid spawn position after {maxSpawnAttempts} attempts at {Time.time:F2}"); + Debug.LogWarning($"[ObstacleSpawner] SPAWN MISSED: Could not find valid spawn position after {_settings.EndlessDescenderObstacleMaxSpawnAttempts} attempts at {Time.time:F2}"); } } @@ -306,7 +299,7 @@ namespace Minigames.DivingForPictures private bool IsValidSpawnPosition(Vector3 position) { // Use OverlapCircle to check for collisions with tiles - Collider2D collision = Physics2D.OverlapCircle(position, spawnCollisionRadius, tileLayerMask); + Collider2D collision = Physics2D.OverlapCircle(position, _settings.EndlessDescenderObstacleSpawnCollisionRadius, _devSettings.ObstacleTileLayerMask); return collision == null; } @@ -330,7 +323,7 @@ namespace Minigames.DivingForPictures GameObject obstacle; // Spawn using pool or instantiate directly - if (useObjectPooling && _obstaclePool != null) + if (_devSettings.ObstacleUseObjectPooling && _obstaclePool != null) { Debug.Log($"[ObstacleSpawner] Requesting obstacle from pool (prefab index {prefabIndex})"); obstacle = _obstaclePool.GetObstacle(prefabIndex); @@ -416,8 +409,10 @@ namespace Minigames.DivingForPictures // Set prefab index obstacleComponent.PrefabIndex = prefabIndex; - // Randomize properties - obstacleComponent.MoveSpeed = Random.Range(minMoveSpeed, maxMoveSpeed); + // Randomize properties using settings + obstacleComponent.MoveSpeed = Random.Range( + _settings.EndlessDescenderObstacleMinMoveSpeed, + _settings.EndlessDescenderObstacleMaxMoveSpeed); // Set spawner reference (since FloatingObstacle has this built-in now) obstacleComponent.SetSpawner(this); @@ -440,7 +435,7 @@ namespace Minigames.DivingForPictures onObstacleDestroyed?.Invoke(obstacle); // Return to pool or destroy - if (useObjectPooling && _obstaclePool != null) + if (_devSettings.ObstacleUseObjectPooling && _obstaclePool != null) { Debug.Log($"[ObstacleSpawner] Returning {obstacle.name} to pool"); _obstaclePool.ReturnObstacle(obstacle, prefabIndex); @@ -457,7 +452,9 @@ namespace Minigames.DivingForPictures /// public void SetSpawnInterval(float interval) { - spawnInterval = interval; + // This method can no longer directly modify the settings + // Consider implementing a runtime settings override system if needed + Debug.LogWarning("[ObstacleSpawner] SetSpawnInterval no longer modifies settings directly. Settings are now centralized."); } /// @@ -465,8 +462,9 @@ namespace Minigames.DivingForPictures /// public void SetSpeedRange(float min, float max) { - minMoveSpeed = min; - maxMoveSpeed = max; + // This method can no longer directly modify the settings + // Consider implementing a runtime settings override system if needed + Debug.LogWarning("[ObstacleSpawner] SetSpeedRange no longer modifies settings directly. Settings are now centralized."); } /// @@ -534,8 +532,8 @@ namespace Minigames.DivingForPictures #if UNITY_EDITOR private void OnDrawGizmosSelected() { - // Only draw if screen bounds have been calculated - if (_spawnRangeX > 0f) + // Only draw if screen bounds have been calculated and settings are available + if (_spawnRangeX > 0f && _settings != null) { // Draw spawn area using dynamic calculations Gizmos.color = Color.yellow; @@ -545,7 +543,7 @@ namespace Minigames.DivingForPictures // Draw collision radius at spawn point Gizmos.color = Color.red; - Gizmos.DrawWireSphere(center, spawnCollisionRadius); + Gizmos.DrawWireSphere(center, _settings.EndlessDescenderObstacleSpawnCollisionRadius); } } #endif diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs index fd247d7a..b61a8f82 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs @@ -1,4 +1,5 @@ using UnityEngine; +using AppleHills.Core.Settings; namespace Minigames.DivingForPictures { @@ -8,11 +9,8 @@ namespace Minigames.DivingForPictures /// public class PlayerController : MonoBehaviour, ITouchInputConsumer { - [Header("Tap Movement")] - [Tooltip("Maximum distance the player can move from a single tap")] - [SerializeField] private float tapMaxDistance = 0.5f; - [Tooltip("How quickly the tap impulse fades (higher = faster stop)")] - [SerializeField] private float tapDecelerationRate = 5.0f; + // Settings reference + private IDivingMinigameSettings _settings; private float _targetFingerX; private bool _isTouchActive; @@ -25,6 +23,13 @@ namespace Minigames.DivingForPictures void Awake() { _originY = transform.position.y; + + // Get settings from GameManager + _settings = GameManager.GetSettingsObject(); + if (_settings == null) + { + Debug.LogError("[PlayerController] Failed to load diving minigame settings!"); + } } void Start() @@ -42,7 +47,7 @@ namespace Minigames.DivingForPictures public void OnTap(Vector2 worldPosition) { // Debug.Log($"[EndlessDescenderController] OnTap at {worldPosition}"); - float targetX = Mathf.Clamp(worldPosition.x, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax); + float targetX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax); // Calculate tap direction (+1 for right, -1 for left) _tapDirection = Mathf.Sign(targetX - transform.position.x); @@ -63,7 +68,7 @@ namespace Minigames.DivingForPictures public void OnHoldStart(Vector2 worldPosition) { // Debug.Log($"[EndlessDescenderController] OnHoldStart at {worldPosition}"); - _targetFingerX = Mathf.Clamp(worldPosition.x, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax); + _targetFingerX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax); _isTouchActive = true; } @@ -73,7 +78,7 @@ namespace Minigames.DivingForPictures public void OnHoldMove(Vector2 worldPosition) { // Debug.Log($"[EndlessDescenderController] OnHoldMove at {worldPosition}"); - _targetFingerX = Mathf.Clamp(worldPosition.x, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax); + _targetFingerX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax); } /// @@ -91,9 +96,9 @@ namespace Minigames.DivingForPictures if (_isTouchActive) { float currentX = transform.position.x; - float lerpSpeed = GameManager.Instance.EndlessDescenderLerpSpeed; - float maxOffset = GameManager.Instance.EndlessDescenderMaxOffset; - float exponent = GameManager.Instance.EndlessDescenderSpeedExponent; + float lerpSpeed = _settings.EndlessDescenderLerpSpeed; + float maxOffset = _settings.EndlessDescenderMaxOffset; + float exponent = _settings.EndlessDescenderSpeedExponent; float targetX = _targetFingerX; float offset = targetX - currentX; offset = Mathf.Clamp(offset, -maxOffset, maxOffset); @@ -103,7 +108,7 @@ namespace Minigames.DivingForPictures // Prevent overshooting moveStep = Mathf.Clamp(moveStep, -absOffset, absOffset); float newX = currentX + moveStep; - newX = Mathf.Clamp(newX, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax); + newX = Mathf.Clamp(newX, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax); UpdatePosition(newX); } @@ -111,21 +116,21 @@ namespace Minigames.DivingForPictures else if (_tapImpulseStrength > 0) { float currentX = transform.position.x; - float maxOffset = GameManager.Instance.EndlessDescenderMaxOffset; - float lerpSpeed = GameManager.Instance.EndlessDescenderLerpSpeed; + float maxOffset = _settings.EndlessDescenderMaxOffset; + float lerpSpeed = _settings.EndlessDescenderLerpSpeed; // Calculate move distance based on impulse strength float moveDistance = maxOffset * _tapImpulseStrength * Time.deltaTime * lerpSpeed; // Limit total movement from single tap - moveDistance = Mathf.Min(moveDistance, tapMaxDistance * _tapImpulseStrength); + moveDistance = Mathf.Min(moveDistance, _settings.EndlessDescenderTapMaxDistance * _tapImpulseStrength); // Apply movement in tap direction float newX = currentX + (moveDistance * _tapDirection); - newX = Mathf.Clamp(newX, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax); + newX = Mathf.Clamp(newX, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax); // Reduce impulse strength over time - _tapImpulseStrength -= Time.deltaTime * tapDecelerationRate; + _tapImpulseStrength -= Time.deltaTime * _settings.EndlessDescenderTapDecelerationRate; if (_tapImpulseStrength < 0.01f) { _tapImpulseStrength = 0f; diff --git a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs index 064944dc..28905763 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs @@ -4,6 +4,7 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; using Pooling; +using AppleHills.Core.Settings; namespace Minigames.DivingForPictures { @@ -16,16 +17,6 @@ namespace Minigames.DivingForPictures [Tooltip("List of possible trench tile prefabs.")] [SerializeField] private List tilePrefabs; - [Header("Tile Settings")] - [SerializeField] private int initialTileCount = 3; - [SerializeField] private float tileSpawnBuffer = 1f; - - [Header("Movement Settings")] - [SerializeField] private float moveSpeed = 3f; - [SerializeField] private float speedUpFactor = 0.2f; - [SerializeField] private float speedUpInterval = 10f; - [SerializeField] private float maxMoveSpeed = 12f; - [Header("Object Pooling")] [SerializeField] private bool useObjectPooling = true; [SerializeField] private int maxPerPrefabPoolSize = 2; @@ -38,6 +29,9 @@ namespace Minigames.DivingForPictures [FormerlySerializedAs("OnTileDestroyed")] public UnityEvent onTileDestroyed; + // Settings reference + private IDivingMinigameSettings _settings; + // Private fields private readonly Dictionary _tileHeights = new Dictionary(); private readonly List _activeTiles = new List(); @@ -52,9 +46,6 @@ namespace Minigames.DivingForPictures // Current velocity for tile movement private float _currentVelocity; - - // Interval for velocity calculations (seconds) - [SerializeField] private float velocityCalculationInterval = 0.5f; private const float TileSpawnZ = -1f; private const float DefaultTileHeight = 5f; @@ -73,7 +64,15 @@ namespace Minigames.DivingForPictures private void Awake() { _mainCamera = Camera.main; - _baseMoveSpeed = moveSpeed; // Store the original base speed + + // Get settings from GameManager + _settings = GameManager.GetSettingsObject(); + if (_settings == null) + { + Debug.LogError("[TrenchTileSpawner] Failed to load diving minigame settings!"); + } + + _baseMoveSpeed = _settings?.EndlessDescenderMoveSpeed ?? 3f; // Store the original base speed // Calculate tile heights for each prefab CalculateTileHeights(); @@ -110,7 +109,7 @@ namespace Minigames.DivingForPictures SpawnInitialTiles(); // Initialize velocity and start the velocity calculation coroutine - _currentVelocity = moveSpeed * Time.fixedDeltaTime; + _currentVelocity = _baseMoveSpeed * Time.fixedDeltaTime; StartCoroutine(VelocityCalculationRoutine()); } @@ -148,7 +147,7 @@ namespace Minigames.DivingForPictures while (true) { CalculateVelocity(); - yield return new WaitForSeconds(velocityCalculationInterval); + yield return new WaitForSeconds(_settings.EndlessDescenderVelocityCalculationInterval); } } @@ -157,7 +156,7 @@ namespace Minigames.DivingForPictures /// private void CalculateVelocity() { - _currentVelocity = moveSpeed * Time.fixedDeltaTime; + _currentVelocity = _baseMoveSpeed * Time.fixedDeltaTime; } /// @@ -247,7 +246,7 @@ namespace Minigames.DivingForPictures // Move starting position up by 2 tile heights startingY += tileHeightEstimate * 2; - for (int i = 0; i < initialTileCount; i++) + for (int i = 0; i < _settings.EndlessDescenderInitialTileCount; i++) { float y = startingY; // Calculate proper Y position based on previous tiles @@ -291,12 +290,12 @@ namespace Minigames.DivingForPictures // Update the actual move speed based on the velocity factor // This keeps the original move speed intact for game logic - moveSpeed = _baseMoveSpeed * Mathf.Abs(_velocityFactor); + _baseMoveSpeed = _settings.EndlessDescenderMoveSpeed * Mathf.Abs(_velocityFactor); // Recalculate velocity immediately CalculateVelocity(); - Debug.Log($"[TrenchTileSpawner] Velocity factor updated to {_velocityFactor:F2}, moveSpeed: {moveSpeed:F2}"); + Debug.Log($"[TrenchTileSpawner] Velocity factor updated to {_velocityFactor:F2}, moveSpeed: {_baseMoveSpeed:F2}"); } /// @@ -362,12 +361,12 @@ namespace Minigames.DivingForPictures if (_isSurfacing) { // When surfacing, destroy tiles at the bottom - shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - tileSpawnBuffer; + shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.EndlessDescenderTileSpawnBuffer; } else { // When descending, destroy tiles at the top - shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer; + shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.EndlessDescenderTileSpawnBuffer; } if (shouldDestroy) @@ -431,12 +430,12 @@ namespace Minigames.DivingForPictures if (_isSurfacing) { // When surfacing, check if the bottom of the tile is above the top of the screen - isLastTileLeaving = bottomTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer; + isLastTileLeaving = bottomTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.EndlessDescenderTileSpawnBuffer; } else { // When descending, check if the top of the tile is below the bottom of the screen - isLastTileLeaving = bottomTile.transform.position.y + tileHeight / 2 < _screenBottom - tileSpawnBuffer; + isLastTileLeaving = bottomTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.EndlessDescenderTileSpawnBuffer; } if (isLastTileLeaving) @@ -454,14 +453,14 @@ namespace Minigames.DivingForPictures { // When surfacing, spawn new tiles at the top float topEdge = bottomTile.transform.position.y + tileHeight / 2; - shouldSpawn = topEdge < _screenTop + tileSpawnBuffer; + shouldSpawn = topEdge < _screenTop + _settings.EndlessDescenderTileSpawnBuffer; newY = bottomTile.transform.position.y + tileHeight; } else { // When descending, spawn new tiles at the bottom float bottomEdge = bottomTile.transform.position.y - tileHeight / 2; - shouldSpawn = bottomEdge > _screenBottom - tileSpawnBuffer; + shouldSpawn = bottomEdge > _screenBottom - _settings.EndlessDescenderTileSpawnBuffer; newY = bottomTile.transform.position.y - tileHeight; } @@ -477,9 +476,9 @@ namespace Minigames.DivingForPictures private void HandleSpeedRamping() { _speedUpTimer += Time.deltaTime; - if (_speedUpTimer >= speedUpInterval) + if (_speedUpTimer >= _settings.EndlessDescenderSpeedUpInterval) { - moveSpeed = Mathf.Min(moveSpeed + speedUpFactor, maxMoveSpeed); + _baseMoveSpeed = Mathf.Min(_baseMoveSpeed + _settings.EndlessDescenderSpeedUpFactor, _settings.EndlessDescenderMaxMoveSpeed); _speedUpTimer = 0f; } } @@ -656,16 +655,19 @@ namespace Minigames.DivingForPictures // Draw tile bounds for debugging Gizmos.color = Color.cyan; - for (int i = 0; i < initialTileCount; i++) + if (_settings != null) { - float height = DefaultTileHeight; - if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null && - _tileHeights.TryGetValue(tilePrefabs[0], out float h)) + for (int i = 0; i < _settings.EndlessDescenderInitialTileCount; i++) { - height = h; + float height = DefaultTileHeight; + if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null && + _tileHeights.TryGetValue(tilePrefabs[0], out float h)) + { + height = h; + } + Vector3 center = new Vector3(0f, _screenBottom + i * height, 0f); + Gizmos.DrawWireCube(center, new Vector3(10f, height, 1f)); } - Vector3 center = new Vector3(0f, _screenBottom + i * height, 0f); - Gizmos.DrawWireCube(center, new Vector3(10f, height, 1f)); } } #endif