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 OnUnitSpawned; public System.Action OnWaveSpawned; // Private variables private BattleManager battleManager; private List spawnedUnits = new List(); private int currentWave = 0; private bool waveSpawningActive = false; private void Start() { battleManager = FindFirstObjectByType(); 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 /// /// Spawn a single unit with specific data and team /// 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(); if (unitController == null) { unitController = unitObj.AddComponent(); } // 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; } /// /// Spawn multiple units for a specific team /// public List SpawnUnitsForTeam(Team team, int count) { List spawnedTeamUnits = new List(); 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; } /// /// Spawn units in a formation pattern /// public List SpawnFormation(Team team, UnitData unitData, int rows, int columns, Vector3? centerPosition = null) { List formationUnits = new List(); 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() == null) { var navAgent = unitObj.AddComponent(); navAgent.speed = unitData.moveSpeed; navAgent.angularSpeed = unitData.rotationSpeed; navAgent.acceleration = 8f; navAgent.stoppingDistance = unitData.attackRange * 0.8f; } // Ensure Rigidbody (if needed) if (unitObj.GetComponent() == null) { var rb = unitObj.AddComponent(); rb.mass = 1f; rb.linearDamping = 5f; rb.freezeRotation = true; } // Ensure Collider if (unitObj.GetComponent() == null) { var collider = unitObj.AddComponent(); collider.height = 2f; collider.radius = 0.5f; } // Add UnitSightSystem if using RaycastPro if (unitData.autoConfigureSightDetector && unitObj.GetComponent() == null) { unitObj.AddComponent(); } } /// /// Clear all spawned units /// public void ClearAllUnits() { foreach (UnitController unit in spawnedUnits) { if (unit != null) { DestroyImmediate(unit.gameObject); } } spawnedUnits.Clear(); currentWave = 0; } /// /// Get all spawned units for a specific team /// public List GetUnitsForTeam(Team team) { List teamUnits = new List(); 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 }