Revamp the settings system (#7)

- A Settings Provider system to utilize addressables for loading settings at runtime
- An editor UI for easy modifications of the settings objects
- A split out developer settings functionality to keep gameplay and nitty-gritty details separately
- Most settings migrated out of game objects and into the new system
- An additional Editor utility for fetching the settings at editor runtime, for gizmos, visualization etc

Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com>
Co-authored-by: AlexanderT <alexander@foolhardyhorizons.com>
Reviewed-on: #7
This commit is contained in:
2025-09-24 13:33:43 +00:00
parent 4b206b9b2e
commit 63cb3f1a8c
77 changed files with 2795 additions and 978 deletions

View File

@@ -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<IDivingMinigameSettings>();
if (_settings == null)
{
Debug.LogError("[DivingGameManager] Failed to load diving minigame settings!");
}
// Initialize with base probability from settings
currentSpawnProbability = _settings?.BaseSpawnProbability ?? 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.MaxSpawnProbability)
{
currentSpawnProbability += probabilityIncreaseRate * Time.deltaTime;
currentSpawnProbability = Mathf.Min(currentSpawnProbability, 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)
@@ -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.GuaranteedSpawnTime;
bool onCooldown = timeSinceLastSpawn < _settings.SpawnCooldown;
// 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.BaseSpawnProbability;
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.DepthMultiplier);
int pointsAwarded = _settings.BasePoints + 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.SurfacingSpeedFactor;
SetVelocityFactor(targetVelocityFactor);
// 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic)
@@ -404,10 +390,12 @@ namespace Minigames.DivingForPictures
GameObject playerObject = GameObject.FindGameObjectWithTag("Player");
if (playerObject != null)
{
// Disable all components except Transform and Animator on the player object (not its children)
// Disable all components except Transform, Animator, and PlayerBlinkBehavior on the player object
foreach (Component component in playerObject.GetComponents<Component>())
{
if (!(component is Transform) && !(component is Animator))
if (!(component is Transform) &&
!(component is Animator) &&
!(component is PlayerBlinkBehavior))
{
if (component is Behaviour behaviour)
{
@@ -419,7 +407,7 @@ namespace Minigames.DivingForPictures
// Start coroutine to reset X position to 0 over 1 second
StartCoroutine(ResetPlayerPosition(playerObject.transform));
Debug.Log("[DivingGameManager] Disabled player components (keeping Animator) and resetting position");
Debug.Log("[DivingGameManager] Disabled player components (keeping Animator and PlayerBlinkBehavior) and resetting position");
}
// 3. Find bubble spawner and slow down existing bubbles (no velocity management needed)
@@ -525,7 +513,7 @@ namespace Minigames.DivingForPictures
private IEnumerator SurfacingSequence()
{
// Wait for the configured delay
yield return new WaitForSeconds(surfacingSpawnDelay);
yield return new WaitForSeconds(_settings.SurfacingSpawnDelay);
// Find tile spawner and tell it to stop spawning
TrenchTileSpawner tileSpawner = FindFirstObjectByType<TrenchTileSpawner>();
@@ -594,10 +582,10 @@ namespace Minigames.DivingForPictures
float startFactor = _currentVelocityFactor;
float elapsed = 0f;
while (elapsed < speedTransitionDuration)
while (elapsed < _settings.SpeedTransitionDuration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / speedTransitionDuration);
float t = Mathf.Clamp01(elapsed / _settings.SpeedTransitionDuration);
// Smooth step interpolation
float smoothStep = t * t * (3f - 2f * t);