Add Monster Spawn points, monster head placeholders. Add utility for prefab variation by sprite selection.
This commit is contained in:
194
Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs
Normal file
194
Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
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<Monster> activeMonsters = new List<Monster>();
|
||||
|
||||
// Public properties
|
||||
public int PlayerScore => playerScore;
|
||||
|
||||
// Events
|
||||
public event Action<int> OnScoreChanged;
|
||||
public event Action<Monster> OnMonsterSpawned;
|
||||
public event Action<Monster, int> OnPictureTaken;
|
||||
public event Action<float> OnSpawnProbabilityChanged;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
currentSpawnProbability = baseSpawnProbability;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Subscribe to tile spawned event
|
||||
TrenchTileSpawner tileSpawner = FindObjectOfType<TrenchTileSpawner>();
|
||||
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<MonsterSpawnPoint>();
|
||||
|
||||
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
|
||||
SpawnMonster(spawnPoint.transform.position);
|
||||
|
||||
// Reset timer and adjust probability
|
||||
lastSpawnTime = Time.time;
|
||||
timeSinceLastSpawn = 0f;
|
||||
currentSpawnProbability = baseSpawnProbability;
|
||||
OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability);
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnMonster(Vector3 position)
|
||||
{
|
||||
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
|
||||
GameObject monsterObj = Instantiate(prefab, position, Quaternion.identity);
|
||||
Monster monster = monsterObj.GetComponent<Monster>();
|
||||
|
||||
if (monster != null)
|
||||
{
|
||||
// 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user