352 lines
10 KiB
C#
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
|
|
}
|