157 lines
6.7 KiB
C#
157 lines
6.7 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// The room relative (<i>RR</i>) dimensions of this space.
|
|
/// </summary>
|
|
internal readonly Dimensions rrDimensions;
|
|
internal List<Module> Modules { get; } = new(2);
|
|
internal readonly Room room;
|
|
|
|
private GameObject _spaceObject, _spaceTiles;
|
|
|
|
internal Space(Room room, Passage entrance)
|
|
{
|
|
this.room = room;
|
|
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}");
|
|
_spaceObject.transform.SetParent(parent, false);
|
|
_spaceObject.transform.localPosition = new Vector3(rrDimensions.x, 0, rrDimensions.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 x = 0; x < rrDimensions.width; x++)
|
|
{
|
|
var left = x == 0;
|
|
var right = x == rrDimensions.width - 1;
|
|
var bottom = z == 0;
|
|
var top = z == rrDimensions.length - 1;
|
|
|
|
TileLocation location;
|
|
if (bottom)
|
|
location = left ? TileLocation.SW : right ? TileLocation.SE : TileLocation.S;
|
|
else if (top)
|
|
location = left ? TileLocation.NW : right ? TileLocation.NE : TileLocation.N;
|
|
else
|
|
location = left ? TileLocation.W : right ? TileLocation.E : TileLocation.C;
|
|
|
|
var tileObject = Object.Instantiate(Engine.DefaultEngine.config.spaceTile, _spaceTiles.transform, false);
|
|
tileObject.transform.localPosition = new Vector3(x, 0, z);
|
|
tileObject.showTile = location;
|
|
}
|
|
}
|
|
|
|
// instantiate all modules inside this space
|
|
Modules.ForEach(module => module.InstantiateModule(_spaceObject.transform));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a position relative to this space to one relative to the room.
|
|
/// </summary>
|
|
/// <param name="srPosition">The space relative (<i>SR</i>) position that should be converted to a room relative (<i>RR</i>) position.</param>
|
|
internal Vector2Int ToRoomRelative(Vector2Int srPosition) => srPosition + rrDimensions.Position;
|
|
/// <summary>
|
|
/// Convert a position relative to the room to one relative to this space.
|
|
/// </summary>
|
|
/// <param name="rrPosition">The room relative (<i>RR</i>) position that should be converted to a space relative (<i>SR</i>) position.</param>
|
|
internal Vector2Int ToSpaceRelative(Vector2Int rrPosition) => rrPosition - rrDimensions.Position;
|
|
|
|
/// <summary>
|
|
/// Generate space dimensions that fit the required size constraints and cover the position of the entrance.
|
|
/// </summary>
|
|
/// <returns>The generated room relative (<i>RR</i>) dimensions.</returns>
|
|
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;
|
|
}
|
|
}
|
|
}
|