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;
}
}