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:
19
Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs
Normal file
19
Assets/Scripts/Core/Settings/BaseDeveloperSettings.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Base abstract class for all developer settings.
|
||||
/// Developer settings are intended for technical configuration rather than gameplay/design values.
|
||||
/// </summary>
|
||||
public abstract class BaseDeveloperSettings : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Called to validate settings values when they are changed in the inspector.
|
||||
/// </summary>
|
||||
public virtual void OnValidate()
|
||||
{
|
||||
// Base implementation does nothing, override in derived classes
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50def2e6e95a4830b57f3e1b76a4df51
|
||||
timeCreated: 1758707161
|
||||
16
Assets/Scripts/Core/Settings/BaseSettings.cs
Normal file
16
Assets/Scripts/Core/Settings/BaseSettings.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all settings ScriptableObjects.
|
||||
/// Provides common functionality for all settings types.
|
||||
/// </summary>
|
||||
public abstract class BaseSettings : ScriptableObject
|
||||
{
|
||||
public virtual void OnValidate()
|
||||
{
|
||||
// Override in derived classes to add validation
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/BaseSettings.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/BaseSettings.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd33ef6036eb49358acbbd50dfd9bb13
|
||||
timeCreated: 1758619858
|
||||
116
Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs
Normal file
116
Assets/Scripts/Core/Settings/DeveloperSettingsProvider.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using System;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to developer settings for technical configuration rather than gameplay parameters.
|
||||
/// Follows the singleton pattern for global access.
|
||||
/// </summary>
|
||||
public class DeveloperSettingsProvider : MonoBehaviour
|
||||
{
|
||||
private static DeveloperSettingsProvider _instance;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton instance of the provider.
|
||||
/// </summary>
|
||||
public static DeveloperSettingsProvider Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null && Application.isPlaying)
|
||||
{
|
||||
_instance = FindFirstObjectByType<DeveloperSettingsProvider>();
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject go = new GameObject("DeveloperSettingsProvider");
|
||||
_instance = go.AddComponent<DeveloperSettingsProvider>();
|
||||
// Don't destroy between scenes
|
||||
DontDestroyOnLoad(go);
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
// Dictionary to cache loaded settings
|
||||
private Dictionary<System.Type, BaseDeveloperSettings> _settingsCache = new Dictionary<System.Type, BaseDeveloperSettings>();
|
||||
|
||||
// Path prefix for addressable developer settings
|
||||
[SerializeField] private string _addressablePath = "Settings/Developer";
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_instance != null && _instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
_instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
// Initialize settings cache
|
||||
_settingsCache = new Dictionary<System.Type, BaseDeveloperSettings>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or loads developer settings of the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of developer settings to retrieve</typeparam>
|
||||
/// <returns>The settings instance or null if not found</returns>
|
||||
public T GetSettings<T>() 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 Addressables if not cached
|
||||
string key = $"{_addressablePath}/{type.Name}";
|
||||
|
||||
try
|
||||
{
|
||||
T settings = Addressables.LoadAssetAsync<T>(key).WaitForCompletion();
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
_settingsCache[type] = settings;
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to load developer settings at '{key}': {e.Message}");
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Developer settings of type {type.Name} not found at addressable path '{key}'");
|
||||
|
||||
// Fallback to Resources for backward compatibility
|
||||
T resourcesSettings = Resources.Load<T>($"{_addressablePath}/{type.Name}");
|
||||
if (resourcesSettings != null)
|
||||
{
|
||||
Debug.Log($"Found developer settings in Resources instead of Addressables at '{_addressablePath}/{type.Name}'");
|
||||
_settingsCache[type] = resourcesSettings;
|
||||
return resourcesSettings;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the settings cache, forcing settings to be reloaded.
|
||||
/// </summary>
|
||||
public void ClearCache()
|
||||
{
|
||||
_settingsCache.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9945aa4a563434e973ab49176259150
|
||||
timeCreated: 1758707186
|
||||
246
Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs
Normal file
246
Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum defining the type of bump response when player collides with obstacles
|
||||
/// </summary>
|
||||
public enum BumpMode
|
||||
{
|
||||
Impulse = 0,
|
||||
SmoothToCenter = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Developer settings for the diving minigame technical configuration.
|
||||
/// These settings are separate from gameplay/design settings and focus on technical implementation details.
|
||||
/// </summary>
|
||||
[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")]
|
||||
[Layer]
|
||||
[SerializeField] private int obstacleLayer = 9;
|
||||
|
||||
[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;
|
||||
|
||||
[Header("Trench Tile System")]
|
||||
[Tooltip("Layer for trench tiles to be placed on")]
|
||||
[Layer]
|
||||
[SerializeField] private int trenchTileLayer = 13; // QuarryTrenchTile layer
|
||||
|
||||
[Tooltip("Whether to use object pooling for trench tiles")]
|
||||
[SerializeField] private bool trenchTileUseObjectPooling = true;
|
||||
|
||||
[Tooltip("Maximum objects per prefab type in trench tile pool")]
|
||||
[SerializeField] private int trenchTileMaxPerPrefabPoolSize = 2;
|
||||
|
||||
[Tooltip("Total maximum size of trench tile pool across all prefab types")]
|
||||
[SerializeField] private int trenchTileTotalMaxPoolSize = 10;
|
||||
|
||||
[Header("Player Blink Behavior")]
|
||||
[Tooltip("Color to blink to when taking damage (typically red for damage indication)")]
|
||||
[SerializeField] private Color playerBlinkDamageColor = Color.red;
|
||||
|
||||
[Tooltip("How fast to blink between normal and damage colors (seconds between color changes)")]
|
||||
[SerializeField] private float playerBlinkRate = 0.15f;
|
||||
|
||||
[Tooltip("Alpha value for the damage color (0 = transparent, 1 = opaque)")]
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float playerDamageColorAlpha = 0.7f;
|
||||
|
||||
[Header("Player Wobble Behavior")]
|
||||
[Tooltip("Frequency of wobble (higher = faster rocking)")]
|
||||
[SerializeField] private float playerWobbleFrequency = 1.5f;
|
||||
|
||||
[Tooltip("Base wobble amplitude in degrees from horizontal")]
|
||||
[SerializeField] private float playerBaseWobbleAmplitude = 8f;
|
||||
|
||||
[Tooltip("How much speed affects amplitude")]
|
||||
[SerializeField] private float playerSpeedToAmplitude = 2f;
|
||||
|
||||
[Tooltip("Maximum allowed rotation in degrees")]
|
||||
[SerializeField] private float playerMaxRotationLimit = 45f;
|
||||
|
||||
[Tooltip("Frequency of vertical bobbing")]
|
||||
[SerializeField] private float playerVerticalFrequency = 0.5f;
|
||||
|
||||
[Tooltip("How far the object moves up/down")]
|
||||
[SerializeField] private float playerVerticalAmplitude = 0.5f;
|
||||
|
||||
[Tooltip("How quickly velocity changes are smoothed")]
|
||||
[SerializeField] private float playerVelocitySmoothing = 10f;
|
||||
|
||||
[Tooltip("How quickly rotation is smoothed")]
|
||||
[SerializeField] private float playerRotationSmoothing = 10f;
|
||||
|
||||
[Header("Collision Settings")]
|
||||
[Tooltip("Layer mask for obstacle detection - configure which layers contain obstacles")]
|
||||
[LayerMask]
|
||||
[SerializeField] private LayerMask playerObstacleLayerMask = -1;
|
||||
|
||||
[Tooltip("Whether to block player input during damage immunity period")]
|
||||
[SerializeField] private bool blockInputDuringImmunity = true;
|
||||
|
||||
[Tooltip("Type of bump response: 0=Impulse, 1=SmoothToCenter")]
|
||||
[SerializeField] private BumpMode bumpMode = BumpMode.Impulse;
|
||||
|
||||
[Tooltip("Animation curve controlling bump movement over time")]
|
||||
[SerializeField] private AnimationCurve bumpCurve = new AnimationCurve(
|
||||
new Keyframe(0f, 0f, 0f, 2f),
|
||||
new Keyframe(1f, 1f, 0f, 0f));
|
||||
|
||||
// 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 bool ObstacleUseObjectPooling => obstacleUseObjectPooling;
|
||||
public int ObstacleMaxPerPrefabPoolSize => obstacleMaxPerPrefabPoolSize;
|
||||
public int ObstacleTotalMaxPoolSize => obstacleTotalMaxPoolSize;
|
||||
|
||||
// Trench Tile System properties
|
||||
public int TrenchTileLayer => trenchTileLayer;
|
||||
public bool TrenchTileUseObjectPooling => trenchTileUseObjectPooling;
|
||||
public int TrenchTileMaxPerPrefabPoolSize => trenchTileMaxPerPrefabPoolSize;
|
||||
public int TrenchTileTotalMaxPoolSize => trenchTileTotalMaxPoolSize;
|
||||
|
||||
// Player Blink Behavior properties
|
||||
public Color PlayerBlinkDamageColor => playerBlinkDamageColor;
|
||||
public float PlayerBlinkRate => playerBlinkRate;
|
||||
public float PlayerDamageColorAlpha => playerDamageColorAlpha;
|
||||
|
||||
// Player Wobble Behavior properties
|
||||
public float PlayerWobbleFrequency => playerWobbleFrequency;
|
||||
public float PlayerBaseWobbleAmplitude => playerBaseWobbleAmplitude;
|
||||
public float PlayerSpeedToAmplitude => playerSpeedToAmplitude;
|
||||
public float PlayerMaxRotationLimit => playerMaxRotationLimit;
|
||||
public float PlayerVerticalFrequency => playerVerticalFrequency;
|
||||
public float PlayerVerticalAmplitude => playerVerticalAmplitude;
|
||||
public float PlayerVelocitySmoothing => playerVelocitySmoothing;
|
||||
public float PlayerRotationSmoothing => playerRotationSmoothing;
|
||||
|
||||
// Collision Settings properties
|
||||
public LayerMask PlayerObstacleLayerMask => playerObstacleLayerMask;
|
||||
public bool BlockInputDuringImmunity => blockInputDuringImmunity;
|
||||
public BumpMode BumpMode => bumpMode;
|
||||
public AnimationCurve BumpCurve => bumpCurve;
|
||||
|
||||
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);
|
||||
|
||||
// Validate Trench Tile settings
|
||||
trenchTileMaxPerPrefabPoolSize = Mathf.Max(1, trenchTileMaxPerPrefabPoolSize);
|
||||
trenchTileTotalMaxPoolSize = Mathf.Max(trenchTileMaxPerPrefabPoolSize, trenchTileTotalMaxPoolSize);
|
||||
|
||||
// Validate Player Blink settings
|
||||
playerBlinkRate = Mathf.Max(0.01f, playerBlinkRate);
|
||||
playerDamageColorAlpha = Mathf.Clamp01(playerDamageColorAlpha);
|
||||
|
||||
// Validate Player Wobble settings
|
||||
playerWobbleFrequency = Mathf.Max(0.01f, playerWobbleFrequency);
|
||||
playerBaseWobbleAmplitude = Mathf.Max(0f, playerBaseWobbleAmplitude);
|
||||
playerMaxRotationLimit = Mathf.Max(0f, playerMaxRotationLimit);
|
||||
playerVerticalFrequency = Mathf.Max(0.01f, playerVerticalFrequency);
|
||||
playerVerticalAmplitude = Mathf.Max(0f, playerVerticalAmplitude);
|
||||
playerVelocitySmoothing = Mathf.Max(0.1f, playerVelocitySmoothing);
|
||||
playerRotationSmoothing = Mathf.Max(0.1f, playerRotationSmoothing);
|
||||
|
||||
// Validate Collision settings
|
||||
bumpMode = (BumpMode)Mathf.Clamp((int)bumpMode, 0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 033961b12e7b4289838d554c2264bacd
|
||||
timeCreated: 1758707215
|
||||
234
Assets/Scripts/Core/Settings/DivingMinigameSettings.cs
Normal file
234
Assets/Scripts/Core/Settings/DivingMinigameSettings.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings related to minigames
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "MinigameSettings", menuName = "AppleHills/Settings/Minigames", order = 3)]
|
||||
public class DivingMinigameSettings : BaseSettings, IDivingMinigameSettings
|
||||
{
|
||||
[Header("Basic Movement")]
|
||||
[Tooltip("How quickly the character follows the finger horizontally (higher = more responsive)")]
|
||||
[SerializeField] private float lerpSpeed = 12f;
|
||||
|
||||
[Tooltip("Maximum horizontal offset allowed between character and finger position")]
|
||||
[SerializeField] private float maxOffset = 3f;
|
||||
|
||||
[Tooltip("Minimum allowed X position for movement")]
|
||||
[SerializeField] private float clampXMin = -3.5f;
|
||||
|
||||
[Tooltip("Maximum allowed X position for movement")]
|
||||
[SerializeField] private float clampXMax = 3.5f;
|
||||
|
||||
[Tooltip("Exponent for speed drop-off curve (higher = sharper drop near target)")]
|
||||
[SerializeField] private float speedExponent = 2.5f;
|
||||
|
||||
[Header("Player 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;
|
||||
|
||||
[Header("Monster Spawning")]
|
||||
[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;
|
||||
|
||||
[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("Surfacing")]
|
||||
[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;
|
||||
|
||||
[Header("Tile Generation")]
|
||||
[Tooltip("Initial number of tiles to create at start")]
|
||||
[SerializeField] private int initialTileCount = 3;
|
||||
|
||||
[Tooltip("Buffer distance for spawning new tiles")]
|
||||
[SerializeField] private float tileSpawnBuffer = 1f;
|
||||
|
||||
[Tooltip("Base movement speed for tiles")]
|
||||
[SerializeField] private float moveSpeed = 3f;
|
||||
|
||||
[Tooltip("Factor to increase speed by each interval")]
|
||||
[SerializeField] private float speedUpFactor = 0.2f;
|
||||
|
||||
[Tooltip("Time interval between speed increases (seconds)")]
|
||||
[SerializeField] private float speedUpInterval = 10f;
|
||||
|
||||
[Tooltip("Maximum movement speed allowed")]
|
||||
[SerializeField] private float maxMoveSpeed = 12f;
|
||||
|
||||
[Tooltip("Interval for velocity calculations (seconds)")]
|
||||
[SerializeField] private float velocityCalculationInterval = 0.5f;
|
||||
|
||||
[Header("Obstacles")]
|
||||
[Tooltip("Time interval between obstacle spawn attempts (in seconds)")]
|
||||
[SerializeField] private float obstacleSpawnInterval = 2f;
|
||||
|
||||
[Tooltip("Random variation in obstacle spawn timing (+/- seconds)")]
|
||||
[SerializeField] private float obstacleSpawnIntervalVariation = 0.5f;
|
||||
|
||||
[Tooltip("Maximum number of obstacle spawn position attempts before skipping")]
|
||||
[SerializeField] private int obstacleMaxSpawnAttempts = 10;
|
||||
|
||||
[Tooltip("Radius around obstacle spawn point to check for tile collisions")]
|
||||
[SerializeField] private float obstacleSpawnCollisionRadius = 1f;
|
||||
|
||||
[Tooltip("Minimum movement speed for spawned obstacles")]
|
||||
[SerializeField] private float obstacleMinMoveSpeed = 1f;
|
||||
|
||||
[Tooltip("Maximum movement speed for spawned obstacles")]
|
||||
[SerializeField] private float obstacleMaxMoveSpeed = 4f;
|
||||
|
||||
[Header("Collision Handling")]
|
||||
[Tooltip("Duration in seconds of damage immunity after being hit")]
|
||||
[SerializeField] private float damageImmunityDuration = 1.0f;
|
||||
|
||||
[Tooltip("Force strength for impulse bumps - higher values push further toward center")]
|
||||
[SerializeField] private float bumpForce = 5.0f;
|
||||
|
||||
[Tooltip("Speed for smooth movement to center (units per second)")]
|
||||
[SerializeField] private float smoothMoveSpeed = 8.0f;
|
||||
|
||||
[Tooltip("Whether to block player input during bump movement")]
|
||||
[SerializeField] private bool blockInputDuringBump = true;
|
||||
|
||||
// IDivingMinigameSettings implementation - Basic Movement
|
||||
public float LerpSpeed => lerpSpeed;
|
||||
public float MaxOffset => maxOffset;
|
||||
public float ClampXMin => clampXMin;
|
||||
public float ClampXMax => clampXMax;
|
||||
public float SpeedExponent => speedExponent;
|
||||
|
||||
// IDivingMinigameSettings implementation - Player Movement
|
||||
public float TapMaxDistance => tapMaxDistance;
|
||||
public float TapDecelerationRate => tapDecelerationRate;
|
||||
|
||||
// IDivingMinigameSettings implementation - Monster Spawning
|
||||
public float BaseSpawnProbability => baseSpawnProbability;
|
||||
public float MaxSpawnProbability => maxSpawnProbability;
|
||||
public float ProbabilityIncreaseRate => probabilityIncreaseRate;
|
||||
public float GuaranteedSpawnTime => guaranteedSpawnTime;
|
||||
public float SpawnCooldown => spawnCooldown;
|
||||
|
||||
// IDivingMinigameSettings implementation - Scoring
|
||||
public int BasePoints => basePoints;
|
||||
public int DepthMultiplier => depthMultiplier;
|
||||
|
||||
// IDivingMinigameSettings implementation - Surfacing
|
||||
public float SpeedTransitionDuration => speedTransitionDuration;
|
||||
public float SurfacingSpeedFactor => surfacingSpeedFactor;
|
||||
public float SurfacingSpawnDelay => surfacingSpawnDelay;
|
||||
|
||||
// IDivingMinigameSettings implementation - Tile Generation
|
||||
public int InitialTileCount => initialTileCount;
|
||||
public float TileSpawnBuffer => tileSpawnBuffer;
|
||||
public float MoveSpeed => moveSpeed;
|
||||
public float SpeedUpFactor => speedUpFactor;
|
||||
public float SpeedUpInterval => speedUpInterval;
|
||||
public float MaxMoveSpeed => maxMoveSpeed;
|
||||
public float VelocityCalculationInterval => velocityCalculationInterval;
|
||||
|
||||
// IDivingMinigameSettings implementation - Obstacles
|
||||
public float ObstacleSpawnInterval => obstacleSpawnInterval;
|
||||
public float ObstacleSpawnIntervalVariation => obstacleSpawnIntervalVariation;
|
||||
public int ObstacleMaxSpawnAttempts => obstacleMaxSpawnAttempts;
|
||||
public float ObstacleSpawnCollisionRadius => obstacleSpawnCollisionRadius;
|
||||
public float ObstacleMinMoveSpeed => obstacleMinMoveSpeed;
|
||||
public float ObstacleMaxMoveSpeed => obstacleMaxMoveSpeed;
|
||||
|
||||
// IDivingMinigameSettings implementation - Collision Handling
|
||||
public float DamageImmunityDuration => damageImmunityDuration;
|
||||
public float BumpForce => bumpForce;
|
||||
public float SmoothMoveSpeed => smoothMoveSpeed;
|
||||
public bool BlockInputDuringBump => blockInputDuringBump;
|
||||
|
||||
public override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
|
||||
// Validate basic movement values
|
||||
lerpSpeed = Mathf.Max(0.1f, lerpSpeed);
|
||||
maxOffset = Mathf.Max(0.1f, maxOffset);
|
||||
speedExponent = Mathf.Max(0.1f, speedExponent);
|
||||
|
||||
// Ensure min is less than max for clamping
|
||||
if (clampXMin >= clampXMax)
|
||||
{
|
||||
clampXMin = clampXMax - 0.1f;
|
||||
}
|
||||
|
||||
// Validate player movement
|
||||
tapMaxDistance = Mathf.Max(0.01f, tapMaxDistance);
|
||||
tapDecelerationRate = Mathf.Max(0.1f, tapDecelerationRate);
|
||||
|
||||
// Validate probability values
|
||||
baseSpawnProbability = Mathf.Clamp01(baseSpawnProbability);
|
||||
maxSpawnProbability = Mathf.Clamp01(maxSpawnProbability);
|
||||
probabilityIncreaseRate = Mathf.Max(0f, probabilityIncreaseRate);
|
||||
|
||||
// Ensure max probability is at least base probability
|
||||
if (maxSpawnProbability < baseSpawnProbability)
|
||||
{
|
||||
maxSpawnProbability = baseSpawnProbability;
|
||||
}
|
||||
|
||||
// Validate time values
|
||||
guaranteedSpawnTime = Mathf.Max(0.1f, guaranteedSpawnTime);
|
||||
spawnCooldown = Mathf.Max(0.1f, spawnCooldown);
|
||||
speedTransitionDuration = Mathf.Max(0.1f, speedTransitionDuration);
|
||||
surfacingSpawnDelay = Mathf.Max(0f, surfacingSpawnDelay);
|
||||
|
||||
// Validate scoring
|
||||
basePoints = Mathf.Max(0, basePoints);
|
||||
depthMultiplier = Mathf.Max(0, depthMultiplier);
|
||||
|
||||
// Validate tile generation
|
||||
initialTileCount = Mathf.Max(1, initialTileCount);
|
||||
tileSpawnBuffer = Mathf.Max(0f, tileSpawnBuffer);
|
||||
moveSpeed = Mathf.Max(0.1f, moveSpeed);
|
||||
speedUpFactor = Mathf.Max(0f, speedUpFactor);
|
||||
speedUpInterval = Mathf.Max(0.1f, speedUpInterval);
|
||||
maxMoveSpeed = Mathf.Max(moveSpeed, maxMoveSpeed);
|
||||
velocityCalculationInterval = Mathf.Max(0.01f, velocityCalculationInterval);
|
||||
|
||||
// Validate obstacle values
|
||||
obstacleSpawnInterval = Mathf.Max(0.1f, obstacleSpawnInterval);
|
||||
obstacleSpawnIntervalVariation = Mathf.Max(0f, obstacleSpawnIntervalVariation);
|
||||
obstacleMaxSpawnAttempts = Mathf.Max(1, obstacleMaxSpawnAttempts);
|
||||
obstacleSpawnCollisionRadius = Mathf.Max(0.1f, obstacleSpawnCollisionRadius);
|
||||
obstacleMinMoveSpeed = Mathf.Max(0.1f, obstacleMinMoveSpeed);
|
||||
obstacleMaxMoveSpeed = Mathf.Max(obstacleMinMoveSpeed, obstacleMaxMoveSpeed);
|
||||
|
||||
// Validate collision settings
|
||||
damageImmunityDuration = Mathf.Max(0.1f, damageImmunityDuration);
|
||||
bumpForce = Mathf.Max(0.1f, bumpForce);
|
||||
smoothMoveSpeed = Mathf.Max(0.1f, smoothMoveSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ce4dba7a1c54e73b1b3d7131a1c0570
|
||||
timeCreated: 1758619927
|
||||
48
Assets/Scripts/Core/Settings/InteractionSettings.cs
Normal file
48
Assets/Scripts/Core/Settings/InteractionSettings.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings related to interactions and items
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "InteractionSettings", menuName = "AppleHills/Settings/Interaction & Items", order = 2)]
|
||||
public class InteractionSettings : BaseSettings, IInteractionSettings
|
||||
{
|
||||
[Header("Interactions")]
|
||||
[SerializeField] private float playerStopDistance = 6.0f;
|
||||
[SerializeField] private float playerStopDistanceDirectInteraction = 2.0f;
|
||||
[SerializeField] private float followerPickupDelay = 0.2f;
|
||||
|
||||
[Header("InputManager Settings")]
|
||||
[Tooltip("Layer(s) to use for interactable objects.")]
|
||||
[SerializeField] private LayerMask interactableLayerMask = -1; // Default to Everything
|
||||
|
||||
[Header("Default Prefabs")]
|
||||
[SerializeField] private GameObject basePickupPrefab;
|
||||
[SerializeField] private GameObject levelSwitchMenuPrefab;
|
||||
|
||||
[Header("Item Configuration")]
|
||||
[SerializeField] private List<CombinationRule> combinationRules = new List<CombinationRule>();
|
||||
[SerializeField] private List<SlotItemConfig> slotItemConfigs = new List<SlotItemConfig>();
|
||||
|
||||
// IInteractionSettings implementation
|
||||
public float PlayerStopDistance => playerStopDistance;
|
||||
public float PlayerStopDistanceDirectInteraction => playerStopDistanceDirectInteraction;
|
||||
public float FollowerPickupDelay => followerPickupDelay;
|
||||
public LayerMask InteractableLayerMask => interactableLayerMask;
|
||||
public GameObject BasePickupPrefab => basePickupPrefab;
|
||||
public GameObject LevelSwitchMenuPrefab => levelSwitchMenuPrefab;
|
||||
public List<CombinationRule> CombinationRules => combinationRules;
|
||||
public List<SlotItemConfig> SlotItemConfigs => slotItemConfigs;
|
||||
|
||||
public override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
// Validate values
|
||||
playerStopDistance = Mathf.Max(0.1f, playerStopDistance);
|
||||
playerStopDistanceDirectInteraction = Mathf.Max(0.1f, playerStopDistanceDirectInteraction);
|
||||
followerPickupDelay = Mathf.Max(0f, followerPickupDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/InteractionSettings.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/InteractionSettings.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac22b092dc6f4db5b3dad35172b6e4c4
|
||||
timeCreated: 1758619914
|
||||
27
Assets/Scripts/Core/Settings/ItemConfigTypes.cs
Normal file
27
Assets/Scripts/Core/Settings/ItemConfigTypes.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a rule for combining two items
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class CombinationRule
|
||||
{
|
||||
public PickupItemData itemA;
|
||||
public PickupItemData itemB;
|
||||
public GameObject resultPrefab; // The prefab to spawn as the result
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for items that can be placed in slots
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class SlotItemConfig
|
||||
{
|
||||
public PickupItemData slotItem; // The slot object (SO reference)
|
||||
public List<PickupItemData> allowedItems;
|
||||
public List<PickupItemData> forbiddenItems; // Items that cannot be placed in this slot
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/ItemConfigTypes.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/ItemConfigTypes.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f9547445fd84c7db30533b7ee9d81dd
|
||||
timeCreated: 1758699048
|
||||
20
Assets/Scripts/Core/Settings/LayerAttributes.cs
Normal file
20
Assets/Scripts/Core/Settings/LayerAttributes.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to indicate a field should be drawn using the layer selector dropdown
|
||||
/// </summary>
|
||||
public class LayerAttribute : PropertyAttribute
|
||||
{
|
||||
// No properties needed - this is a marker attribute
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attribute to indicate a field should be drawn using the layer mask selector dropdown
|
||||
/// </summary>
|
||||
public class LayerMaskAttribute : PropertyAttribute
|
||||
{
|
||||
// No properties needed - this is a marker attribute
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/LayerAttributes.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/LayerAttributes.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c64dbd728524f23bda766b57a388207
|
||||
timeCreated: 1758711688
|
||||
13
Assets/Scripts/Core/Settings/MovementModeTypes.cs
Normal file
13
Assets/Scripts/Core/Settings/MovementModeTypes.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum defining different movement modes for player movement
|
||||
/// </summary>
|
||||
public enum HoldMovementMode
|
||||
{
|
||||
Pathfinding,
|
||||
Direct
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/MovementModeTypes.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/MovementModeTypes.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6b1454235ab476dae09e99238d6c7ce
|
||||
timeCreated: 1758699033
|
||||
53
Assets/Scripts/Core/Settings/PlayerFollowerSettings.cs
Normal file
53
Assets/Scripts/Core/Settings/PlayerFollowerSettings.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings related to player and follower behavior
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "PlayerFollowerSettings", menuName = "AppleHills/Settings/Player & Follower", order = 1)]
|
||||
public class PlayerFollowerSettings : BaseSettings, IPlayerFollowerSettings
|
||||
{
|
||||
[Header("Player Settings")]
|
||||
[SerializeField] private float moveSpeed = 5f;
|
||||
[SerializeField] private float stopDistance = 0.1f;
|
||||
[SerializeField] private bool useRigidbody = true;
|
||||
[SerializeField] private HoldMovementMode defaultHoldMovementMode = HoldMovementMode.Pathfinding;
|
||||
|
||||
[Header("Follower Settings")]
|
||||
[SerializeField] private float followDistance = 1.5f;
|
||||
[SerializeField] private float manualMoveSmooth = 8f;
|
||||
[SerializeField] private float thresholdFar = 2.5f;
|
||||
[SerializeField] private float thresholdNear = 0.5f;
|
||||
[SerializeField] private float stopThreshold = 0.1f;
|
||||
|
||||
[Header("Backend Settings")]
|
||||
[Tooltip("Technical parameters, not for design tuning")]
|
||||
[SerializeField] private float followUpdateInterval = 0.1f;
|
||||
[SerializeField] private float followerSpeedMultiplier = 1.2f;
|
||||
[SerializeField] private float heldIconDisplayHeight = 2.0f;
|
||||
|
||||
// IPlayerFollowerSettings implementation
|
||||
public float MoveSpeed => moveSpeed;
|
||||
public float StopDistance => stopDistance;
|
||||
public bool UseRigidbody => useRigidbody;
|
||||
public HoldMovementMode DefaultHoldMovementMode => defaultHoldMovementMode;
|
||||
public float FollowDistance => followDistance;
|
||||
public float ManualMoveSmooth => manualMoveSmooth;
|
||||
public float ThresholdFar => thresholdFar;
|
||||
public float ThresholdNear => thresholdNear;
|
||||
public float StopThreshold => stopThreshold;
|
||||
public float FollowUpdateInterval => followUpdateInterval;
|
||||
public float FollowerSpeedMultiplier => followerSpeedMultiplier;
|
||||
public float HeldIconDisplayHeight => heldIconDisplayHeight;
|
||||
|
||||
public override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
// Validate values
|
||||
moveSpeed = Mathf.Max(0.1f, moveSpeed);
|
||||
followDistance = Mathf.Max(0.1f, followDistance);
|
||||
followerSpeedMultiplier = Mathf.Max(0.1f, followerSpeedMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32cd6d14d9304d5ba0fd590da1346654
|
||||
timeCreated: 1758619904
|
||||
51
Assets/Scripts/Core/Settings/ServiceLocator.cs
Normal file
51
Assets/Scripts/Core/Settings/ServiceLocator.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Service Locator implementation for managing settings services.
|
||||
/// Provides a central registry for all settings services.
|
||||
/// </summary>
|
||||
public static class ServiceLocator
|
||||
{
|
||||
private static readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Register a service with the service locator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The interface type for the service</typeparam>
|
||||
/// <param name="service">The service implementation</param>
|
||||
public static void Register<T>(T service) where T : class
|
||||
{
|
||||
_services[typeof(T)] = service;
|
||||
Debug.Log($"Service registered: {typeof(T).Name}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a service from the service locator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The interface type for the service</typeparam>
|
||||
/// <returns>The service implementation, or null if not found</returns>
|
||||
public static T Get<T>() where T : class
|
||||
{
|
||||
if (_services.TryGetValue(typeof(T), out object service))
|
||||
{
|
||||
return service as T;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Service of type {typeof(T).Name} not found!");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all registered services.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
_services.Clear();
|
||||
Debug.Log("All services cleared");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/ServiceLocator.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/ServiceLocator.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16cc39d2f99b4e7fa65c4a8b39f3e87c
|
||||
timeCreated: 1758619866
|
||||
98
Assets/Scripts/Core/Settings/SettingsInterfaces.cs
Normal file
98
Assets/Scripts/Core/Settings/SettingsInterfaces.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for player and follower settings
|
||||
/// </summary>
|
||||
public interface IPlayerFollowerSettings
|
||||
{
|
||||
// Player settings
|
||||
float MoveSpeed { get; }
|
||||
float StopDistance { get; }
|
||||
bool UseRigidbody { get; }
|
||||
HoldMovementMode DefaultHoldMovementMode { get; }
|
||||
|
||||
// Follower settings
|
||||
float FollowDistance { get; }
|
||||
float ManualMoveSmooth { get; }
|
||||
float ThresholdFar { get; }
|
||||
float ThresholdNear { get; }
|
||||
float StopThreshold { get; }
|
||||
float FollowUpdateInterval { get; }
|
||||
float FollowerSpeedMultiplier { get; }
|
||||
float HeldIconDisplayHeight { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for interaction and item settings
|
||||
/// </summary>
|
||||
public interface IInteractionSettings
|
||||
{
|
||||
float PlayerStopDistance { get; }
|
||||
float PlayerStopDistanceDirectInteraction { get; }
|
||||
float FollowerPickupDelay { get; }
|
||||
LayerMask InteractableLayerMask { get; }
|
||||
GameObject BasePickupPrefab { get; }
|
||||
GameObject LevelSwitchMenuPrefab { get; }
|
||||
List<CombinationRule> CombinationRules { get; }
|
||||
List<SlotItemConfig> SlotItemConfigs { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for minigame settings
|
||||
/// </summary>
|
||||
public interface IDivingMinigameSettings
|
||||
{
|
||||
// Basic Movement
|
||||
float LerpSpeed { get; }
|
||||
float MaxOffset { get; }
|
||||
float ClampXMin { get; }
|
||||
float ClampXMax { get; }
|
||||
float SpeedExponent { get; }
|
||||
|
||||
// Player Movement
|
||||
float TapMaxDistance { get; }
|
||||
float TapDecelerationRate { get; }
|
||||
|
||||
// Monster Spawning
|
||||
float BaseSpawnProbability { get; }
|
||||
float MaxSpawnProbability { get; }
|
||||
float ProbabilityIncreaseRate { get; }
|
||||
float GuaranteedSpawnTime { get; }
|
||||
float SpawnCooldown { get; }
|
||||
|
||||
// Scoring
|
||||
int BasePoints { get; }
|
||||
int DepthMultiplier { get; }
|
||||
|
||||
// Surfacing
|
||||
float SpeedTransitionDuration { get; }
|
||||
float SurfacingSpeedFactor { get; }
|
||||
float SurfacingSpawnDelay { get; }
|
||||
|
||||
// Tile Generation
|
||||
int InitialTileCount { get; }
|
||||
float TileSpawnBuffer { get; }
|
||||
float MoveSpeed { get; }
|
||||
float SpeedUpFactor { get; }
|
||||
float SpeedUpInterval { get; }
|
||||
float MaxMoveSpeed { get; }
|
||||
float VelocityCalculationInterval { get; }
|
||||
|
||||
// Obstacles
|
||||
float ObstacleSpawnInterval { get; }
|
||||
float ObstacleSpawnIntervalVariation { get; }
|
||||
int ObstacleMaxSpawnAttempts { get; }
|
||||
float ObstacleSpawnCollisionRadius { get; }
|
||||
float ObstacleMinMoveSpeed { get; }
|
||||
float ObstacleMaxMoveSpeed { get; }
|
||||
|
||||
// Collision Handling
|
||||
float DamageImmunityDuration { get; }
|
||||
float BumpForce { get; }
|
||||
float SmoothMoveSpeed { get; }
|
||||
bool BlockInputDuringBump { get; }
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/SettingsInterfaces.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/SettingsInterfaces.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54611ae012ab4455a53bd60961d9e7ea
|
||||
timeCreated: 1758619892
|
||||
100
Assets/Scripts/Core/Settings/SettingsProvider.cs
Normal file
100
Assets/Scripts/Core/Settings/SettingsProvider.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Responsible for loading and caching settings from Addressables.
|
||||
/// Uses synchronous loading to ensure settings are available immediately.
|
||||
/// </summary>
|
||||
public class SettingsProvider : MonoBehaviour
|
||||
{
|
||||
private static SettingsProvider _instance;
|
||||
private Dictionary<string, BaseSettings> _settingsCache = new Dictionary<string, BaseSettings>();
|
||||
|
||||
// Singleton instance
|
||||
public static SettingsProvider Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject go = new GameObject("Settings Provider");
|
||||
_instance = go.AddComponent<SettingsProvider>();
|
||||
DontDestroyOnLoad(go);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else if (_instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load settings synchronously using Addressables - blocks until complete
|
||||
/// </summary>
|
||||
public T LoadSettingsSynchronous<T>() where T : BaseSettings
|
||||
{
|
||||
string key = typeof(T).Name;
|
||||
|
||||
// Return from cache if already loaded
|
||||
if (_settingsCache.TryGetValue(key, out BaseSettings cachedSettings))
|
||||
{
|
||||
return cachedSettings as T;
|
||||
}
|
||||
|
||||
// Load using Addressables synchronously
|
||||
try
|
||||
{
|
||||
// WaitForCompletion blocks until the asset is loaded
|
||||
T settings = Addressables.LoadAssetAsync<T>($"Settings/{key}").WaitForCompletion();
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
_settingsCache[key] = settings;
|
||||
return settings;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to load settings: {key}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Error loading settings {key}: {e.Message}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get cached settings or load them synchronously if not cached
|
||||
/// </summary>
|
||||
public T GetSettings<T>() where T : BaseSettings
|
||||
{
|
||||
string key = typeof(T).Name;
|
||||
|
||||
// Return from cache if already loaded
|
||||
if (_settingsCache.TryGetValue(key, out BaseSettings cachedSettings))
|
||||
{
|
||||
return cachedSettings as T;
|
||||
}
|
||||
|
||||
// Load synchronously if not in cache
|
||||
return LoadSettingsSynchronous<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Core/Settings/SettingsProvider.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/SettingsProvider.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d212b25192045d198f2bf42ef74f278
|
||||
timeCreated: 1758619879
|
||||
Reference in New Issue
Block a user