Files
LowPolyBattleSim/Assets/Scripts/SpawnManager.cs
Caleb Sandford deQuincey ecdd3e2a9e intial commit
2025-06-27 23:27:49 +01:00

352 lines
10 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using System.Collections;
public class SpawnManager : MonoBehaviour
{
[Header("Spawn Configuration")]
[SerializeField] private GameObject unitPrefab; // The base unit prefab to spawn
[SerializeField] private Transform playerSpawnArea;
[SerializeField] private Transform enemySpawnArea;
[Header("Spawn Patterns")]
[SerializeField] private float spawnRadius = 5f;
[SerializeField] private float unitSpacing = 2f;
[SerializeField] private bool useFormationSpawning = true;
[Header("Unit Data Assets")]
[SerializeField] private UnitData[] playerUnitTypes;
[SerializeField] private UnitData[] enemyUnitTypes;
[Header("Auto Spawn Settings")]
[SerializeField] private bool autoSpawnOnStart = false;
[SerializeField] private int defaultPlayerUnits = 5;
[SerializeField] private int defaultEnemyUnits = 5;
[Header("Wave Spawning")]
[SerializeField] private bool enableWaveSpawning = false;
[SerializeField] private float timeBetweenWaves = 30f;
[SerializeField] private int unitsPerWave = 3;
// Events
public System.Action<UnitController> OnUnitSpawned;
public System.Action<Team, int> OnWaveSpawned;
// Private variables
private BattleManager battleManager;
private List<UnitController> spawnedUnits = new List<UnitController>();
private int currentWave = 0;
private bool waveSpawningActive = false;
private void Start()
{
battleManager = FindFirstObjectByType<BattleManager>();
if (autoSpawnOnStart)
{
StartCoroutine(AutoSpawnInitialUnits());
}
}
private IEnumerator AutoSpawnInitialUnits()
{
yield return new WaitForSeconds(0.1f); // Wait a frame for initialization
SpawnUnitsForTeam(Team.Player, defaultPlayerUnits);
yield return new WaitForSeconds(0.1f);
SpawnUnitsForTeam(Team.Enemy, defaultEnemyUnits);
if (enableWaveSpawning)
{
StartWaveSpawning();
}
}
#region Public Spawn Methods
/// <summary>
/// Spawn a single unit with specific data and team
/// </summary>
public UnitController SpawnUnit(UnitData unitData, Team team, Vector3? position = null)
{
if (unitPrefab == null)
{
Debug.LogError("Unit prefab is not assigned in SpawnManager!");
return null;
}
if (unitData == null)
{
Debug.LogError("UnitData is null!");
return null;
}
// Determine spawn position
Vector3 spawnPos = position ?? GetSpawnPosition(team);
// Instantiate the unit
GameObject unitObj = Instantiate(unitPrefab, spawnPos, Quaternion.identity);
unitObj.name = $"{team}_{unitData.unitName}_{spawnedUnits.Count}";
// Configure the unit
UnitController unitController = unitObj.GetComponent<UnitController>();
if (unitController == null)
{
unitController = unitObj.AddComponent<UnitController>();
}
// Set up the unit
unitController.unitData = unitData;
unitController.team = team;
unitController.unitId = spawnedUnits.Count;
// Add required components if missing
EnsureRequiredComponents(unitObj, unitData);
// Add to tracking
spawnedUnits.Add(unitController);
// Notify battle manager
if (battleManager != null)
{
battleManager.RegisterUnit(unitController);
}
// Fire event
OnUnitSpawned?.Invoke(unitController);
Debug.Log($"Spawned {unitData.unitName} for {team} at {spawnPos}");
return unitController;
}
/// <summary>
/// Spawn multiple units for a specific team
/// </summary>
public List<UnitController> SpawnUnitsForTeam(Team team, int count)
{
List<UnitController> spawnedTeamUnits = new List<UnitController>();
UnitData[] unitTypes = team == Team.Player ? playerUnitTypes : enemyUnitTypes;
if (unitTypes == null || unitTypes.Length == 0)
{
Debug.LogWarning($"No unit types configured for {team}!");
return spawnedTeamUnits;
}
for (int i = 0; i < count; i++)
{
// Randomly select unit type
UnitData selectedUnitData = unitTypes[Random.Range(0, unitTypes.Length)];
// Spawn the unit
UnitController unit = SpawnUnit(selectedUnitData, team);
if (unit != null)
{
spawnedTeamUnits.Add(unit);
}
}
return spawnedTeamUnits;
}
/// <summary>
/// Spawn units in a formation pattern
/// </summary>
public List<UnitController> SpawnFormation(Team team, UnitData unitData, int rows, int columns, Vector3? centerPosition = null)
{
List<UnitController> formationUnits = new List<UnitController>();
Vector3 center = centerPosition ?? GetSpawnPosition(team);
float spacing = unitSpacing;
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < columns; col++)
{
Vector3 offset = new Vector3(
(col - columns / 2f) * spacing,
0,
(row - rows / 2f) * spacing
);
Vector3 spawnPos = center + offset;
UnitController unit = SpawnUnit(unitData, team, spawnPos);
if (unit != null)
{
formationUnits.Add(unit);
// Set formation position for AI
unit.SetFormationPosition(spawnPos);
}
}
}
return formationUnits;
}
#endregion
#region Wave Spawning
public void StartWaveSpawning()
{
if (!waveSpawningActive)
{
waveSpawningActive = true;
StartCoroutine(WaveSpawningCoroutine());
}
}
public void StopWaveSpawning()
{
waveSpawningActive = false;
}
private IEnumerator WaveSpawningCoroutine()
{
while (waveSpawningActive)
{
yield return new WaitForSeconds(timeBetweenWaves);
if (battleManager != null && battleManager.battleStarted)
{
SpawnWave();
}
}
}
private void SpawnWave()
{
currentWave++;
// Spawn reinforcements for both teams
SpawnUnitsForTeam(Team.Player, unitsPerWave);
SpawnUnitsForTeam(Team.Enemy, unitsPerWave);
OnWaveSpawned?.Invoke(Team.Player, currentWave);
OnWaveSpawned?.Invoke(Team.Enemy, currentWave);
Debug.Log($"Wave {currentWave} spawned! {unitsPerWave} units per team.");
}
#endregion
#region Utility Methods
private Vector3 GetSpawnPosition(Team team)
{
Transform spawnArea = team == Team.Player ? playerSpawnArea : enemySpawnArea;
if (spawnArea == null)
{
Debug.LogWarning($"No spawn area set for {team}! Using default position.");
return team == Team.Player ? Vector3.left * 10 : Vector3.right * 10;
}
if (useFormationSpawning)
{
return spawnArea.position;
}
else
{
// Random position within spawn radius
Vector2 randomCircle = Random.insideUnitCircle * spawnRadius;
return spawnArea.position + new Vector3(randomCircle.x, 0, randomCircle.y);
}
}
private void EnsureRequiredComponents(GameObject unitObj, UnitData unitData)
{
// Ensure NavMeshAgent
if (unitObj.GetComponent<UnityEngine.AI.NavMeshAgent>() == null)
{
var navAgent = unitObj.AddComponent<UnityEngine.AI.NavMeshAgent>();
navAgent.speed = unitData.moveSpeed;
navAgent.angularSpeed = unitData.rotationSpeed;
navAgent.acceleration = 8f;
navAgent.stoppingDistance = unitData.attackRange * 0.8f;
}
// Ensure Rigidbody (if needed)
if (unitObj.GetComponent<Rigidbody>() == null)
{
var rb = unitObj.AddComponent<Rigidbody>();
rb.mass = 1f;
rb.linearDamping = 5f;
rb.freezeRotation = true;
}
// Ensure Collider
if (unitObj.GetComponent<Collider>() == null)
{
var collider = unitObj.AddComponent<CapsuleCollider>();
collider.height = 2f;
collider.radius = 0.5f;
}
// Add UnitSightSystem if using RaycastPro
if (unitData.autoConfigureSightDetector && unitObj.GetComponent<UnitSightSystem>() == null)
{
unitObj.AddComponent<UnitSightSystem>();
}
}
/// <summary>
/// Clear all spawned units
/// </summary>
public void ClearAllUnits()
{
foreach (UnitController unit in spawnedUnits)
{
if (unit != null)
{
DestroyImmediate(unit.gameObject);
}
}
spawnedUnits.Clear();
currentWave = 0;
}
/// <summary>
/// Get all spawned units for a specific team
/// </summary>
public List<UnitController> GetUnitsForTeam(Team team)
{
List<UnitController> teamUnits = new List<UnitController>();
foreach (UnitController unit in spawnedUnits)
{
if (unit != null && unit.team == team)
{
teamUnits.Add(unit);
}
}
return teamUnits;
}
#endregion
#region Editor Helpers
private void OnDrawGizmosSelected()
{
// Draw spawn areas
if (playerSpawnArea != null)
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(playerSpawnArea.position, spawnRadius);
Gizmos.DrawIcon(playerSpawnArea.position, "sv_icon_dot0_pix16_gizmo", false);
}
if (enemySpawnArea != null)
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(enemySpawnArea.position, spawnRadius);
Gizmos.DrawIcon(enemySpawnArea.position, "sv_icon_dot1_pix16_gizmo", false);
}
}
#endregion
}