using UnityEngine; using Core; using Core.Settings; using Core.Lifecycle; using AppleHillsCamera; namespace Minigames.BirdPooper { /// /// Spawns obstacles at regular intervals for Bird Pooper minigame. /// Uses Transform references for spawn and despawn positions instead of hardcoded values. /// All obstacles are spawned at Y = 0 (prefabs should be authored accordingly). /// public class ObstacleSpawner : ManagedBehaviour { [Header("Spawn Configuration")] [Tooltip("Transform marking where obstacles spawn (off-screen right)")] [SerializeField] private Transform spawnPoint; [Tooltip("Transform marking where obstacles despawn (off-screen left)")] [SerializeField] private Transform despawnPoint; [Header("EdgeAnchor References")] [Tooltip("ScreenReferenceMarker to pass to spawned obstacles")] [SerializeField] private ScreenReferenceMarker referenceMarker; [Tooltip("CameraScreenAdapter to pass to spawned obstacles")] [SerializeField] private CameraScreenAdapter cameraAdapter; [Header("Obstacle Prefabs")] [Tooltip("Array of obstacle prefabs to spawn randomly")] [SerializeField] private GameObject[] obstaclePrefabs; private IBirdPooperSettings settings; private float spawnTimer; private bool isSpawning; internal override void OnManagedAwake() { base.OnManagedAwake(); // Load settings settings = GameManager.GetSettingsObject(); if (settings == null) { Debug.LogError("[ObstacleSpawner] BirdPooperSettings not found!"); return; } // Validate references if (spawnPoint == null) { Debug.LogError("[ObstacleSpawner] Spawn Point not assigned! Please assign a Transform in the Inspector."); } if (despawnPoint == null) { Debug.LogError("[ObstacleSpawner] Despawn Point not assigned! Please assign a Transform in the Inspector."); } if (obstaclePrefabs == null || obstaclePrefabs.Length == 0) { Debug.LogError("[ObstacleSpawner] No obstacle prefabs assigned! Please assign at least one prefab in the Inspector."); } if (referenceMarker == null) { Debug.LogError("[ObstacleSpawner] ScreenReferenceMarker not assigned! Obstacles need this for EdgeAnchor positioning."); } if (cameraAdapter == null) { Debug.LogWarning("[ObstacleSpawner] CameraScreenAdapter not assigned. EdgeAnchor will attempt to auto-find camera."); } Debug.Log("[ObstacleSpawner] Initialized successfully"); } private void Update() { if (!isSpawning || settings == null || spawnPoint == null) return; spawnTimer += Time.deltaTime; if (spawnTimer >= settings.ObstacleSpawnInterval) { SpawnObstacle(); spawnTimer = 0f; } } /// /// Spawn a random obstacle at the spawn point position (Y = 0). /// private void SpawnObstacle() { if (obstaclePrefabs == null || obstaclePrefabs.Length == 0) { Debug.LogWarning("[ObstacleSpawner] No obstacle prefabs to spawn!"); return; } if (despawnPoint == null) { Debug.LogWarning("[ObstacleSpawner] Cannot spawn obstacle without despawn point reference!"); return; } // Select random prefab GameObject selectedPrefab = obstaclePrefabs[Random.Range(0, obstaclePrefabs.Length)]; // Spawn at spawn point position with Y = 0 Vector3 spawnPosition = new Vector3(spawnPoint.position.x, 0f, 0f); GameObject obstacleObj = Instantiate(selectedPrefab, spawnPosition, Quaternion.identity); // Initialize obstacle with despawn X position and EdgeAnchor references Obstacle obstacle = obstacleObj.GetComponent(); if (obstacle != null) { obstacle.Initialize(despawnPoint.position.x, referenceMarker, cameraAdapter); } else { Debug.LogError($"[ObstacleSpawner] Spawned prefab '{selectedPrefab.name}' does not have Obstacle component!"); Destroy(obstacleObj); } Debug.Log($"[ObstacleSpawner] Spawned obstacle '{selectedPrefab.name}' at position {spawnPosition}"); } /// /// Start spawning obstacles. /// Spawns the first obstacle immediately, then continues with interval-based spawning. /// public void StartSpawning() { isSpawning = true; spawnTimer = 0f; // Spawn the first obstacle immediately SpawnObstacle(); Debug.Log("[ObstacleSpawner] Started spawning (first obstacle spawned immediately)"); } /// /// Stop spawning obstacles. /// public void StopSpawning() { isSpawning = false; Debug.Log("[ObstacleSpawner] Stopped spawning"); } /// /// Check if spawner is currently active. /// public bool IsSpawning => isSpawning; #if UNITY_EDITOR /// /// Draw gizmos in editor to visualize spawn/despawn points. /// private void OnDrawGizmos() { if (spawnPoint != null) { Gizmos.color = Color.green; Gizmos.DrawLine(spawnPoint.position + Vector3.up * 10f, spawnPoint.position + Vector3.down * 10f); Gizmos.DrawWireSphere(spawnPoint.position, 0.5f); } if (despawnPoint != null) { Gizmos.color = Color.red; Gizmos.DrawLine(despawnPoint.position + Vector3.up * 10f, despawnPoint.position + Vector3.down * 10f); Gizmos.DrawWireSphere(despawnPoint.position, 0.5f); } } #endif } }