Files
AppleHillsProduction/Assets/Scripts/Minigames/BirdPooper/TargetSpawner.cs

221 lines
7.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using Core;
using Core.Settings;
using Core.Lifecycle;
using AppleHillsCamera;
namespace Minigames.BirdPooper
{
/// <summary>
/// Spawns targets at regular intervals for Bird Pooper minigame.
/// Uses Transform references for spawn and despawn positions.
/// All targets are spawned at Y = 0 (EdgeAnchor positions them vertically).
/// </summary>
public class TargetSpawner : ManagedBehaviour
{
[Header("Spawn Configuration")]
[Tooltip("Transform marking where targets spawn (off-screen right)")]
[SerializeField] private Transform spawnPoint;
[Tooltip("Transform marking where targets despawn (off-screen left)")]
[SerializeField] private Transform despawnPoint;
[Header("EdgeAnchor References")]
[Tooltip("ScreenReferenceMarker to pass to spawned targets")]
[SerializeField] private ScreenReferenceMarker referenceMarker;
[Tooltip("CameraScreenAdapter to pass to spawned targets")]
[SerializeField] private CameraScreenAdapter cameraAdapter;
[Header("Target Prefabs")]
[Tooltip("Array of target prefabs to spawn randomly")]
[SerializeField] private GameObject[] targetPrefabs;
private IBirdPooperSettings settings;
private float spawnTimer;
private bool isSpawning;
private float _currentTargetInterval = 1f;
[Header("Spawn Timing")]
[Tooltip("Minimum interval between target spawns (seconds)")]
[SerializeField] private float minTargetSpawnInterval = 1f;
[Tooltip("Maximum interval between target spawns (seconds)")]
[SerializeField] private float maxTargetSpawnInterval = 2f;
internal override void OnManagedAwake()
{
base.OnManagedAwake();
// Load settings
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
if (settings == null)
{
Debug.LogError("[TargetSpawner] BirdPooperSettings not found!");
// continue we'll use inspector intervals
}
// Validate interval range
if (minTargetSpawnInterval < 0f) minTargetSpawnInterval = 0f;
if (maxTargetSpawnInterval < 0f) maxTargetSpawnInterval = 0f;
if (minTargetSpawnInterval > maxTargetSpawnInterval)
{
float tmp = minTargetSpawnInterval;
minTargetSpawnInterval = maxTargetSpawnInterval;
maxTargetSpawnInterval = tmp;
Debug.LogWarning("[TargetSpawner] minTargetSpawnInterval was greater than maxTargetSpawnInterval. Values were swapped.");
}
// Validate references
if (spawnPoint == null)
{
Debug.LogError("[TargetSpawner] Spawn Point not assigned! Please assign a Transform in the Inspector.");
}
if (despawnPoint == null)
{
Debug.LogError("[TargetSpawner] Despawn Point not assigned! Please assign a Transform in the Inspector.");
}
if (targetPrefabs == null || targetPrefabs.Length == 0)
{
Debug.LogError("[TargetSpawner] No target prefabs assigned! Please assign at least one prefab in the Inspector.");
}
if (referenceMarker == null)
{
Debug.LogError("[TargetSpawner] ScreenReferenceMarker not assigned! Targets need this for EdgeAnchor positioning.");
}
if (cameraAdapter == null)
{
Debug.LogWarning("[TargetSpawner] CameraScreenAdapter not assigned. EdgeAnchor will attempt to auto-find camera.");
}
Debug.Log("[TargetSpawner] Initialized successfully");
}
private void Update()
{
if (!isSpawning)
return;
spawnTimer += Time.deltaTime;
if (spawnTimer >= _currentTargetInterval)
{
SpawnTarget();
spawnTimer = 0f;
// pick next random interval
_currentTargetInterval = Random.Range(minTargetSpawnInterval, maxTargetSpawnInterval);
}
}
/// <summary>
/// Spawns a random target prefab at the spawn point.
/// Target is spawned at Y = 0, EdgeAnchor will position it vertically.
/// </summary>
private void SpawnTarget()
{
if (targetPrefabs == null || targetPrefabs.Length == 0 || spawnPoint == null)
{
Debug.LogError("[TargetSpawner] Cannot spawn target - missing prefabs or spawn point!");
return;
}
// Randomly select target prefab
GameObject prefab = targetPrefabs[Random.Range(0, targetPrefabs.Length)];
// Spawn at spawn point X, but Y = 0 (EdgeAnchor will position vertically)
Vector3 spawnPosition = new Vector3(spawnPoint.position.x, 0f, 0f);
GameObject targetObj = Instantiate(prefab, spawnPosition, Quaternion.identity);
// Initialize target
Target target = targetObj.GetComponent<Target>();
if (target != null)
{
float despawnX = despawnPoint != null ? despawnPoint.position.x : -12f;
target.Initialize(despawnX, referenceMarker, cameraAdapter);
// Subscribe to target hit event to notify manager
target.onTargetHit.AddListener(OnTargetHit);
Debug.Log($"[TargetSpawner] Spawned target at {spawnPosition}");
}
else
{
Debug.LogError($"[TargetSpawner] Spawned prefab '{prefab.name}' does not have Target component!");
Destroy(targetObj);
}
}
/// <summary>
/// Called when a target is hit by a projectile.
/// Notifies the game manager for score tracking.
/// </summary>
private void OnTargetHit()
{
// Find and notify manager
BirdPooperGameManager manager = BirdPooperGameManager.Instance;
if (manager != null)
{
manager.OnTargetHit();
}
else
{
Debug.LogWarning("[TargetSpawner] BirdPooperGameManager not found!");
}
}
/// <summary>
/// Start spawning targets at regular intervals.
/// </summary>
public void StartSpawning()
{
isSpawning = true;
spawnTimer = 0f;
// choose initial interval
_currentTargetInterval = Random.Range(minTargetSpawnInterval, maxTargetSpawnInterval);
Debug.Log("[TargetSpawner] Started spawning targets");
}
/// <summary>
/// Stop spawning new targets (existing targets continue).
/// </summary>
public void StopSpawning()
{
isSpawning = false;
Debug.Log("[TargetSpawner] Stopped spawning targets");
}
/// <summary>
/// Check if spawner is currently spawning.
/// </summary>
public bool IsSpawning => isSpawning;
/// <summary>
/// Draw gizmos to visualize spawn and despawn points in the editor.
/// </summary>
private void OnDrawGizmos()
{
if (spawnPoint != null)
{
Gizmos.color = Color.cyan;
Gizmos.DrawLine(
new Vector3(spawnPoint.position.x, -10f, 0f),
new Vector3(spawnPoint.position.x, 10f, 0f)
);
}
if (despawnPoint != null)
{
Gizmos.color = Color.magenta;
Gizmos.DrawLine(
new Vector3(despawnPoint.position.x, -10f, 0f),
new Vector3(despawnPoint.position.x, 10f, 0f)
);
}
}
}
}