using UnityEngine; using System.Collections.Generic; using System; using UnityEngine.Events; namespace Minigames.DivingForPictures { public class DivingGameManager : MonoBehaviour { [Header("Monster Prefabs")] [Tooltip("Array of monster prefabs to spawn randomly")] [SerializeField] private GameObject[] monsterPrefabs; [Header("Spawn Probability")] [Tooltip("Base chance (0-1) of spawning a monster on each tile")] [SerializeField] private float baseSpawnProbability = 0.2f; [Tooltip("Maximum chance (0-1) of spawning a monster")] [SerializeField] private float maxSpawnProbability = 0.5f; [Tooltip("How fast the probability increases per second")] [SerializeField] private float probabilityIncreaseRate = 0.01f; [Header("Spawn Timing")] [Tooltip("Force a spawn after this many seconds without spawns")] [SerializeField] private float guaranteedSpawnTime = 30f; [Tooltip("Minimum time between monster spawns")] [SerializeField] private float spawnCooldown = 5f; [Header("Scoring")] [Tooltip("Base points for taking a picture")] [SerializeField] private int basePoints = 100; [Tooltip("Additional points per depth unit")] [SerializeField] private int depthMultiplier = 10; // Private state variables private int playerScore = 0; private float currentSpawnProbability; private float lastSpawnTime = -100f; private float timeSinceLastSpawn = 0f; private List activeMonsters = new List(); // Public properties public int PlayerScore => playerScore; // Events public event Action OnScoreChanged; public event Action OnMonsterSpawned; public event Action OnPictureTaken; public event Action OnSpawnProbabilityChanged; private void Awake() { currentSpawnProbability = baseSpawnProbability; } private void Start() { // Subscribe to tile spawned event TrenchTileSpawner tileSpawner = FindFirstObjectByType(); if (tileSpawner != null) { tileSpawner.onTileSpawned.AddListener(OnTileSpawned); } else { Debug.LogWarning("No TrenchTileSpawner found in scene. Monster spawning won't work."); } } private void Update() { timeSinceLastSpawn += Time.deltaTime; // Gradually increase spawn probability over time float previousProbability = currentSpawnProbability; if (currentSpawnProbability < maxSpawnProbability) { currentSpawnProbability += probabilityIncreaseRate * Time.deltaTime; currentSpawnProbability = Mathf.Min(currentSpawnProbability, maxSpawnProbability); // Only fire event if probability changed significantly if (Mathf.Abs(currentSpawnProbability - previousProbability) > 0.01f) { OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability); } } } private void OnTileSpawned(GameObject tile) { // Check for spawn points in the new tile MonsterSpawnPoint[] spawnPoints = tile.GetComponentsInChildren(); if (spawnPoints.Length == 0) return; bool forceSpawn = timeSinceLastSpawn >= guaranteedSpawnTime; bool onCooldown = timeSinceLastSpawn < spawnCooldown; // Don't spawn if on cooldown, unless forced if (onCooldown && !forceSpawn) return; // Check probability or forced spawn if (forceSpawn || UnityEngine.Random.value <= currentSpawnProbability) { // Pick a random spawn point from this tile MonsterSpawnPoint spawnPoint = spawnPoints[UnityEngine.Random.Range(0, spawnPoints.Length)]; // Spawn the monster at the spawn point and parent it SpawnMonster(spawnPoint.transform); // Reset timer and adjust probability lastSpawnTime = Time.time; timeSinceLastSpawn = 0f; currentSpawnProbability = baseSpawnProbability; OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability); } } private void SpawnMonster(Transform spawnPoint) { if (monsterPrefabs.Length == 0) { Debug.LogWarning("No monster prefabs assigned to DivingGameManager."); return; } // Select random monster prefab GameObject prefab = monsterPrefabs[UnityEngine.Random.Range(0, monsterPrefabs.Length)]; // Instantiate monster at spawn point position GameObject monsterObj = Instantiate(prefab, spawnPoint.position, Quaternion.identity); Monster monster = monsterObj.GetComponent(); if (monster != null) { // Parent the monster to the spawn point so it moves with the tile monsterObj.transform.SetParent(spawnPoint); // Subscribe to monster events monster.OnPictureTaken += OnMonsterPictureTaken; monster.OnMonsterDespawned += OnMonsterDespawned; // Add to active monsters list activeMonsters.Add(monster); // Fire event OnMonsterSpawned?.Invoke(monster); } else { Debug.LogError($"Monster prefab {prefab.name} does not have a Monster component!"); Destroy(monsterObj); } } private void OnMonsterPictureTaken(Monster monster) { // Calculate points based on depth int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * depthMultiplier); int pointsAwarded = basePoints + depthBonus; // Add score playerScore += pointsAwarded; // Fire events OnScoreChanged?.Invoke(playerScore); OnPictureTaken?.Invoke(monster, pointsAwarded); } private void OnMonsterDespawned(Monster monster) { // Remove from active list activeMonsters.Remove(monster); // Unsubscribe from events monster.OnPictureTaken -= OnMonsterPictureTaken; monster.OnMonsterDespawned -= OnMonsterDespawned; } // Call this when the game ends public void EndGame() { // Clean up active monsters foreach (var monster in activeMonsters.ToArray()) { if (monster != null) { monster.DespawnMonster(); } } activeMonsters.Clear(); // Final score could be saved to player prefs or other persistence Debug.Log($"Final Score: {playerScore}"); } } }