diff --git a/Assets/Desert/Assets/Desert.asset b/Assets/Desert/Assets/Desert.asset index d211598..ffaed64 100644 --- a/Assets/Desert/Assets/Desert.asset +++ b/Assets/Desert/Assets/Desert.asset @@ -13,7 +13,7 @@ MonoBehaviour: m_Name: Desert m_EditorClassIdentifier: minRoomSize: {x: 3, y: 3} - playSpace: {x: 4, y: 6} + playSpace: {x: 3, y: 5} spaceTile: {fileID: 3229991053255736984, guid: b8f192f7cebe686468af6b1a71c4605b, type: 3} environment: {fileID: 5743657079028767629, guid: 17ecdbaca50efaa4ab503614dfec54a8, diff --git a/Assets/Desert/Assets/Modules/Puzzle A/Ball.asset b/Assets/Desert/Assets/Modules/Puzzle A/Ball.asset index 67a9199..5f697e4 100644 --- a/Assets/Desert/Assets/Modules/Puzzle A/Ball.asset +++ b/Assets/Desert/Assets/Modules/Puzzle A/Ball.asset @@ -19,5 +19,4 @@ MonoBehaviour: placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} - orientationRequirements: - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} diff --git a/Assets/Desert/Assets/Modules/Puzzle A/Puzzle A.asset b/Assets/Desert/Assets/Modules/Puzzle A/Puzzle A.asset index 7f2cc65..7f1ab7f 100644 --- a/Assets/Desert/Assets/Modules/Puzzle A/Puzzle A.asset +++ b/Assets/Desert/Assets/Modules/Puzzle A/Puzzle A.asset @@ -20,5 +20,4 @@ MonoBehaviour: placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} - orientationRequirements: - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} diff --git a/Assets/Desert/Assets/Modules/Puzzle B/Ball.asset b/Assets/Desert/Assets/Modules/Puzzle B/Ball.asset index 4511448..bdf2e96 100644 --- a/Assets/Desert/Assets/Modules/Puzzle B/Ball.asset +++ b/Assets/Desert/Assets/Modules/Puzzle B/Ball.asset @@ -19,5 +19,4 @@ MonoBehaviour: placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} - orientationRequirements: - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} diff --git a/Assets/Desert/Assets/Modules/Puzzle B/Puzzle B.asset b/Assets/Desert/Assets/Modules/Puzzle B/Puzzle B.asset index bb7ac67..32081a4 100644 --- a/Assets/Desert/Assets/Modules/Puzzle B/Puzzle B.asset +++ b/Assets/Desert/Assets/Modules/Puzzle B/Puzzle B.asset @@ -20,5 +20,4 @@ MonoBehaviour: placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} - orientationRequirements: - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} diff --git a/Assets/Engine/Assets/Module Descriptions/Generic Door Exit.asset b/Assets/Engine/Assets/Module Descriptions/Generic Door Exit.asset index aa88ba0..63613b1 100644 --- a/Assets/Engine/Assets/Module Descriptions/Generic Door Exit.asset +++ b/Assets/Engine/Assets/Module Descriptions/Generic Door Exit.asset @@ -15,10 +15,10 @@ MonoBehaviour: types: 01000000 modulePrefab: {fileID: 7146915386488129308, guid: d877ee36ba6ace440aebce2c20cf70d6, type: 3} + preconditionRequirements: [] placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} - orientationRequirements: - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} connectedDoorDescription: {fileID: 11400000, guid: a70cb93176094309a847f1928d6b950d, type: 2} diff --git a/Assets/Engine/Assets/Module Descriptions/Generic Module.asset b/Assets/Engine/Assets/Module Descriptions/Generic Module.asset index 2d36336..6a82031 100644 --- a/Assets/Engine/Assets/Module Descriptions/Generic Module.asset +++ b/Assets/Engine/Assets/Module Descriptions/Generic Module.asset @@ -15,6 +15,6 @@ MonoBehaviour: types: modulePrefab: {fileID: 4604142456167599783, guid: ad2655de8289afa40aa520f9fc474681, type: 3} + preconditionRequirements: [] placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - orientationRequirements: [] diff --git a/Assets/Engine/Assets/Module Descriptions/Generic Puzzle.asset b/Assets/Engine/Assets/Module Descriptions/Generic Puzzle.asset index 0f20a63..e7e203e 100644 --- a/Assets/Engine/Assets/Module Descriptions/Generic Puzzle.asset +++ b/Assets/Engine/Assets/Module Descriptions/Generic Puzzle.asset @@ -15,8 +15,8 @@ MonoBehaviour: types: 02000000 modulePrefab: {fileID: 9077423192650498975, guid: e419cb35bd744b24ea973860d8b1405d, type: 3} + preconditionRequirements: [] placementRequirements: - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} - orientationRequirements: - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} diff --git a/Assets/Engine/Runtime/Dimensions.cs b/Assets/Engine/Runtime/Dimensions.cs deleted file mode 100644 index c32d47e..0000000 --- a/Assets/Engine/Runtime/Dimensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace EscapeRoomEngine.Engine.Runtime -{ - public struct Dimensions - { - public int width; - public int length; - public int x; - public int z; - - public Vector2Int Position - { - get => new(x, z); - set - { - x = value.x; - z = value.y; - } - } - - public Vector2Int Size - { - get => new(width, length); - set - { - width = value.x; - length = value.y; - } - } - - public int Area => width * length; - - public HashSet EveryPosition - { - get - { - var positions = new HashSet(); - - for (var zIter = 0; zIter < length; zIter++) - { - for (var xIter = 0; xIter < width; xIter++) - { - positions.Add(new Vector2Int(xIter, zIter)); - } - } - - return positions; - } - } - - public override string ToString() => $"({width}, {length}) at ({x}, {z})"; - } -} \ No newline at end of file diff --git a/Assets/Engine/Runtime/Dimensions.cs.meta b/Assets/Engine/Runtime/Dimensions.cs.meta deleted file mode 100644 index c32d43b..0000000 --- a/Assets/Engine/Runtime/Dimensions.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: b70ad3679d5c48768c1d132f56dba4dd -timeCreated: 1667222427 \ No newline at end of file diff --git a/Assets/Engine/Runtime/Engine.cs b/Assets/Engine/Runtime/Engine.cs index ece0698..f682f17 100644 --- a/Assets/Engine/Runtime/Engine.cs +++ b/Assets/Engine/Runtime/Engine.cs @@ -56,7 +56,7 @@ namespace EscapeRoomEngine.Engine.Runtime Logger.Log("Generating room...", LogType.RoomGeneration); // get the last entrance from the newest room or create a spawn passage with no entrance door for where the player will start - var entrance = NumberOfRooms > 0 ? _rooms.Last().exit : new Passage(new DoorModule(null, theme.spawnDoor), true); + var entrance = NumberOfRooms > 0 ? _rooms.Last().exit : new Passage(new DoorModule(null, theme.spawnDoor)); var room = new Room(entrance); _rooms.Add(room); diff --git a/Assets/Engine/Runtime/EngineTheme.cs b/Assets/Engine/Runtime/EngineTheme.cs index 17d8a18..1e06905 100644 --- a/Assets/Engine/Runtime/EngineTheme.cs +++ b/Assets/Engine/Runtime/EngineTheme.cs @@ -45,7 +45,7 @@ namespace EscapeRoomEngine.Engine.Runtime #region Puzzles - [BoxGroup("Puzzles")] [MinMaxSlider(0, 10)] + [BoxGroup("Puzzles")] [MinMaxSlider(0, 24)] public Vector2Int puzzleCount; [BoxGroup("Puzzles")] diff --git a/Assets/Engine/Runtime/Modules/Module.cs b/Assets/Engine/Runtime/Modules/Module.cs index b1041cf..1b939c1 100644 --- a/Assets/Engine/Runtime/Modules/Module.cs +++ b/Assets/Engine/Runtime/Modules/Module.cs @@ -10,37 +10,27 @@ using Object = UnityEngine.Object; namespace EscapeRoomEngine.Engine.Runtime.Modules { - public enum Orientation - { - North = 0, East = 90, South = 180, West = 270 - } - public class Module { - public static HashSet EveryOrientation => new(new[] - { - Orientation.North, Orientation.East, Orientation.South, Orientation.West - }); - public readonly List relatedModules = new(); public ModuleState State { get; private set; } + internal Orientation Orientation => srPlacement.orientation; /// /// Get the space relative (SR) position of this module. /// - internal Vector2Int SrPosition => srDimensions.Position; + internal Vector3Int SrPosition => srPlacement.position; /// /// Get the room relative (RR) position of this module. /// - internal Vector2Int RrPosition => space.ToRoomRelative(SrPosition); + internal Vector3Int RrPosition => space?.ToRoomRelative(SrPosition) ?? SrPosition; internal readonly ModuleDescription description; - internal Orientation orientation; /// - /// The space relative (SR) dimensions of this module. + /// The space relative (SR) placement of this module. /// - protected Dimensions srDimensions; + public Placement srPlacement; protected readonly Space space; @@ -58,49 +48,55 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules internal bool CheckRequirements() { return PreconditionRequirement.CheckPreconditions(this, space) && - PlacementRequirement.TryPlacing(this, space) && - OrientationRequirement.TryOrienting(this, space); + PlacementRequirement.TryPlacing(this, space); } /// /// Place this module with a position relative to the room. /// /// The room relative (RR) position of this module. Must be inside the space dimensions. + /// The orientation of this module. /// If the position is not inside the space dimensions. - internal void PlaceRoomRelative(Vector2Int rrPosition) => Place(space.ToSpaceRelative(rrPosition)); - + internal void PlaceRoomRelative(Vector3Int rrPosition, Orientation orientation) => + Place(new Placement + { + position = space.ToSpaceRelative(rrPosition), + size = description.modulePrefab.size, + orientation = orientation + }); + /// /// Place this module with a position relative to the space it is in. /// - /// The space relative (SR) position of this module. Must be inside the space dimensions. + /// The space relative (SR) placement of this module. Must be inside the space dimensions. /// If the position is not inside the space dimensions. - internal void Place(Vector2Int srPosition) { - if (space != null && !srPosition.IsInsideRelative(space.rrDimensions)) + internal void Place(Placement placement) { + if (space != null && !placement.position.IsInsideRelative(space.rrPlacement)) { - throw new EngineException($"Trying to place {this} at {srPosition}, which is outside space dimensions {space.rrDimensions}."); + throw new EngineException($"Trying to place {this} at {placement.position} which is outside space dimensions {space.rrPlacement}."); } + + srPlacement = placement; - srDimensions.Position = srPosition; - - Logger.Log($"{this} has been placed at {srPosition} (SR)", LogType.ModulePlacement); + Logger.Log($"{this} has been placed at {placement.position} (SR)", LogType.ModulePlacement); } /// /// Convert a position relative to this module to one relative to its space. - /// The module relative position (0, 1) should always be in front of the module, wherever it faces. + /// The module relative position (0, 0, 1) should always be in front of the module, wherever it faces. /// /// The module relative (MR) position that should be converted to a space relative (SR) position. - /// - internal Vector2Int ToSpaceRelative(Vector2Int mrPosition) + internal Vector3Int ToSpaceRelative(Vector3Int mrPosition) { - return srDimensions.Position + orientation switch + // ReSharper disable once ArrangeRedundantParentheses + return srPlacement.position + (Orientation switch { Orientation.North => mrPosition, - Orientation.East => new Vector2Int(mrPosition.y, -mrPosition.x), + Orientation.East => new Vector3Int(mrPosition.z, 0, -mrPosition.x), Orientation.South => -mrPosition, - Orientation.West => new Vector2Int(-mrPosition.y, mrPosition.x), + Orientation.West => new Vector3Int(-mrPosition.z, 0, mrPosition.x), _ => throw new ArgumentOutOfRangeException() - }; + }); } internal virtual void InstantiateModule(Transform parent) @@ -108,8 +104,8 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules Logger.Log($"Instantiating {this}", LogType.ModuleInstantiation); State = Object.Instantiate(description.modulePrefab, parent, false); - State.transform.localPosition = new Vector3(srDimensions.x + .5f, 0, srDimensions.z + .5f); - State.transform.Rotate(Vector3.up, (float)orientation); + State.transform.localPosition = new Vector3(SrPosition.x + .5f, 0, SrPosition.z + .5f); + State.transform.Rotate(Vector3.up, Orientation.Angle()); State.name = ToString(); State.SetModule(this); } diff --git a/Assets/Engine/Runtime/Modules/ModuleDescription.cs b/Assets/Engine/Runtime/Modules/ModuleDescription.cs index 81a6a28..c42a2ca 100644 --- a/Assets/Engine/Runtime/Modules/ModuleDescription.cs +++ b/Assets/Engine/Runtime/Modules/ModuleDescription.cs @@ -14,8 +14,6 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules public List preconditionRequirements = new(); [BoxGroup("Requirements")] public List placementRequirements = new(); - [BoxGroup("Requirements")] - public List orientationRequirements = new(); internal bool HasType(ModuleType type) { diff --git a/Assets/Engine/Runtime/Orientation.cs b/Assets/Engine/Runtime/Orientation.cs new file mode 100644 index 0000000..4f9de3d --- /dev/null +++ b/Assets/Engine/Runtime/Orientation.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace EscapeRoomEngine.Engine.Runtime +{ + public enum Orientation + { + North = 0, East = 90, South = 180, West = 270 + } + + public static class OrientationExtensions + { + public static HashSet EveryOrientation() => new(new[] + { + Orientation.North, Orientation.East, Orientation.South, Orientation.West + }); + + public static float Angle(this Orientation orientation) => (float)orientation; + } +} \ No newline at end of file diff --git a/Assets/Engine/Runtime/Orientation.cs.meta b/Assets/Engine/Runtime/Orientation.cs.meta new file mode 100644 index 0000000..418e503 --- /dev/null +++ b/Assets/Engine/Runtime/Orientation.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 892800b15ed4409582647cfc5659b820 +timeCreated: 1669115056 \ No newline at end of file diff --git a/Assets/Engine/Runtime/Passage.cs b/Assets/Engine/Runtime/Passage.cs index 79f574f..8fe5b58 100644 --- a/Assets/Engine/Runtime/Passage.cs +++ b/Assets/Engine/Runtime/Passage.cs @@ -1,5 +1,4 @@ using EscapeRoomEngine.Engine.Runtime.Modules; -using UnityEngine; using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger; using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType; @@ -7,31 +6,12 @@ namespace EscapeRoomEngine.Engine.Runtime { public class Passage { - internal DoorModule fromOut, toIn; - /// - /// The room relative (RR) position of this passage. - /// - internal Vector2Int rrPosition; + internal readonly DoorModule fromOut; + internal DoorModule toIn; - internal Passage(DoorModule from, bool spawnPassage = false) + internal Passage(DoorModule from) { - if (spawnPassage) - { - fromOut = from; - rrPosition = Vector2Int.zero; - } - else - { - ConnectFrom(from); - } - } - - internal void ConnectFrom(DoorModule door) - { - fromOut = door; - rrPosition = fromOut.RrPosition; - - Logger.Log($"Connected passage from {door} at {rrPosition} (RR)", LogType.PassageConnection); + fromOut = from; } internal void ConnectTo(DoorModule door) @@ -39,10 +19,9 @@ namespace EscapeRoomEngine.Engine.Runtime toIn = door; // to make sure the origin of the player doesn't move, the two doors must be placed in the same location in the same orientation - toIn.PlaceRoomRelative(rrPosition); - toIn.orientation = fromOut.orientation; + toIn.PlaceRoomRelative(fromOut.RrPosition, fromOut.Orientation); - Logger.Log($"Connected passage to {door} at {rrPosition} (RR)", LogType.PassageConnection); + Logger.Log($"Connected passage from {fromOut} to {toIn} at {toIn.RrPosition} (RR)", LogType.PassageConnection); } } } \ No newline at end of file diff --git a/Assets/Engine/Runtime/Placement.cs b/Assets/Engine/Runtime/Placement.cs new file mode 100644 index 0000000..f3bd3ab --- /dev/null +++ b/Assets/Engine/Runtime/Placement.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace EscapeRoomEngine.Engine.Runtime +{ + public struct Placement + { + public Vector3Int position; + public Vector2Int size; + public Orientation orientation; + + /// + /// Create a set with every possible combination of position and orientation given the dimensions. + /// + /// + /// The size of all placements will be (1, 1). + /// + /// + public List EveryPlacement + { + get + { + var placements = new List(); + + for (var zIter = 0; zIter < size.y; zIter++) + { + for (var xIter = 0; xIter < size.x; xIter++) + { + placements.AddRange(OrientationExtensions.EveryOrientation().Select(o => new Placement + { + position = new Vector3Int(xIter, 0, zIter), + size = Vector2Int.one, + orientation = o + })); + } + } + + return placements; + } + } + + public string PositionAndOrientation() => $"{{({position.x}, {position.z}), {orientation}}}"; + + public override string ToString() => $"{{{position}, {size}, {orientation}}}"; + } +} \ No newline at end of file diff --git a/Assets/Engine/Runtime/Placement.cs.meta b/Assets/Engine/Runtime/Placement.cs.meta new file mode 100644 index 0000000..a21efe6 --- /dev/null +++ b/Assets/Engine/Runtime/Placement.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fd604a23d14e49aeb740a8108bd35111 +timeCreated: 1669114833 \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/FaceSpaceCenter.cs b/Assets/Engine/Runtime/Requirements/FaceSpaceCenter.cs index 4b097b8..6d9c1c7 100644 --- a/Assets/Engine/Runtime/Requirements/FaceSpaceCenter.cs +++ b/Assets/Engine/Runtime/Requirements/FaceSpaceCenter.cs @@ -5,26 +5,29 @@ using UnityEngine; namespace EscapeRoomEngine.Engine.Runtime.Requirements { [CreateAssetMenu(menuName = "Requirements/Face Space Center")] - public class FaceSpaceCenter : OrientationRequirement + public class FaceSpaceCenter : PlacementRequirement { - protected override IEnumerable GenerateCandidates(Module module, Space space) + protected override List FilterCandidates(List candidates, Module module, Space space) { - var orientation = new HashSet(1); - float width = space.rrDimensions.width; - float length = space.rrDimensions.length; - var xRel = module.SrPosition.x / (width - 1); - var zRel = module.SrPosition.y / (length - 1); - - if (zRel > xRel) - { - orientation.Add(zRel > 1 - xRel ? Orientation.South : Orientation.East); - } - else - { - orientation.Add(zRel > 1 - xRel ? Orientation.West : Orientation.North); - } + float width = space.rrPlacement.size.x - 1; + float length = space.rrPlacement.size.y - 1; - return orientation; + candidates.RemoveAll(candidate => + { + var xRel = candidate.position.x / width; + var zRel = candidate.position.z / length; + + return candidate.orientation != + (zRel > xRel + ? zRel > 1 - xRel + ? Orientation.South + : Orientation.East + : zRel > 1 - xRel + ? Orientation.West + : Orientation.North); + }); + + return candidates; } } } \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/NoOverlap.cs b/Assets/Engine/Runtime/Requirements/NoOverlap.cs index 569d090..ccde5a7 100644 --- a/Assets/Engine/Runtime/Requirements/NoOverlap.cs +++ b/Assets/Engine/Runtime/Requirements/NoOverlap.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using EscapeRoomEngine.Engine.Runtime.Modules; -using NaughtyAttributes; using UnityEngine; namespace EscapeRoomEngine.Engine.Runtime.Requirements @@ -8,21 +7,11 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements [CreateAssetMenu(menuName = "Requirements/No Overlap")] public class NoOverlap : PlacementRequirement { - [InfoBox("A module relative position will be oriented with the module (e.g. (0, 1) is always in front of the module).")] - [Label("Reserved Positions (Module Relative)")] - public List mrReservedPositions; - - protected override IEnumerable GenerateCandidates(Module module, Space space) + protected override List FilterCandidates(List candidates, Module module, Space space) { - var candidates = space.rrDimensions.EveryPosition; - - space.AllModules.ForEach(m => + space.AllModules.ForEach(other => { - candidates.Remove(m.SrPosition); - m.description.placementRequirements - .FindAll(r => r is NoOverlap) - .ForEach(r => ((NoOverlap)r).mrReservedPositions - .ForEach(p => candidates.Remove(m.ToSpaceRelative(p)))); + candidates.RemoveAll(candidate => candidate.position.Equals(other.SrPosition)); }); return candidates; diff --git a/Assets/Engine/Runtime/Requirements/OrientationRequirement.cs b/Assets/Engine/Runtime/Requirements/OrientationRequirement.cs deleted file mode 100644 index fa5fe1c..0000000 --- a/Assets/Engine/Runtime/Requirements/OrientationRequirement.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using EscapeRoomEngine.Engine.Runtime.Modules; -using EscapeRoomEngine.Engine.Runtime.Utilities; - -namespace EscapeRoomEngine.Engine.Runtime.Requirements -{ - public abstract class OrientationRequirement : Requirement - { - protected abstract override IEnumerable GenerateCandidates(Module module, Space space); - - public static bool TryOrienting(Module module, Space space) - { - if (module.description.orientationRequirements.Count == 0) - { - // don't evaluate requirements if there are none - return true; - } - - var orientationCandidates = Candidates( - Module.EveryOrientation, - module.description.orientationRequirements, - module, space); - - Logger.Log($"orientation candidates: {string.Join(",", orientationCandidates.ToList().ConvertAll(c => c.ToString()))}", LogType.RequirementResolution); - - if (orientationCandidates.Count > 0) - { - module.orientation = orientationCandidates.RandomElement(); - return true; - } - // ReSharper disable once RedundantIfElseBlock - else - { - Logger.Log("Could not find suitable orientation for module", LogType.RequirementResolution); - return false; - } - } - } -} \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/OrientationRequirement.cs.meta b/Assets/Engine/Runtime/Requirements/OrientationRequirement.cs.meta deleted file mode 100644 index 40b92cd..0000000 --- a/Assets/Engine/Runtime/Requirements/OrientationRequirement.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 0704ea5393394baf921f68d2dcbdfaec -timeCreated: 1667878220 \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/PlaceAlongSpaceEdges.cs b/Assets/Engine/Runtime/Requirements/PlaceAlongSpaceEdges.cs index ca9946d..d9294ba 100644 --- a/Assets/Engine/Runtime/Requirements/PlaceAlongSpaceEdges.cs +++ b/Assets/Engine/Runtime/Requirements/PlaceAlongSpaceEdges.cs @@ -7,22 +7,18 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements [CreateAssetMenu(menuName = "Requirements/Place Along Space Edges")] public class PlaceAlongSpaceEdges : PlacementRequirement { - protected override IEnumerable GenerateCandidates(Module module, Space space) + protected override List FilterCandidates(List candidates, Module module, Space space) { - var edgePositions = new HashSet(); + var right = space.rrPlacement.size.x - 1; + var top = space.rrPlacement.size.y - 1; - for (var x = 0; x < space.rrDimensions.width; x++) + candidates.RemoveAll(candidate => { - edgePositions.Add(new Vector2Int(x, 0)); - edgePositions.Add(new Vector2Int(x, space.rrDimensions.length - 1)); - } - for (var z = 0; z < space.rrDimensions.length; z++) - { - edgePositions.Add(new Vector2Int(0, z)); - edgePositions.Add(new Vector2Int(space.rrDimensions.width - 1, z)); - } + var position = candidate.position; + return position.x > 0 && position.x < right && position.z > 0 && position.z < top; + }); - return edgePositions; + return candidates; } } } \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/PlaceAnywhere.cs b/Assets/Engine/Runtime/Requirements/PlaceAnywhere.cs index 231c64e..33fcb92 100644 --- a/Assets/Engine/Runtime/Requirements/PlaceAnywhere.cs +++ b/Assets/Engine/Runtime/Requirements/PlaceAnywhere.cs @@ -7,9 +7,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements [CreateAssetMenu(menuName = "Requirements/Place Anywhere")] public class PlaceAnywhere : PlacementRequirement { - protected override IEnumerable GenerateCandidates(Module module, Space space) + protected override List FilterCandidates(List candidates, Module module, Space space) { - return space.rrDimensions.EveryPosition; + return candidates; } } } \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/PlacementRequirement.cs b/Assets/Engine/Runtime/Requirements/PlacementRequirement.cs index a5180e4..f68b9a2 100644 --- a/Assets/Engine/Runtime/Requirements/PlacementRequirement.cs +++ b/Assets/Engine/Runtime/Requirements/PlacementRequirement.cs @@ -2,15 +2,12 @@ using System.Linq; using EscapeRoomEngine.Engine.Runtime.Modules; using EscapeRoomEngine.Engine.Runtime.Utilities; -using UnityEngine; -using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger; -using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType; namespace EscapeRoomEngine.Engine.Runtime.Requirements { - public abstract class PlacementRequirement : Requirement + public abstract class PlacementRequirement : Requirement { - protected abstract override IEnumerable GenerateCandidates(Module module, Space space); + protected abstract override List FilterCandidates(List candidates, Module module, Space space); public static bool TryPlacing(Module module, Space space) { @@ -21,11 +18,11 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements } var placementCandidates = Candidates( - space.rrDimensions.EveryPosition, + space.rrPlacement.EveryPlacement, module.description.placementRequirements, module, space); - Logger.Log($"placement candidates: {string.Join(", ", placementCandidates.ToList().ConvertAll(c => c.ToString()))}", LogType.RequirementResolution); + Logger.Log($"placement candidates: {string.Join(", ", placementCandidates.ToList().ConvertAll(c => c.PositionAndOrientation()))}", LogType.RequirementResolution); if (placementCandidates.Count > 0) { diff --git a/Assets/Engine/Runtime/Requirements/PreconditionRequirement.cs b/Assets/Engine/Runtime/Requirements/PreconditionRequirement.cs index e5456f7..41492a8 100644 --- a/Assets/Engine/Runtime/Requirements/PreconditionRequirement.cs +++ b/Assets/Engine/Runtime/Requirements/PreconditionRequirement.cs @@ -7,9 +7,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements { public abstract class PreconditionRequirement : Requirement { - protected static readonly HashSet TrueSet = new(new[] { true }), FalseSet = new(new[] { false }); + private static readonly List TrueSet = new(new[] { true }); - protected abstract override IEnumerable GenerateCandidates(Module module, Space space); + protected abstract override List FilterCandidates(List candidates, Module module, Space space); public static bool CheckPreconditions(Module module, Space space) { diff --git a/Assets/Engine/Runtime/Requirements/RelatedModule.cs b/Assets/Engine/Runtime/Requirements/RelatedModule.cs index 56e07bd..56655e7 100644 --- a/Assets/Engine/Runtime/Requirements/RelatedModule.cs +++ b/Assets/Engine/Runtime/Requirements/RelatedModule.cs @@ -12,12 +12,12 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements [Required] public ModuleDescription relatedModule; - protected override IEnumerable GenerateCandidates(Module module, Space space) + protected override List FilterCandidates(List candidates, Module module, Space space) { var newModule = Module.CreateModuleByType(space, relatedModule); module.relatedModules.Add(newModule); - return new []{ space.StageModuleWithRequirements(newModule) }; + return new List { space.StageModuleWithRequirements(newModule) }; } } } \ No newline at end of file diff --git a/Assets/Engine/Runtime/Requirements/Requirement.cs b/Assets/Engine/Runtime/Requirements/Requirement.cs index 55ee981..9b29623 100644 --- a/Assets/Engine/Runtime/Requirements/Requirement.cs +++ b/Assets/Engine/Runtime/Requirements/Requirement.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using EscapeRoomEngine.Engine.Runtime.Modules; using UnityEngine; @@ -6,22 +7,15 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements { public abstract class Requirement : ScriptableObject { - protected abstract IEnumerable GenerateCandidates(Module module, Space space); + protected abstract List FilterCandidates(List candidates, Module module, Space space); - public void Restrict(HashSet candidates, Module module, Space space) => - candidates.IntersectWith(GenerateCandidates(module, space)); - - public static HashSet Candidates( - HashSet initialCandidates, + protected static List Candidates( + List candidates, IEnumerable> requirements, Module module, Space space) { - foreach (var requirement in requirements) - { - requirement.Restrict(initialCandidates, module, space); - } - - return initialCandidates; + return requirements.Aggregate(candidates, + (current, requirement) => requirement.FilterCandidates(current, module, space)); } } } \ No newline at end of file diff --git a/Assets/Engine/Runtime/Space.cs b/Assets/Engine/Runtime/Space.cs index 9ea2920..342ad7f 100644 --- a/Assets/Engine/Runtime/Space.cs +++ b/Assets/Engine/Runtime/Space.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using EscapeRoomEngine.Engine.Runtime.Modules; +using EscapeRoomEngine.Engine.Runtime.Utilities; using UnityEngine; using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger; using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType; @@ -13,7 +14,7 @@ namespace EscapeRoomEngine.Engine.Runtime /// /// The room relative (RR) dimensions of this space. /// - internal readonly Dimensions rrDimensions; + internal readonly Placement rrPlacement; internal readonly Room room; /// @@ -42,10 +43,10 @@ namespace EscapeRoomEngine.Engine.Runtime internal Space(Room room, Passage entrance) { this.room = room; - rrDimensions = GenerateSpaceDimensions( + rrPlacement = GenerateSpaceDimensions( entrance, - Engine.DefaultEngine.theme.minRoomSize, - Engine.DefaultEngine.theme.playSpace); + Engine.DefaultEngine.theme.minRoomSize.ProjectAtFloor(), + Engine.DefaultEngine.theme.playSpace.ProjectAtFloor()); // connect the space to its passage entrance.ConnectTo(new DoorModule(this, @@ -94,20 +95,20 @@ namespace EscapeRoomEngine.Engine.Runtime { _spaceObject = new GameObject($"Space {name}"); _spaceObject.transform.SetParent(parent, false); - _spaceObject.transform.localPosition = new Vector3(rrDimensions.x, 0, rrDimensions.z); + _spaceObject.transform.localPosition = new Vector3(rrPlacement.position.x, 0, rrPlacement.position.z); // build the space floor out of tiles _spaceTiles = new GameObject($"Space Geometry"); _spaceTiles.transform.SetParent(_spaceObject.transform, false); _spaceTiles.isStatic = true; - for (var z = 0; z < rrDimensions.length; z++) + for (var z = 0; z < rrPlacement.size.y; z++) { - for (var x = 0; x < rrDimensions.width; x++) + for (var x = 0; x < rrPlacement.size.x; x++) { var left = x == 0; - var right = x == rrDimensions.width - 1; + var right = x == rrPlacement.size.x - 1; var bottom = z == 0; - var top = z == rrDimensions.length - 1; + var top = z == rrPlacement.size.y - 1; TileLocation location; if (bottom) @@ -131,40 +132,40 @@ namespace EscapeRoomEngine.Engine.Runtime /// 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; + internal Vector3Int ToRoomRelative(Vector3Int srPosition) => srPosition + rrPlacement.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; + internal Vector3Int ToSpaceRelative(Vector3Int rrPosition) => rrPosition - rrPlacement.position; /// /// 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) + /// A room relative (RR) placement with the generated dimensions. Always faces North. + private static Placement GenerateSpaceDimensions(Passage entrance, Vector3Int minSize, Vector3Int availableSpace) { var xMin = -1; var xMax = -1; var zMin = -1; var zMax = -1; - var position = entrance.rrPosition; var door = entrance.fromOut; + var position = door.RrPosition; // fix the side the door is facing away from - switch (door.orientation) + switch (door.Orientation) { case Orientation.North: - zMin = position.y; - zMax = Utilities.Utilities.RandomInclusive(zMin + minSize.y, availableSpace.y); + zMin = position.z; + zMax = Utilities.Utilities.RandomInclusive(zMin + minSize.z, availableSpace.z); 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); + zMax = position.z + 1; + zMin = Utilities.Utilities.RandomInclusive(0, zMax - minSize.z); break; case Orientation.West: xMax = position.x + 1; @@ -180,16 +181,14 @@ namespace EscapeRoomEngine.Engine.Runtime 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)); + zMin = Utilities.Utilities.RandomInclusive(0, Math.Min(position.z, availableSpace.z - minSize.z)); if(zMax == -1) - zMax = Utilities.Utilities.RandomInclusive(Math.Max(position.y + 1, zMin + minSize.y), availableSpace.y); + zMax = Utilities.Utilities.RandomInclusive(Math.Max(position.z + 1, zMin + minSize.z), availableSpace.z); - var dimensions = new Dimensions + var dimensions = new Placement { - width = xMax - xMin, - length = zMax - zMin, - x = xMin, - z = zMin + position = new Vector3Int(xMin, 0, zMin), + size = new Vector2Int(xMax - xMin, zMax - zMin) }; Logger.Log($"Generated space dimensions {dimensions} from entrance position {position}", LogType.RoomGeneration); diff --git a/Assets/Engine/Runtime/Utilities/Utilities.cs b/Assets/Engine/Runtime/Utilities/Utilities.cs index 310ad55..96e0d54 100644 --- a/Assets/Engine/Runtime/Utilities/Utilities.cs +++ b/Assets/Engine/Runtime/Utilities/Utilities.cs @@ -9,13 +9,13 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities #region Math /// - /// Returns whether a position relative to some dimensions is inside those dimensions. + /// Returns whether a position relative to some placement is inside its dimensions. /// - /// The position to check, relative to the dimensions. - /// The dimensions to check the position against. - public static bool IsInsideRelative(this Vector2Int position, Dimensions dimensions) + /// The position to check, relative to the placement. + /// The placement to check the position against. + public static bool IsInsideRelative(this Vector3Int position, Placement placement) { - return position.x >= 0 && position.y >= 0 && position.x < dimensions.width && position.y < dimensions.length; + return position.x >= 0 && position.z >= 0 && position.x < placement.size.x && position.z < placement.size.y; } #endregion @@ -29,4 +29,12 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities #endregion } + + public static class Vector2IntExtensions + { + public static Vector3Int ProjectAtFloor(this Vector2Int vector) => vector.ProjectAtHeight(0); + + public static Vector3Int ProjectAtHeight(this Vector2Int vector, int height) => + new Vector3Int(vector.x, height, vector.y); + } } \ No newline at end of file diff --git a/Assets/Escape Room Engine/Test Assets/Test Puzzle.asset b/Assets/Escape Room Engine/Test Assets/Test Puzzle.asset new file mode 100644 index 0000000..b8f970e --- /dev/null +++ b/Assets/Escape Room Engine/Test Assets/Test Puzzle.asset @@ -0,0 +1,22 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f928b97941e3469a9015316bb5ac1309, type: 3} + m_Name: Test Puzzle + m_EditorClassIdentifier: + types: 02000000 + modulePrefab: {fileID: 9077423192650498975, guid: e419cb35bd744b24ea973860d8b1405d, + type: 3} + preconditionRequirements: [] + placementRequirements: + - {fileID: 11400000, guid: 43eb2a566a244964aa3a3319eaafe1a8, type: 2} + - {fileID: 11400000, guid: 1f1825b71bae09c438a1cb52603347d6, type: 2} + - {fileID: 11400000, guid: ed4830127e9381245a6af07e42c52422, type: 2} diff --git a/Assets/Escape Room Engine/Test Assets/Test Puzzle.asset.meta b/Assets/Escape Room Engine/Test Assets/Test Puzzle.asset.meta new file mode 100644 index 0000000..7a6c722 --- /dev/null +++ b/Assets/Escape Room Engine/Test Assets/Test Puzzle.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 23cf2b6a956b6a745a88334950f088dd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Escape Room Engine/Test Assets/Test Theme.asset b/Assets/Escape Room Engine/Test Assets/Test Theme.asset new file mode 100644 index 0000000..c8a1c33 --- /dev/null +++ b/Assets/Escape Room Engine/Test Assets/Test Theme.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 28d04249c1c4438da94b524e7d4afff2, type: 3} + m_Name: Test Theme + m_EditorClassIdentifier: + minRoomSize: {x: 4, y: 6} + playSpace: {x: 4, y: 6} + spaceTile: {fileID: 3229991053255736984, guid: b8f192f7cebe686468af6b1a71c4605b, + type: 3} + environment: {fileID: 5743657079028767629, guid: 17ecdbaca50efaa4ab503614dfec54a8, + type: 3} + puzzleColor: {r: 8, g: 3.5137255, b: 0, a: 1} + solvedColor: {r: 0.53333336, g: 7.5607843, b: 0, a: 1} + activeColor: {r: 0, g: 4.329412, b: 8, a: 1} + spawnDoor: {fileID: 11400000, guid: 6e937b2e9f774999b5962c4b40947165, type: 2} + exitDoorTypes: + - {fileID: 11400000, guid: 29e2ae36585f4e65966bc9ea2f95ac4a, type: 2} + puzzleCount: {x: 24, y: 24} + puzzleTypes: + - {fileID: 11400000, guid: 23cf2b6a956b6a745a88334950f088dd, type: 2} diff --git a/Assets/Escape Room Engine/Test Assets/Test Theme.asset.meta b/Assets/Escape Room Engine/Test Assets/Test Theme.asset.meta new file mode 100644 index 0000000..1c3d7f2 --- /dev/null +++ b/Assets/Escape Room Engine/Test Assets/Test Theme.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ac11abaacb19cac4f9f43fc3d82883fe +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/TestScene.unity b/Assets/Scenes/TestScene.unity index 552c8c6..bdc435d 100644 --- a/Assets/Scenes/TestScene.unity +++ b/Assets/Scenes/TestScene.unity @@ -1649,7 +1649,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: loggingEnabled: 1 - typeFilter: 000000000500000006000000 + typeFilter: 0000000003000000050000000400000001000000 --- !u!1 &1718957584 GameObject: m_ObjectHideFlags: 0