185 lines
6.4 KiB
C#
185 lines
6.4 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using Core;
|
|||
|
|
using Core.Settings;
|
|||
|
|
using Core.Lifecycle;
|
|||
|
|
using AppleHillsCamera;
|
|||
|
|
|
|||
|
|
namespace Minigames.BirdPooper
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 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).
|
|||
|
|
/// </summary>
|
|||
|
|
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<IBirdPooperSettings>();
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Spawn a random obstacle at the spawn point position (Y = 0).
|
|||
|
|
/// </summary>
|
|||
|
|
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<Obstacle>();
|
|||
|
|
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}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Start spawning obstacles.
|
|||
|
|
/// Spawns the first obstacle immediately, then continues with interval-based spawning.
|
|||
|
|
/// </summary>
|
|||
|
|
public void StartSpawning()
|
|||
|
|
{
|
|||
|
|
isSpawning = true;
|
|||
|
|
spawnTimer = 0f;
|
|||
|
|
|
|||
|
|
// Spawn the first obstacle immediately
|
|||
|
|
SpawnObstacle();
|
|||
|
|
|
|||
|
|
Debug.Log("[ObstacleSpawner] Started spawning (first obstacle spawned immediately)");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Stop spawning obstacles.
|
|||
|
|
/// </summary>
|
|||
|
|
public void StopSpawning()
|
|||
|
|
{
|
|||
|
|
isSpawning = false;
|
|||
|
|
Debug.Log("[ObstacleSpawner] Stopped spawning");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Check if spawner is currently active.
|
|||
|
|
/// </summary>
|
|||
|
|
public bool IsSpawning => isSpawning;
|
|||
|
|
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
/// <summary>
|
|||
|
|
/// Draw gizmos in editor to visualize spawn/despawn points.
|
|||
|
|
/// </summary>
|
|||
|
|
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
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|