using UnityEngine; using Pooling; namespace Minigames.DivingForPictures { /// /// Spawns bubbles at intervals, randomizing their properties and assigning a random sprite to each. /// public class BubbleSpawner : MonoBehaviour { 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 float _timer; private float _nextSpawnInterval; private BubblePool _bubblePool; private Camera _mainCamera; // Cache camera reference private bool _isSurfacing = false; void Awake() { _mainCamera = Camera.main; if (useObjectPooling) { // Create the bubble pool GameObject poolGO = new GameObject("BubblePool"); poolGO.transform.SetParent(transform); _bubblePool = poolGO.AddComponent(); _bubblePool.initialPoolSize = initialPoolSize; _bubblePool.maxPoolSize = maxPoolSize; _bubblePool.Initialize(bubblePrefab); // Periodically check for pool statistics in debug builds #if DEVELOPMENT_BUILD || UNITY_EDITOR InvokeRepeating(nameof(LogPoolStats), 5f, 30f); #endif } } void Start() { // Initialize the next spawn interval _nextSpawnInterval = GetRandomizedInterval(); } void Update() { _timer += Time.deltaTime; if (_timer >= _nextSpawnInterval) { SpawnBubble(); _timer = 0f; _nextSpawnInterval = GetRandomizedInterval(); } } /// /// Returns a randomized interval for bubble spawning. /// /// Randomized interval in seconds. float GetRandomizedInterval() { return spawnInterval * Random.Range(0.8f, 1.2f); } /// /// Spawns a bubble with randomized properties and assigns a random sprite. /// void SpawnBubble() { float x = Random.Range(spawnXMin, spawnXMax); Vector3 spawnPos = new Vector3(x, spawnY, 0f); Bubble bubble; if (useObjectPooling && _bubblePool != null) { bubble = _bubblePool.GetBubble(); bubble.transform.position = spawnPos; } else { bubble = Instantiate(bubblePrefab, spawnPos, Quaternion.identity, transform); } // Randomize bubble properties float baseSpeed = Random.Range(speedRange.x, speedRange.y); // Apply surfacing speed reduction if needed if (_isSurfacing) { bubble.speed = baseSpeed * surfacingSpeedFactor; } else { bubble.speed = baseSpeed; } bubble.wobbleSpeed = Random.Range(wobbleSpeedRange.x, wobbleSpeedRange.y); // Set base scale (initial size) for the bubble float baseScale = Random.Range(scaleRange.x, scaleRange.y); bubble.SetBaseScale(baseScale); // Assign random sprite to BubbleSprite (fixed naming from BottleSprite) if (bubbleSprites != null && bubbleSprites.Length > 0) { Sprite randomSprite = bubbleSprites[Random.Range(0, bubbleSprites.Length)]; bubble.SetBubbleSprite(randomSprite); } // Random rotation bubble.transform.rotation = Quaternion.Euler(0f, 0f, Random.Range(0f, 360f)); // Pass min/max scale for wobble clamping bubble.SetWobbleScaleLimits(wobbleMinScale, wobbleMaxScale); } /// /// Start surfacing mode - slow down all bubbles /// public void StartSurfacing() { if (_isSurfacing) return; // Already surfacing _isSurfacing = true; // Slow down all existing bubbles Bubble[] activeBubbles = FindObjectsOfType(); foreach (Bubble bubble in activeBubbles) { bubble.speed *= surfacingSpeedFactor; } Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {surfacingSpeedFactor * 100}% speed."); } /// /// Logs the current pool statistics for debugging /// private void LogPoolStats() { if (_bubblePool != null) { _bubblePool.LogPoolStats(); } } } }