using System; using System.Collections.Generic; using Escape_Room_Engine.Engine.Scripts.Modules; using Escape_Room_Engine.Engine.Scripts.Requirements; using UnityEngine; using LogType = Escape_Room_Engine.Engine.Scripts.Utilities.LogType; using Object = UnityEngine.Object; namespace Escape_Room_Engine.Engine.Scripts { public class Space { /// /// The room relative (RR) dimensions of this space. /// internal readonly Dimensions rrDimensions; internal List Modules { get; } = new(2); private GameObject _spaceObject; internal Space(Passage entrance) { rrDimensions = GenerateSpaceDimensions( entrance, Engine.DefaultEngine.config.minRoomSize, Engine.DefaultEngine.config.playSpace); // connect the space to its passage entrance.ConnectTo(new DoorModule(this, ((DoorModuleDescription)entrance.fromOut.description).connectedDoorDescription)); AddModule(entrance.toIn); } internal void AddModule(Module module) { Modules.Add(module); } internal bool AddModuleWithRequirements(Module module) { var requirementsFulfilled = PlacementRequirement.TryPlacing(module, this) && OrientationRequirement.TryOrienting(module, this); if (requirementsFulfilled) { AddModule(module); } return requirementsFulfilled; } internal void InstantiateSpace(Transform parent, string name) { _spaceObject = new GameObject($"Space {name}", typeof(MeshFilter), typeof(MeshRenderer)); _spaceObject.transform.SetParent(parent, false); _spaceObject.transform.localPosition = new Vector3(rrDimensions.x, 0, rrDimensions.z); var meshFilter = _spaceObject.GetComponent(); meshFilter.mesh = GenerateMesh(); var meshRenderer = _spaceObject.GetComponent(); meshRenderer.material = Engine.DefaultEngine.roomMaterial; // instantiate all modules inside this space Modules.ForEach(module => module.InstantiateModule(_spaceObject.transform)); } /// /// Convert a position relative to this space to one relative to the room. /// /// The space relative (SR) position that should be converted to a room relative (RR) position. internal Vector2Int ToRoomRelative(Vector2Int srPosition) => srPosition + rrDimensions.Position; /// /// Convert a position relative to the room to one relative to this space. /// /// The room relative (RR) position that should be converted to a space relative (SR) position. internal Vector2Int ToSpaceRelative(Vector2Int rrPosition) => rrPosition - rrDimensions.Position; private Mesh GenerateMesh() { var mesh = new Mesh(); mesh.vertices = new[] { new Vector3(0, 0, 0), new Vector3(rrDimensions.width, 0, 0), new Vector3(0, 0, rrDimensions.length), new Vector3(rrDimensions.width, 0, rrDimensions.length) }; mesh.triangles = new[] { 0, 2, 1, 2, 3, 1 }; var normal = Vector3.up; mesh.normals = new[] { normal, normal, normal, normal }; mesh.uv = new[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 1), new Vector2(1, 1) }; return mesh; } internal void Destroy() { Object.Destroy(_spaceObject); } /// /// Generate space dimensions that fit the required size constraints and cover the position of the entrance. /// /// The generated room relative (RR) dimensions. private static Dimensions GenerateSpaceDimensions(Passage entrance, Vector2Int minSize, Vector2Int availableSpace) { var xMin = -1; var xMax = -1; var zMin = -1; var zMax = -1; var position = entrance.rrPosition; var door = entrance.fromOut; // fix the side the door is facing away from switch (door.orientation) { case Orientation.North: zMin = position.y; zMax = Utilities.Utilities.RandomInclusive(zMin + minSize.y, availableSpace.y); break; case Orientation.East: xMin = position.x; xMax = Utilities.Utilities.RandomInclusive(xMin + minSize.x, availableSpace.x); break; case Orientation.South: zMax = position.y + 1; zMin = Utilities.Utilities.RandomInclusive(0, zMax - minSize.y); break; case Orientation.West: xMax = position.x + 1; xMin = Utilities.Utilities.RandomInclusive(0, xMax - minSize.x); break; default: throw new ArgumentOutOfRangeException(); } // calculate remaining values if they haven't been covered by the switch statement yet if(xMin == -1) xMin = Utilities.Utilities.RandomInclusive(0, Math.Min(position.x, availableSpace.x - minSize.x)); if(xMax == -1) xMax = Utilities.Utilities.RandomInclusive(Math.Max(position.x + 1, xMin + minSize.x), availableSpace.x); if(zMin == -1) zMin = Utilities.Utilities.RandomInclusive(0, Math.Min(position.y, availableSpace.y - minSize.y)); if(zMax == -1) zMax = Utilities.Utilities.RandomInclusive(Math.Max(position.y + 1, zMin + minSize.y), availableSpace.y); var dimensions = new Dimensions(xMax - xMin, zMax - zMin, xMin, zMin); Utilities.Logger.Log($"Generated space dimensions {dimensions} from entrance position {position}", LogType.RoomGeneration); return dimensions; } } }