using System; using UnityEngine; namespace Minigames.BirdPooper { /// /// Container for a pool of obstacle prefabs at a specific difficulty tier. /// Pools are ordered by difficulty, with pool[0] being the easiest. /// [Serializable] public class ObstaclePool { [Tooltip("Obstacles in this difficulty tier")] public GameObject[] obstacles; } /// /// Configuration for obstacle spawning in Bird Pooper minigame. /// Includes difficulty pools, spawn timing, and diversity settings. /// [Serializable] public class ObstacleSpawnConfig { [Header("Difficulty Pools")] [Tooltip("Obstacle pools ordered by difficulty (pool[0] = easiest, always active)")] public ObstaclePool[] obstaclePools; [Tooltip("Times (in seconds) when each additional pool unlocks. Length should be obstaclePools.Length - 1. At poolUnlockTimes[i], pool[i+1] becomes available.")] public float[] poolUnlockTimes; [Header("Spawn Timing")] [Tooltip("Minimum interval between spawns (seconds) - represents high difficulty")] public float minSpawnInterval = 1f; [Tooltip("Maximum interval between spawns (seconds) - represents low difficulty")] public float maxSpawnInterval = 2f; [Header("Difficulty Scaling")] [Tooltip("Time in seconds for difficulty to ramp from 0 to 1")] public float difficultyRampDuration = 60f; [Tooltip("Curve mapping normalized time (0..1) to difficulty (0..1). Default is linear.")] public AnimationCurve difficultyCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f); [Tooltip("Maximum jitter applied to computed interval (fractional). 0.1 = +/-10% jitter")] public float intervalJitter = 0.05f; [Header("Recency / Diversity")] [Tooltip("Time in seconds it takes for a recently-used prefab to recover back to full weight")] public float recentDecayDuration = 10f; [Tooltip("Minimum weight (0..1) applied to a just-used prefab so it can still appear occasionally")] [Range(0f, 1f)] public float minRecentWeight = 0.05f; /// /// Validates the configuration and logs warnings for invalid settings. /// public void Validate() { // Validate pools if (obstaclePools == null || obstaclePools.Length == 0) { Debug.LogError("[ObstacleSpawnConfig] No obstacle pools defined!"); return; } // Validate pool unlock times int expectedUnlockTimes = obstaclePools.Length - 1; if (poolUnlockTimes == null) { Debug.LogWarning($"[ObstacleSpawnConfig] poolUnlockTimes is null. Expected {expectedUnlockTimes} entries. Only pool[0] will be available."); } else if (poolUnlockTimes.Length != expectedUnlockTimes) { Debug.LogWarning($"[ObstacleSpawnConfig] poolUnlockTimes.Length ({poolUnlockTimes.Length}) does not match expected value ({expectedUnlockTimes}). Should be obstaclePools.Length - 1."); } // Validate spawn intervals if (minSpawnInterval < 0f) { Debug.LogWarning("[ObstacleSpawnConfig] minSpawnInterval is negative. Clamping to 0."); } if (maxSpawnInterval < 0f) { Debug.LogWarning("[ObstacleSpawnConfig] maxSpawnInterval is negative. Clamping to 0."); } if (minSpawnInterval > maxSpawnInterval) { Debug.LogWarning("[ObstacleSpawnConfig] minSpawnInterval is greater than maxSpawnInterval. Values should be swapped."); } // Validate difficulty ramp if (difficultyRampDuration < 0.01f) { Debug.LogWarning("[ObstacleSpawnConfig] difficultyRampDuration is too small. Should be at least 0.01."); } // Validate recency settings if (recentDecayDuration < 0.01f) { Debug.LogWarning("[ObstacleSpawnConfig] recentDecayDuration is too small. Should be at least 0.01."); } if (minRecentWeight < 0f || minRecentWeight > 1f) { Debug.LogWarning("[ObstacleSpawnConfig] minRecentWeight should be between 0 and 1."); } } } }