handle modules larger than 1x1, widen door size to allow walking around it
This commit is contained in:
@@ -1,47 +1,122 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Range = EscapeRoomEngine.Engine.Runtime.Utilities.Range;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
public struct Placement
|
||||
{
|
||||
/// <summary>
|
||||
/// The placement position is always considered to be at <c>(0.5, 0.5)</c> relative to the placement.
|
||||
///
|
||||
/// <example>In a placement of size <c>(1, 1)</c>, the position is at the center of the placement. In a larger placement, the position is in the center of the bottom left square meter.</example>
|
||||
/// </summary>
|
||||
public Vector3Int position;
|
||||
public Vector2Int size;
|
||||
public Orientation orientation;
|
||||
|
||||
/// <summary>
|
||||
/// Create a set with every possible combination of position and orientation given the dimensions.
|
||||
///
|
||||
/// <remarks>
|
||||
/// The size of all placements will be (1, 1).
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public List<Placement> EveryPlacement
|
||||
{
|
||||
|
||||
public Vector3Int BottomLeft {
|
||||
get
|
||||
{
|
||||
var placements = new List<Placement>();
|
||||
|
||||
for (var zIter = 0; zIter < size.y; zIter++)
|
||||
var sizeMinusOne = size - Vector2Int.one;
|
||||
return orientation switch
|
||||
{
|
||||
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
|
||||
}));
|
||||
}
|
||||
}
|
||||
Orientation.North => position,
|
||||
Orientation.East => position - new Vector3Int(0, 0, sizeMinusOne.x),
|
||||
Orientation.South => position - new Vector3Int(sizeMinusOne.x, 0, sizeMinusOne.y),
|
||||
Orientation.West => position - new Vector3Int(sizeMinusOne.y, 0, 0),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a set with every possible combination of position and orientation of placements that fit in a given space.
|
||||
/// The size of the placements are given by this placement.
|
||||
/// </summary>
|
||||
/// <param name="space">The generated placements will fit inside the placement of the given space.</param>
|
||||
public List<Placement> EveryPlacementInSpace(Space space)
|
||||
{
|
||||
var placements = new List<Placement>();
|
||||
var sizeMinusOne = size - Vector2Int.one;
|
||||
var spaceSize = space.rrPlacement.size;
|
||||
|
||||
return placements;
|
||||
foreach (var o in OrientationExtensions.EveryOrientation())
|
||||
{
|
||||
Range x;
|
||||
Range z;
|
||||
|
||||
switch (o)
|
||||
{
|
||||
case Orientation.North:
|
||||
x = new Range(0, spaceSize.x - sizeMinusOne.x);
|
||||
z = new Range(0, spaceSize.y - sizeMinusOne.y);
|
||||
break;
|
||||
case Orientation.East:
|
||||
x = new Range(0, spaceSize.x - sizeMinusOne.y);
|
||||
z = new Range(sizeMinusOne.x, spaceSize.y);
|
||||
break;
|
||||
case Orientation.South:
|
||||
x = new Range(sizeMinusOne.x, spaceSize.x);
|
||||
z = new Range(sizeMinusOne.y, spaceSize.y);
|
||||
break;
|
||||
case Orientation.West:
|
||||
x = new Range(sizeMinusOne.y, spaceSize.x);
|
||||
z = new Range(0, spaceSize.y - sizeMinusOne.x);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
placements.AddRange(ConstrainedPlacements(o, size, x, z));
|
||||
}
|
||||
|
||||
return placements;
|
||||
}
|
||||
|
||||
private static IEnumerable<Placement> ConstrainedPlacements(
|
||||
Orientation orientation,
|
||||
Vector2Int size,
|
||||
Range xRange, Range zRange)
|
||||
{
|
||||
var placements = new List<Placement>(xRange.Length * zRange.Length);
|
||||
|
||||
for (var z = zRange.min; z < zRange.max; z++)
|
||||
{
|
||||
for (var x = xRange.min; x < xRange.max; x++)
|
||||
{
|
||||
placements.Add(new Placement
|
||||
{
|
||||
position = new Vector3Int(x, 0, z),
|
||||
size = size,
|
||||
orientation = orientation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return placements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the specified action for each position inside the size of this placement.
|
||||
///
|
||||
/// <example>For the placement {(2, 0, 3), (1, 2), East} the action would be called twice with the parameters (2, 0, 3) and (3, 0, 3).</example>
|
||||
/// </summary>
|
||||
public void ForEachPosition(Action<Vector3Int> action)
|
||||
{
|
||||
var bottomLeft = BottomLeft;
|
||||
|
||||
for (var z = 0; z < (orientation is Orientation.North or Orientation.South ? size.y : size.x); z++)
|
||||
{
|
||||
for (var x = 0; x < (orientation is Orientation.North or Orientation.South ? size.x : size.y); x++)
|
||||
{
|
||||
action(bottomLeft + new Vector3Int(x, 0, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string PositionAndOrientation() => $"{{({position.x}, {position.z}), {orientation}}}";
|
||||
|
||||
public string ToStringShort() => $"{{{position}, {orientation}}}";
|
||||
public override string ToString() => $"{{{position}, {size}, {orientation}}}";
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,17 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
protected override List<Placement> FilterCandidates(List<Placement> candidates, Module module, Space space)
|
||||
{
|
||||
float width = space.rrPlacement.size.x - 1;
|
||||
float length = space.rrPlacement.size.y - 1;
|
||||
float width = space.rrPlacement.size.x;
|
||||
float length = space.rrPlacement.size.y;
|
||||
|
||||
candidates.RemoveAll(candidate =>
|
||||
{
|
||||
var xRel = candidate.position.x / width;
|
||||
var zRel = candidate.position.z / length;
|
||||
|
||||
var bottomLeft = candidate.BottomLeft;
|
||||
var center = new Vector2(bottomLeft.x, bottomLeft.z) +
|
||||
new Vector2(candidate.size.x / 2f, candidate.size.y / 2f);
|
||||
var xRel = center.x / width;
|
||||
var zRel = center.y / length;
|
||||
|
||||
return candidate.orientation !=
|
||||
(zRel > xRel
|
||||
? zRel > 1 - xRel
|
||||
|
||||
@@ -9,10 +9,22 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
protected override List<Placement> FilterCandidates(List<Placement> candidates, Module module, Space space)
|
||||
{
|
||||
space.AllModules.ForEach(other =>
|
||||
{
|
||||
candidates.RemoveAll(candidate => candidate.position.Equals(other.SrPosition));
|
||||
});
|
||||
space.AllModules.ForEach(other => // for all other module ...
|
||||
other.srPlacement.ForEachPosition(otherPosition => // ... positions ...
|
||||
candidates.RemoveAll(candidate => // ... remove every candidate that ...
|
||||
{
|
||||
var remove = false;
|
||||
|
||||
candidate.ForEachPosition(position => // ... anywhere inside its bounds ...
|
||||
{
|
||||
if (!remove)
|
||||
{
|
||||
remove = position.Equals(otherPosition); // ... overlaps with other modules' position
|
||||
}
|
||||
});
|
||||
|
||||
return remove;
|
||||
})));
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,17 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
|
||||
candidates.RemoveAll(candidate =>
|
||||
{
|
||||
var position = candidate.position;
|
||||
return position.x > 0 && position.x < right && position.z > 0 && position.z < top;
|
||||
var keep = false;
|
||||
|
||||
candidate.ForEachPosition(position =>
|
||||
{
|
||||
if (!keep)
|
||||
{
|
||||
keep = position.x == 0 || position.x == right || position.z == 0 || position.z == top;
|
||||
}
|
||||
});
|
||||
|
||||
return !keep;
|
||||
});
|
||||
|
||||
return candidates;
|
||||
|
||||
@@ -18,11 +18,11 @@ namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
}
|
||||
|
||||
var placementCandidates = Candidates(
|
||||
space.rrPlacement.EveryPlacement,
|
||||
module.srPlacement.EveryPlacementInSpace(space),
|
||||
module.description.placementRequirements,
|
||||
module, space);
|
||||
|
||||
Logger.Log($"placement candidates: {string.Join(", ", placementCandidates.ToList().ConvertAll(c => c.PositionAndOrientation()))}", LogType.RequirementResolution);
|
||||
Logger.Log($"placement candidates: {string.Join(", ", placementCandidates.ToList().ConvertAll(c => c.ToStringShort()))}", LogType.RequirementResolution);
|
||||
|
||||
if (placementCandidates.Count > 0)
|
||||
{
|
||||
|
||||
17
Assets/Engine/Runtime/Utilities/Range.cs
Normal file
17
Assets/Engine/Runtime/Utilities/Range.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
public struct Range
|
||||
{
|
||||
public int min, max;
|
||||
|
||||
public int Length => max - min;
|
||||
|
||||
public Range(int min, int max)
|
||||
{
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public override string ToString() => $"{{{min}, ..., {max}}}";
|
||||
}
|
||||
}
|
||||
3
Assets/Engine/Runtime/Utilities/Range.cs.meta
Normal file
3
Assets/Engine/Runtime/Utilities/Range.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c02bc5b9e6d74d6eaab716d63b53a48f
|
||||
timeCreated: 1669288906
|
||||
Reference in New Issue
Block a user