using System.Collections.Generic;
using UnityEngine;
namespace MazeGen
{
///
/// Single entry point for milestone 1: drop this on one empty GameObject in the scene
/// and press Play. It creates the generator, agent and path visualizer, spawns the
/// start room(s), and lets you click yellow exit markers to walk the agent through them.
///
[RequireComponent(typeof(MazeGenerator))]
public class MazeSceneBuilder : MonoBehaviour
{
[SerializeField, Min(1)] private int startRoomCount = 1;
[SerializeField] private float startRoomSpread = 6f;
private MazeGenerator _generator;
private MazeAgentController _agentController;
private PathVisualizer _pathVisualizer;
private MazeCameraController _cameraController;
private readonly Dictionary _exitMarkers = new Dictionary();
private void Awake()
{
_generator = GetComponent();
_generator.RoomGenerated += OnRoomGenerated;
_generator.ExitAdded += OnExitAdded;
var agentGO = new GameObject("Agent");
agentGO.transform.SetParent(transform, false);
_agentController = agentGO.AddComponent();
_agentController.Initialize(_generator);
var pathGO = new GameObject("PathVisualizer");
pathGO.transform.SetParent(transform, false);
pathGO.AddComponent();
_pathVisualizer = pathGO.AddComponent();
var cam = Camera.main;
if (cam != null)
{
_cameraController = cam.GetComponent();
if (_cameraController == null)
_cameraController = cam.gameObject.AddComponent();
}
}
private void Start()
{
Room firstStartRoom = null;
for (int i = 0; i < startRoomCount; i++)
{
float angle = startRoomCount > 1 ? (360f / startRoomCount) * i : 0f;
Vector2 pos = startRoomCount > 1
? new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad)) * startRoomSpread
: Vector2.zero;
var room = _generator.GenerateStartRoom(pos);
firstStartRoom ??= room;
}
// Milestone 1: single agent spawns in the first start room.
_agentController.Spawn(firstStartRoom);
_agentController.Agent.RoomEntered += room => _pathVisualizer.AppendPoint(room.Position);
_agentController.Agent.RoomEntered += room => _cameraController?.FocusOn(room.Position);
_agentController.Agent.ReachedExitRoom += room => Debug.Log($"[MazeGen] Agent reached the exit room (id {room.Id})!");
_pathVisualizer.AppendPoint(firstStartRoom.Position);
_cameraController?.SnapTo(firstStartRoom.Position);
RefreshMarkerVisuals();
}
private void OnRoomGenerated(Room room)
{
var roomGO = new GameObject($"Room_{room.Id}_{room.Kind}");
roomGO.transform.SetParent(transform, false);
roomGO.AddComponent().Initialize(room);
foreach (var exit in room.Exits)
SpawnExitMarker(room, exit);
}
private void OnExitAdded(Room room, Exit exit)
{
SpawnExitMarker(room, exit);
RefreshMarkerVisuals();
}
private void SpawnExitMarker(Room room, Exit exit)
{
var markerGO = new GameObject($"Exit_{exit.Id}");
markerGO.transform.SetParent(transform, false);
var marker = markerGO.AddComponent();
marker.Initialize(room, exit);
_exitMarkers[exit.Id] = marker;
}
private void Update()
{
if (!MazeInput.WasLeftClickedThisFrame()) return;
Camera cam = Camera.main;
if (cam == null) return;
Ray ray = cam.ScreenPointToRay(MazeInput.GetPointerScreenPosition());
RaycastHit2D hit = Physics2D.GetRayIntersection(ray, Mathf.Infinity);
if (hit.collider != null && hit.collider.TryGetComponent(out ExitMarker marker))
OnExitClicked(marker.ExitData);
}
private void OnExitClicked(Exit exit)
{
if (_agentController.Agent == null || exit.OwnerRoomId != _agentController.Agent.CurrentRoom.Id)
{
Debug.Log("[MazeGen] That exit isn't reachable from your current room.");
return;
}
if (_agentController.TryUseExit(exit))
RefreshMarkerVisuals();
}
private void RefreshMarkerVisuals()
{
Room currentRoom = _agentController.Agent?.CurrentRoom;
MazeAgent agent = _agentController.Agent;
foreach (var marker in _exitMarkers.Values)
marker.UpdateVisual(currentRoom, agent);
}
}
}