using UnityEngine; using System.Collections.Generic; /// /// Manages spawning and tracking of AI agents in the maze /// Supports configurable spawn counts and runtime spawning /// public class AIAgentManager : MonoBehaviour { [Header("Agent Spawning")] [SerializeField] private int initialAgentCount = 10; [SerializeField] private string agentCharacterType = "Default"; [SerializeField] private float spawnDelay = 0.1f; [Header("Agent Prefab")] [SerializeField] private GameObject agentPrefab; [Header("Visual Settings")] [SerializeField] private bool showAgentPaths = true; [SerializeField] private Color agentPathColor = Color.yellow; [SerializeField] private Material agentMaterial; private MazeController mazeController; private List activeAgents = new(); private int nextAgentId = 0; private bool isInitialized = false; void Awake() { mazeController = GetComponent(); if (mazeController == null) { mazeController = FindAnyObjectByType(); } } void Start() { if (mazeController == null) { Debug.LogError("AIAgentManager: MazeController not found!"); enabled = false; return; } // Create agent prefab if not assigned if (agentPrefab == null) { CreateDefaultAgentPrefab(); } // Spawn initial agents StartCoroutine(SpawnAgentsCoroutine(initialAgentCount)); isInitialized = true; } /// /// Creates a default agent prefab if one isn't assigned /// private void CreateDefaultAgentPrefab() { GameObject prefab = new GameObject("AIAgent"); prefab.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f); // Use 3D collider instead of 2D for 3D environment var collider = prefab.AddComponent(); collider.radius = 0.4f; // Add mesh renderer with a simple sphere var meshFilter = prefab.AddComponent(); var meshRenderer = prefab.AddComponent(); // Use Unity's built-in sphere primitive mesh meshFilter.mesh = Resources.GetBuiltinResource("Sphere.fbx"); // Create a cyan material using URP shader (Universal Render Pipeline) var mat = new Material(Shader.Find("Universal Render Pipeline/Lit")); if (mat.shader == null) { // Fallback to simpler URP shader if Lit is not available mat = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); } if (mat.shader == null) { // Last resort - use Standard shader mat = new Material(Shader.Find("Standard")); } mat.color = Color.cyan; meshRenderer.material = mat; prefab.AddComponent(); agentPrefab = prefab; } /// /// Spawns agents with delay /// private System.Collections.IEnumerator SpawnAgentsCoroutine(int count) { for (int i = 0; i < count; i++) { SpawnAgent(); yield return new WaitForSeconds(spawnDelay); } } /// /// Spawns a single AI agent /// public AIAgent SpawnAgent() { if (agentPrefab == null) { Debug.LogError("AIAgentManager: Agent prefab not set!"); return null; } GameObject agentGO = Instantiate(agentPrefab); agentGO.name = $"AIAgent_{agentCharacterType}_{nextAgentId}"; var agent = agentGO.GetComponent(); if (agent == null) { agent = agentGO.AddComponent(); } // Set agent properties via reflection or public properties var idField = typeof(AIAgent).GetField("agentId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var typeField = typeof(AIAgent).GetField("agentCharacterType", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (idField != null) idField.SetValue(agent, nextAgentId); if (typeField != null) typeField.SetValue(agent, agentCharacterType); activeAgents.Add(agent); nextAgentId++; Debug.Log($"Spawned agent {nextAgentId - 1} ({agentCharacterType}). Total agents: {activeAgents.Count}"); return agent; } /// /// Spawns multiple agents at once /// public void SpawnAgents(int count) { StartCoroutine(SpawnAgentsCoroutine(count)); } /// /// Removes and destroys an agent /// public void RemoveAgent(AIAgent agent) { if (activeAgents.Remove(agent)) { Destroy(agent.gameObject); Debug.Log($"Removed agent {agent.AgentId}. Remaining: {activeAgents.Count}"); } } /// /// Gets agents of a specific character type /// public List GetAgentsByType(string characterType) { var agents = new List(); foreach (var agent in activeAgents) { if (agent.CharacterType == characterType) { agents.Add(agent); } } return agents; } /// /// Gets the count of active agents /// public int GetAgentCount() { return activeAgents.Count; } /// /// Gets agent count by character type /// public int GetAgentCountByType(string characterType) { return GetAgentsByType(characterType).Count; } /// /// Clears all agents and resets /// public void ClearAllAgents() { foreach (var agent in activeAgents) { Destroy(agent.gameObject); } activeAgents.Clear(); nextAgentId = 0; AIRoomMemoryManager.ClearAllMemories(); } /// /// Resets agents for a new maze /// public void ResetForNewMaze() { ClearAllAgents(); if (isInitialized) { StartCoroutine(SpawnAgentsCoroutine(initialAgentCount)); } } /// /// Gets UI info about agents /// public string GetAgentStats() { int total = activeAgents.Count; string stats = $"Total Agents: {total}\n"; var typeGroups = new Dictionary(); foreach (var agent in activeAgents) { if (!typeGroups.ContainsKey(agent.CharacterType)) { typeGroups[agent.CharacterType] = 0; } typeGroups[agent.CharacterType]++; } foreach (var kvp in typeGroups) { var memory = AIRoomMemoryManager.GetMemory(kvp.Key); stats += $"{kvp.Key}: {kvp.Value} agents, {memory.VisitedCount} rooms explored\n"; } return stats; } /// /// Gets the initial agent count setting /// public int InitialAgentCount => initialAgentCount; /// /// Sets the initial agent count (affects next reset) /// public void SetInitialAgentCount(int count) { initialAgentCount = count; } /// /// Gets the count of active agents /// public int GetActiveAgentCount() { return activeAgents.Count; } /// /// Gets the list of active agents /// public List GetActiveAgents() { return activeAgents; } }