BITFALL/Assets/Plugins/FImpossible Creations/Plugins - Level Design/PGG/Components/Simple/RectangleOfFieldsGenerator.cs

973 lines
41 KiB
C#

using FIMSpace.Generating.Checker;
using FIMSpace.Generating.RectOfFields;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
namespace FIMSpace.Generating
{
[AddComponentMenu("FImpossible Creations/PGG/Rectangle of Fields Generator", 103)]
public class RectangleOfFieldsGenerator : PGGGeneratorBase
{
public bool RefreshEveryChange = true;
[Space(6)]
public Vector2Int PackingRectSize = new Vector2Int(10, 8);
[Range(0, 6)] public int AdditionalSpacing = 0;
public MinMax MinSingleRectSizeX = new MinMax(4, 6);
public MinMax MaxSingleRectSizeY = new MinMax(4, 6);
public MinMax MinMaxSizeOfFillRects = new MinMax(4, 12);
[Tooltip("Useful when generating exterior walls and want to clear rooms walls on edges or so")]
public int InstructionIdOnRectEdges = -1;
public int InstructionIdOnRectNeightbours = -1;
[Header("Corridor Setup is optional")]
public bool UseCorridorGuide = false;
public MinMax LimitDoorsCount = new MinMax(1, 3);
public FieldSetup CorridorPreset;
public PathFind.SimplePathGuide CorridorGuide;
[Header("You must select at least one field preset")]
public List<FieldOfRect> RoomPresets = new List<FieldOfRect>();
[Header("Optional always in same place - Useful for example for elevator")]
public List<FieldOfRectStatic> StaticRooms = new List<FieldOfRectStatic>();
private RectOfFieldsInstance mainCorridorInstance = null;
private List<RectOfFieldsInstance> rInstances = new List<RectOfFieldsInstance>();
private List<RectOfFieldsInstance> rStatic = new List<RectOfFieldsInstance>();
private List<RectOfFieldsInstance> rAll = new List<RectOfFieldsInstance>();
private CheckerField fullRectCheck = new CheckerField();
[HideInInspector] public int FromMainCorridorToRoomsGuideId = 0;
[Space(5)]
[HideInInspector] public int FromRoomsToCorridorsGuideId = 0;
[HideInInspector] public int FromRoomsToRoomsGuideId = 0;
[HideInInspector] public int FromRoomToAlreadyConnectedRoomGuideId = 0;
public override FGenGraph<FieldCell, FGenPoint> PGG_Grid { get { return null; } }
public override FieldSetup PGG_Setup { get { return null; } }
public override void Prepare()
{
base.Prepare();
rAll.Clear();
rStatic.Clear();
rInstances.Clear();
#region Generating Main Corridor
if (UseCorridorGuide)
{
mainCorridorInstance = new RectOfFieldsInstance(); // Null -> that means it's corridor
mainCorridorInstance.Checker.Position = CorridorGuide.Start;
var mainCorrSetup = CheckerField.GeneratePathFindPointsFromStartToEnd(CorridorGuide);
mainCorridorInstance.Checker.AddPathTowards(mainCorrSetup[0], CorridorGuide.PathThickness);
//mainCorridorInstance.Checker.RecalculateMultiBounds();
mainCorridorInstance.Checker.Position -= new Vector2Int(1, 1);
mainCorridorInstance.Setted = true;
for (int i = mainCorridorInstance.Checker.ChildPos.Count - 1; i >= 0; i--)
{
Vector2Int pos = mainCorridorInstance.Checker.WorldPos(i);
if (pos.x < -PackingRectSize.x) mainCorridorInstance.Checker.Remove(pos);
else
if (pos.x >= PackingRectSize.x) mainCorridorInstance.Checker.Remove(pos);
else
if (pos.y < -PackingRectSize.y - 1) mainCorridorInstance.Checker.Remove(pos);
else
if (pos.y > PackingRectSize.y - 2) mainCorridorInstance.Checker.Remove(pos);
}
rAll.Add(mainCorridorInstance);
}
#endregion
#region Placing static rects
for (int i = 0; i < StaticRooms.Count; i++)
{
RectOfFieldsInstance ins = new RectOfFieldsInstance();
ins.FieldRefStatic = StaticRooms[i];
ins.Checker.SetSize(StaticRooms[i].Size);
ins.Checker.Position = StaticRooms[i].StaticPosition;
ins.Setted = true;
rStatic.Add(ins);
rAll.Add(ins);
if (UseCorridorGuide) mainCorridorInstance.Checker.RemoveOnesCollidingWith(ins.Checker);
}
#endregion
#region Packing fields in rect
// First calculate what rects we use
// We shatter desired box onto small pieces
fullRectCheck = new CheckerField();
fullRectCheck.SetSize(PackingRectSize.x * 2, PackingRectSize.y * 2, true);
fullRectCheck.Position += new Vector2Int(0, -1);
// Clearing place for the corridor
if (mainCorridorInstance != null) fullRectCheck.RemoveOnesCollidingWith(mainCorridorInstance.Checker);
// Clearing place for the static rooms
for (int i = 0; i < rStatic.Count; i++) fullRectCheck.RemoveOnesCollidingWith(rStatic[i].Checker);
int toFill = fullRectCheck.ChildPos.Count;
// Generating until packing shape size minus corridor is reached
for (int i = 0; i < 1000; i++)
{
RectOfFieldsInstance shape = new RectOfFieldsInstance();
shape.Checker.SetSize(MinSingleRectSizeX.GetRandom(), MaxSingleRectSizeY.GetRandom(), false);
shape.Checker.Position += new Vector2Int(PackingRectSize.x * 10, 0);
toFill -= shape.Checker.ChildPos.Count;
rInstances.Add(shape);
rAll.Add(shape);
if (toFill <= 0) break;
}
int positionX = -PackingRectSize.x;
int positionY = -PackingRectSize.y - 1;
int lim = 0;
// Placing shapes in packing rect starting from left down
for (int i = 0; i < rInstances.Count; i++)
{
var ins = rInstances[i];
ins.Checker.Position = new Vector2Int(positionX, positionY);
var coll = CheckIfAnyCollides(ins.Checker);
if (FGenerators.CheckIfIsNull(coll ))
{
ins.Setted = true;
}
else
{
ins.Checker.Position += new Vector2Int(coll.Position.x - ins.Checker.Position.x, ins.Checker.LastSettedSize.y * 2);
ins.Checker.SnapToOther(coll);
if (FGenerators.CheckIfIsNull(CheckIfAnyCollides(ins.Checker) )) ins.Setted = true;
}
if (ins.Setted)
{
if (ins.Checker.GetBoundsMax().x >= PackingRectSize.x) ins.Setted = false;
if (ins.Checker.GetBoundsMax().y >= PackingRectSize.y - 1) ins.Setted = false;
}
if (ins.Setted == false) ins.Checker.PushPositionX(PackingRectSize.x * 3);
if (ins.Setted)
{
positionX = ins.Checker.Position.x;
positionX += ins.Checker.LastSettedSize.x / 2 + AdditionalSpacing;
}
else
{
if (lim < 2) // Allowing to try placing box few times
{
lim++;
i--;
}
else
lim = 0;
}
// Always forwarding a bit
positionX += ins.Checker.LastSettedSize.x / 2;
if (positionX >= PackingRectSize.x)
{
positionX = -PackingRectSize.x;
positionY += ins.Checker.GetSizeOnAxis(Vector2.up);
}
}
// After filling we generate inverse fillment rect
fullRectCheck = new CheckerField();
fullRectCheck.SetSize(PackingRectSize.x * 2, PackingRectSize.y * 2, true);
//fullRectCheck.Position += new Vector2Int(0, -1);
fullRectCheck.PushAllChildPositions(new Vector2Int(0, -1));
for (int i = 0; i < rAll.Count; i++) fullRectCheck.RemoveOnesCollidingWith(rAll[i].Checker);
#endregion
#region Now we create rects out of free space to fill it completely
// Generating until full packing using fullRectCheck
for (int i = 0; i < 1000; i++)
{
int size = MinMaxSizeOfFillRects.GetRandom();
List<Vector2Int> nRect = fullRectCheck.FindConnectedShapeOfSize(size);
if (nRect.Count > 0)
if (nRect.Count >= MinMaxSizeOfFillRects.Min)
{
RectOfFieldsInstance fillShape = new RectOfFieldsInstance(); //RoomPresets[0]
fillShape.Checker.Position = nRect[0];
fillShape.Checker.AddPositions(nRect);
fillShape.Setted = true;
fullRectCheck.RemoveOnesCollidingWith(fillShape.Checker); // Removing reverse fillment squares of this shape
rInstances.Add(fillShape);
}
if (fullRectCheck.ChildPos.Count == 0) break;
}
#endregion
#region Joining smallest rects with bigger ones
// First joining left rects by inverse selection
for (int i = 0; i < fullRectCheck.ChildPos.Count; i++)
{
CheckerField ch = FindAligningTo(fullRectCheck.ChildPosition(i));
if (ch != null) ch.Add(fullRectCheck.ChildPosition(i));
}
#endregion
}
CheckerField CheckIfAnyCollides(CheckerField checker)
{
for (int i = 0; i < rAll.Count; i++)
{
if (rAll[i].Setted == false) continue;
if (checker == rAll[i].Checker) continue;
if (checker.CollidesWith(rAll[i].Checker)) return rAll[i].Checker;
}
return null;
}
CheckerField FindAligningTo(Vector2Int square)
{
for (int i = 0; i < rInstances.Count; i++)
{
if (rInstances[i].Checker.IsAligning(square))
{
return rInstances[i].Checker;
}
}
return null;
}
public override void GenerateObjects()
{
Prepare(); // Preparing packed rooms scheme
// Generating grids out of packed rects
RectOfGeneratingHelper corridorGrid = new RectOfGeneratingHelper(null);
List<RectOfGeneratingHelper> roomsGrids = new List<RectOfGeneratingHelper>();
List<RectOfGeneratingHelper> staticRoomGrids = new List<RectOfGeneratingHelper>();
#region Setting up corridor grid if used
if (UseCorridorGuide)
{
corridorGrid.fieldInstance = mainCorridorInstance;
mainCorridorInstance.Checker.InjectToGrid(corridorGrid.grid);
}
#endregion
#region Setting up grids for all rooms in rect
for (int i = 0; i < rInstances.Count; i++)
{
if (rInstances[i].Setted == false) continue;
RectOfGeneratingHelper room = new RectOfGeneratingHelper(rInstances[i]);
rInstances[i].Checker.InjectToGrid(room.grid);
roomsGrids.Add(room);
}
#endregion
#region Setting up grids for static rooms
for (int i = 0; i < rStatic.Count; i++)
{
RectOfGeneratingHelper room = new RectOfGeneratingHelper(rStatic[i]);
room.inject = rStatic[i].FieldRefStatic.Injections;
rStatic[i].Checker.InjectToGrid(room.grid);
staticRoomGrids.Add(room);
}
#endregion
#region Choosing most fitting presets settings for rooms
List<RectOfFieldsInstance> notAssigned = new List<RectOfFieldsInstance>();
for (int p = 0; p < RoomPresets.Count; p++) RoomPresets[p].Refresh();
List<FieldOfRect> randomUnlimited = new List<FieldOfRect>();
for (int p = 0; p < RoomPresets.Count; p++) if (RoomPresets[p].MaxCountOfThisRoom <= 0) randomUnlimited.Add(RoomPresets[p]);
for (int i = 0; i < rInstances.Count; i++)
{
RectOfFieldsInstance room = rInstances[i];
for (int p = 0; p < RoomPresets.Count; p++)
{
var preset = RoomPresets[p];
if (preset.MaxCountOfThisRoom > 0) if (preset.AlreadyGenerated >= preset.MaxCountOfThisRoom) continue; // already used all
int roomSize = room.Checker.CountSize();
if (roomSize > preset.DesiredSizeInCells.Min && roomSize < preset.DesiredSizeInCells.Max)
{
room.FieldRef = preset;
preset.AlreadyGenerated++;
break;
}
}
if (room.FieldRef == null || room.FieldRef.Preset == null) notAssigned.Add(room);
}
if (randomUnlimited.Count == 0)
if (RoomPresets.Count > 0)
randomUnlimited.Add(RoomPresets[0]);
if (randomUnlimited.Count == 0)
{
for (int i = 0; i < notAssigned.Count; i++)
{
if (RoomPresets.Count > 0)
notAssigned[i].FieldRef = RoomPresets[0];
}
}
else
{
for (int i = 0; i < notAssigned.Count; i++)
{
notAssigned[i].FieldRef = randomUnlimited[Random.Range(0, randomUnlimited.Count)];
}
}
for (int i = 0; i < roomsGrids.Count; i++)
{
if (roomsGrids[i].fieldInstance.FieldRef == null) continue;
roomsGrids[i].inject = roomsGrids[i].fieldInstance.FieldRef.Injections;
}
#endregion
#region Additional Guides if wanted
if (InstructionIdOnRectEdges >= 0)
{
CheckerField boundChecker = new CheckerField();
boundChecker.SetSize(PackingRectSize.x * 2, PackingRectSize.y * 2, true);
boundChecker.Position += (new Vector2Int(0, -1));
//boundChecker.PushAllChildPositions(new Vector2Int(0, -1));
List<Vector2Int> edges = boundChecker.GetEdgePositions();
for (int i = 0; i < roomsGrids.Count; i++)
InjectBuildupInstructions(roomsGrids[i], boundChecker, edges, roomsGrids[i].fieldInstance.FieldRef.Preset);
for (int i = 0; i < staticRoomGrids.Count; i++)
InjectBuildupInstructions(staticRoomGrids[i], boundChecker, edges, staticRoomGrids[i].fieldInstance.FieldRefStatic.Preset);
corridorGrid.fieldInstance = mainCorridorInstance;
InjectBuildupInstructions(corridorGrid, boundChecker, edges, CorridorPreset);
}
#endregion
#region Generating door connections between rooms
#region Preparing doors for corridor start and end if used
if (UseCorridorGuide)
if (CorridorPreset)
{
// Guides for start and end dungeon points
if (CorridorGuide.StartGuideDoorInstruction > -1)
{
// Making hole from start point towards corridor back (should be static closed gates or so)
SpawnInstruction startDoorsGuide = PGGUtils.GenerateInstructionTowards(mainCorridorInstance.Checker,
CorridorGuide.Start, CorridorGuide.StartDir.GetDirection().V3toV3Int(), 5);
startDoorsGuide.definition = CorridorPreset.CellsInstructions[CorridorGuide.StartGuideDoorInstruction];
corridorGrid.guides.Add(startDoorsGuide);
}
if (CorridorGuide.EndGuideDoorInstruction > -1)
{
SpawnInstruction endDoorsGuide = PGGUtils.GenerateInstructionTowards(mainCorridorInstance.Checker,
CorridorGuide.End, CorridorGuide.EndDir.GetDirection().V3toV3Int(), 5); // 5 for centering
endDoorsGuide.definition = CorridorPreset.CellsInstructions[CorridorGuide.EndGuideDoorInstruction];
corridorGrid.guides.Add(endDoorsGuide);
}
mainCorridorInstance.IsMainCorridor = true;
}
#endregion
#region Preparing doors for static rooms
for (int i = 0; i < staticRoomGrids.Count; i++)
{
RectOfGeneratingHelper room = staticRoomGrids[i];
if (room.fieldInstance.FieldRefStatic == null) continue;
var sRoom = room.fieldInstance.FieldRefStatic;
if (sRoom.Preset == null) continue;
bool generateOtherConnectrions = !sRoom.OnlyCorridorConnection;
int limit = 12;
// Connection between room and corridor
if (room.fieldInstance.Checker.IsAligning(mainCorridorInstance.Checker))
{
RectOfGeneratingHelper corridor = corridorGrid;
if (sRoom.PrioritizeDoorsDirection != Vector3Int.zero)
{
// Making hole from room to corridor
SpawnInstruction instr = PGGUtils.GenerateInstructionTowards(room.fieldInstance.Checker, sRoom.StaticPosition + sRoom.PrioritizeOriginOffset, sRoom.PrioritizeDoorsDirection, 0, false);
if (sRoom.OverrideDoorholeCommand >= 0)
instr.definition = sRoom.Preset.CellsInstructions[sRoom.OverrideDoorholeCommand];
else
instr.definition = sRoom.Preset.CellsInstructions[FromRoomsToRoomsGuideId];
room.guides.Add(instr);
// Making hole from corridor to room
SpawnInstruction pathInstr = PGGUtils.GenerateInstructionTowards(corridor.fieldInstance.Checker, room.fieldInstance.Checker, 0, new Vector2Int(instr.helperCoords.x, instr.helperCoords.z));
if (sRoom.OverrideFromCorridorCommand >= 0)
pathInstr.definition = CorridorPreset.CellsInstructions[sRoom.OverrideFromCorridorCommand];
else
pathInstr.definition = CorridorPreset.CellsInstructions[FromRoomsToRoomsGuideId];
corridor.guides.Add(pathInstr);
corridor.fieldInstance.Connections.Add(room.fieldInstance);
room.fieldInstance.Connections.Add(corridor.fieldInstance);
}
else
{
// Generating guide for creating door on corridor side and room side
SpawnInstruction instr = PGGUtils.GenerateInstructionTowards(corridor.fieldInstance.Checker, room.fieldInstance.Checker, 0);
if (sRoom.OverrideFromCorridorCommand >= 0)
instr.definition = CorridorPreset.CellsInstructions[sRoom.OverrideFromCorridorCommand];
else
instr.definition = CorridorPreset.CellsInstructions[FromRoomsToRoomsGuideId];
corridor.guides.Add(instr);
corridor.fieldInstance.Connections.Add(room.fieldInstance);
// Making hole from room to corridor
SpawnInstruction pathInstr = PGGUtils.GenerateInstructionTowards(room.fieldInstance.Checker, corridor.fieldInstance.Checker, 0, new Vector2Int(instr.helperCoords.x, instr.helperCoords.z));
if (sRoom.OverrideDoorholeCommand >= 0)
pathInstr.definition = sRoom.Preset.CellsInstructions[sRoom.OverrideDoorholeCommand];
else
pathInstr.definition = sRoom.Preset.CellsInstructions[FromRoomsToRoomsGuideId];
room.guides.Add(pathInstr);
room.fieldInstance.Connections.Add(corridor.fieldInstance);
}
}
else // Not aligning to corridor so do any connection
{
generateOtherConnectrions = true;
limit = 11;
}
// Generate connections with aligning rooms
if (generateOtherConnectrions)
{
#region Collecting rooms which have possibility for connection with this room
List<RectOfGeneratingHelper> aligning = new List<RectOfGeneratingHelper>();
for (int r = 0; r < roomsGrids.Count; r++)
{
var other = roomsGrids[r];
if (other.fieldInstance.Connections.Contains(room.fieldInstance)) continue; // Already connected
if (room.fieldInstance.Checker.IsAligning(other.fieldInstance.Checker))
aligning.Add(other);
if (aligning.Count >= limit) break;
}
#endregion
if (room.fieldInstance.FieldRefStatic != null)
if (room.fieldInstance.FieldRefStatic.Preset)
for (int a = 0; a < aligning.Count; a++)
{
RectOfGeneratingHelper other = aligning[a];
if (other.fieldInstance.FieldRef == null) continue;
if (other.fieldInstance.FieldRef.Preset == null) continue;
// Generating guide for creating door on room side and other room side
SpawnInstruction instr = PGGUtils.GenerateInstructionTowards(room.fieldInstance.Checker, other.fieldInstance.Checker, 0);
instr.definition = room.fieldInstance.FieldRefStatic.Preset.CellsInstructions[FromRoomsToRoomsGuideId];
room.guides.Add(instr);
room.fieldInstance.Connections.Add(other.fieldInstance);
// Making hole on other room to this room
SpawnInstruction pathInstr = PGGUtils.GenerateInstructionTowards(other.fieldInstance.Checker, room.fieldInstance.Checker, 0, new Vector2Int(instr.helperCoords.x, instr.helperCoords.z));
pathInstr.definition = other.fieldInstance.FieldRef.Preset.CellsInstructions[FromRoomToAlreadyConnectedRoomGuideId];
other.guides.Add(pathInstr);
other.fieldInstance.Connections.Add(room.fieldInstance);
}
}
}
#endregion
#region Preparing doors for rooms and corridor
if (UseCorridorGuide)
{
if (CorridorPreset)
for (int i = 0; i < roomsGrids.Count; i++)
{
RectOfGeneratingHelper other = roomsGrids[i];
if (other.fieldInstance.FieldRef == null) continue;
if (other.fieldInstance.FieldRef.Preset == null) continue;
if (other.fieldInstance.Checker.IsAligning(mainCorridorInstance.Checker))
{
RectOfGeneratingHelper corridor = corridorGrid;
// Generating guide for creating door on room side and other room side
SpawnInstruction instr = PGGUtils.GenerateInstructionTowards(corridor.fieldInstance.Checker, other.fieldInstance.Checker, 0);
instr.definition = CorridorPreset.CellsInstructions[FromRoomsToRoomsGuideId];
corridor.guides.Add(instr);
corridor.fieldInstance.Connections.Add(other.fieldInstance);
// Making hole on other room to this room
SpawnInstruction pathInstr = PGGUtils.GenerateInstructionTowards(other.fieldInstance.Checker, corridor.fieldInstance.Checker, 0, new Vector2Int(instr.helperCoords.x, instr.helperCoords.z));
pathInstr.definition = other.fieldInstance.FieldRef.Preset.CellsInstructions[FromRoomsToRoomsGuideId];
other.guides.Add(pathInstr);
other.fieldInstance.Connections.Add(corridor.fieldInstance);
}
}
}
#endregion
// Preparing doors between rooms
for (int i = 0; i < roomsGrids.Count; i++)
{
RectOfGeneratingHelper room = roomsGrids[i];
int limitConnections = -1;
if (HaveConnectionWithCorridor(room.fieldInstance))
limitConnections = LimitDoorsCount.GetRandom(); // If already can go to corridor then dont create all connections
if (limitConnections <= 0) limitConnections = -1;
#region Collecting rooms which have possibility for connection with this room
List<RectOfGeneratingHelper> aligning = new List<RectOfGeneratingHelper>();
List<RectOfGeneratingHelper> reserve = new List<RectOfGeneratingHelper>();
for (int r = 0; r < roomsGrids.Count; r++)
{
if (r == i) continue;
var other = roomsGrids[r];
if (other.fieldInstance.Connections.Contains(room.fieldInstance)) continue; // Already connected
// Corridor connection relation
if (UseCorridorGuide)
if (limitConnections != -1)
if (HaveConnectionWithCorridor(other.fieldInstance))
{
reserve.Add(other);
continue;
}
if (room.fieldInstance.Checker.IsAligning(other.fieldInstance.Checker))
aligning.Add(other);
if (UseCorridorGuide) if (limitConnections != -1) if (aligning.Count >= limitConnections) break;
}
// Corridor connection relation
if (UseCorridorGuide) if (limitConnections != -1) if (aligning.Count < limitConnections)
{
for (int r = 0; r < reserve.Count; r++)
{
aligning.Add(reserve[r]);
if (aligning.Count >= limitConnections) break;
}
}
#endregion
if (room.fieldInstance.FieldRef != null)
if (room.fieldInstance.FieldRef.Preset)
for (int a = 0; a < aligning.Count; a++)
{
RectOfGeneratingHelper other = aligning[a];
// Generating guide for creating door on room side and other room side
SpawnInstruction instr = PGGUtils.GenerateInstructionTowards(room.fieldInstance.Checker, other.fieldInstance.Checker, 0);
instr.definition = room.fieldInstance.FieldRef.Preset.CellsInstructions[FromRoomsToRoomsGuideId];
room.guides.Add(instr);
room.fieldInstance.Connections.Add(other.fieldInstance);
// Making hole on other room to this room
SpawnInstruction pathInstr = PGGUtils.GenerateInstructionTowards(other.fieldInstance.Checker, room.fieldInstance.Checker, 0, new Vector2Int(instr.helperCoords.x, instr.helperCoords.z));
pathInstr.definition = other.fieldInstance.FieldRef.Preset.CellsInstructions[FromRoomToAlreadyConnectedRoomGuideId];
other.guides.Add(pathInstr);
other.fieldInstance.Connections.Add(room.fieldInstance);
}
}
#endregion
#region Using help guides if setted
if (HelpGuides != null)
{
List<RectOfGeneratingHelper> allGrids = new List<RectOfGeneratingHelper>();
if (UseCorridorGuide) allGrids.Add(corridorGrid);
if (roomsGrids.Count > 0) PGGUtils.TransferFromListToList<RectOfGeneratingHelper>(roomsGrids, allGrids);
if (StaticRooms.Count > 0) PGGUtils.TransferFromListToList<RectOfGeneratingHelper>(staticRoomGrids, allGrids);
for (int i = 0; i < HelpGuides.Count; i++)
{
var guide = HelpGuides[i];
// Find grid in which target cell exists
for (int g = 0; g < allGrids.Count; g++)
{
FGenCell cell = allGrids[g].grid.GetCell(guide.gridPosition, false);
if (FGenerators.CheckIfIsNull(cell )) continue;
if (cell.InTargetGridArea == false) continue;
//if (allGrids[i].fieldInstance.GetFieldSetup() == null) continue;
int definitionId = 0;
if (guide.helperType == EHelperGuideType.Spawn) definitionId = 1;
else if (guide.helperType == EHelperGuideType.ClearWall) definitionId = 2;
guide.definition = allGrids[g].fieldInstance.GetFieldSetup().CellsCommands[definitionId];
allGrids[g].guides.Add(guide);
break;
}
}
}
#endregion
#region Running instantiating
// Running FieldSetups and Instantiating all objects
ClearGenerated();
Generated = new List<InstantiatedFieldInfo>();
if (UseCorridorGuide)
{
if (CorridorPreset == null) { UnityEngine.Debug.Log("No Corridor preset!"); }
else
{
InstantiatedFieldInfo g = IGeneration.GenerateFieldObjectsWithContainer(CorridorPreset.name, CorridorPreset, corridorGrid.grid, transform, corridorGrid.guides, corridorGrid.inject);
Generated.Add(g);
}
}
for (int i = 0; i < staticRoomGrids.Count; i++)
{
if (staticRoomGrids[i].grid.AllApprovedCells.Count <= 0) continue;
if (staticRoomGrids[i].fieldInstance == null) continue;
if (staticRoomGrids[i].fieldInstance.FieldRefStatic == null) continue;
if (staticRoomGrids[i].fieldInstance.FieldRefStatic.Preset == null) continue;
FieldSetup targetFieldSetup = staticRoomGrids[i].fieldInstance.FieldRefStatic.Preset;
InstantiatedFieldInfo g = IGeneration.GenerateFieldObjectsWithContainer(targetFieldSetup.name, targetFieldSetup, staticRoomGrids[i].grid, transform, staticRoomGrids[i].guides, staticRoomGrids[i].inject);
Generated.Add(g);
}
for (int i = 0; i < roomsGrids.Count; i++)
{
if (roomsGrids[i].grid.AllApprovedCells.Count <= 0) continue;
FieldSetup targetFieldSetup = CorridorPreset;
if (roomsGrids[i].fieldInstance != null)
if (roomsGrids[i].fieldInstance.FieldRef != null)
if (roomsGrids[i].fieldInstance.FieldRef.Preset != null)
targetFieldSetup = roomsGrids[i].fieldInstance.FieldRef.Preset;
InstantiatedFieldInfo g = IGeneration.GenerateFieldObjectsWithContainer(targetFieldSetup.name, targetFieldSetup, roomsGrids[i].grid, transform, roomsGrids[i].guides, roomsGrids[i].inject);
Generated.Add(g);
}
#endregion
base.GenerateObjects();
}
/// <summary> Additional guides used in custom coding, helperType == Door -> command 0, Spawn -> command 1, ClearWall -> command 2 </summary>
public List<SpawnInstruction> HelpGuides = null;
bool HaveConnectionWithCorridor(RectOfFieldsInstance ins, bool deep = false)
{
for (int i = 0; i < ins.Connections.Count; i++)
{
if (ins.Connections[i].IsMainCorridor) return true;
if (deep)
for (int c = 0; c < ins.Connections[i].Connections.Count; c++)
if (ins.Connections[i].Connections[c].IsMainCorridor)
return true;
}
return false;
}
void InjectBuildupInstructions(RectOfGeneratingHelper room, CheckerField boundChecker, List<Vector2Int> edges, FieldSetup field)
{
if (InstructionIdOnRectEdges >= field.CellsInstructions.Count) return;
if (InstructionIdOnRectNeightbours >= field.CellsInstructions.Count) return;
var checker = room.fieldInstance.Checker;
// Adding remove walls on edges guides
for (int c = 0; c < edges.Count; c++)
if (checker.ContainsWorldPos(edges[c]))
{
SpawnInstruction guide;
#region Adding ghost cell guides to prevent removing inside walls in neightbour rooms
if (InstructionIdOnRectNeightbours >= 0)
{
Vector2Int checkPos = edges[c] + new Vector2Int(1, 0);
if (boundChecker.ContainsWorldPos(checkPos) && checker.ContainsWorldPos(checkPos) == false) { guide = new SpawnInstruction(); guide.gridPosition = boundChecker.FromWorldToGridPos(checkPos).V2toV3Int(); guide.definition = field.CellsInstructions[InstructionIdOnRectNeightbours]; room.guides.Add(guide); }
checkPos = edges[c] + new Vector2Int(-1, 0);
if (boundChecker.ContainsWorldPos(checkPos) && checker.ContainsWorldPos(checkPos) == false) { guide = new SpawnInstruction(); guide.gridPosition = boundChecker.FromWorldToGridPos(checkPos).V2toV3Int(); guide.definition = field.CellsInstructions[InstructionIdOnRectNeightbours]; room.guides.Add(guide); }
checkPos = edges[c] + new Vector2Int(0, 1);
if (boundChecker.ContainsWorldPos(checkPos) && checker.ContainsWorldPos(checkPos) == false) { guide = new SpawnInstruction(); guide.gridPosition = boundChecker.FromWorldToGridPos(checkPos).V2toV3Int(); guide.definition = field.CellsInstructions[InstructionIdOnRectNeightbours]; room.guides.Add(guide); }
checkPos = edges[c] + new Vector2Int(0, -1);
if (boundChecker.ContainsWorldPos(checkPos) && checker.ContainsWorldPos(checkPos) == false) { guide = new SpawnInstruction(); guide.gridPosition = boundChecker.FromWorldToGridPos(checkPos).V2toV3Int(); guide.definition = field.CellsInstructions[InstructionIdOnRectNeightbours]; room.guides.Add(guide); }
}
#endregion
// Remove outer walls guides
guide = new SpawnInstruction();
guide.gridPosition = boundChecker.FromWorldToGridPos(edges[c]).V2toV3Int();
guide.definition = field.CellsInstructions[InstructionIdOnRectEdges];
room.guides.Add(guide);
}
}
class RectOfGeneratingHelper
{
public FGenGraph<FieldCell, FGenPoint> grid;
public List<SpawnInstruction> guides;
public List<InjectionSetup> inject;
public RectOfFieldsInstance fieldInstance;
public RectOfGeneratingHelper(RectOfFieldsInstance ins)
{
grid = IGeneration.GetEmptyFieldGraph();
guides = new List<SpawnInstruction>();
inject = null;
if (FGenerators.CheckIfIsNull(ins ))
fieldInstance = new RectOfFieldsInstance();
else
fieldInstance = ins;
}
public void AddInject(InjectionSetup inj)
{
if (inject == null) inject = new List<InjectionSetup>();
inject.Add(inj);
}
}
private void OnValidate()
{
if (RefreshEveryChange) Prepare();
for (int i = 0; i < RoomPresets.Count; i++) RoomPresets[i].CheckReset();
for (int i = 0; i < StaticRooms.Count; i++) StaticRooms[i].CheckReset();
}
#region Gizmos
protected override void DrawGizmos()
{
Vector3 presetCellSize = new Vector3(2, 1, 2);
if (RoomPresets.Count > 0) if (RoomPresets[0].Preset) presetCellSize = RoomPresets[0].Preset.GetCellUnitSize();
if (CorridorPreset) presetCellSize = CorridorPreset.GetCellUnitSize();
presetCellSize.y *= 0.1f;
float cellSizeX = presetCellSize.x;
// Draw all shapes
if (mainCorridorInstance != null)
{
Gizmos.color = new Color(0.8f, 0.8f, 0.8f, 0.5f);
mainCorridorInstance.DrawGizmos(cellSizeX);
}
float step = 1f / (float)rInstances.Count;
for (int i = 0; i < rInstances.Count; i++)
{
if (rInstances[i].Setted == false) continue;
Gizmos.color = Color.HSVToRGB((step * i + (i % 2 == 0 ? 0.35f : 0f)) % 1, 0.7f, 0.6f);
rInstances[i].DrawGizmos(cellSizeX);
}
Gizmos.color = new Color(0.1f, 0.1f, 0.1f, 0.4f);
for (int i = 0; i < rStatic.Count; i++)
{
rStatic[i].DrawGizmos(cellSizeX);
}
CorridorGuide.DrawGizmos(cellSizeX, presetCellSize);
Gizmos.color = new Color(0.2f, 0.8f, 0.3f, 0.5f);
fullRectCheck.DrawGizmos(cellSizeX);
presetCellSize.y *= 0.1f;
Gizmos.color = new Color(0.1f, 0.1f, 0.1f, 0.85f);
Vector3 off = new Vector3(presetCellSize.x * 0.5f, 0f, presetCellSize.z * -0.5f);
float xs = PackingRectSize.x * 1f;
float zs = PackingRectSize.y * 1f;
Gizmos.DrawLine(new Vector3(-xs, 0, -zs) * cellSizeX + off, new Vector3(xs, 0, -zs) * cellSizeX + off);
Gizmos.DrawLine(new Vector3(xs, 0, -zs) * cellSizeX + off, new Vector3(xs, 0, zs) * cellSizeX + off);
Gizmos.DrawLine(new Vector3(xs, 0, zs) * cellSizeX + off, new Vector3(-xs, 0, zs) * cellSizeX + off);
Gizmos.DrawLine(new Vector3(-xs, 0, zs) * cellSizeX + off, new Vector3(-xs, 0, -zs) * cellSizeX + off);
}
#endregion
}
#region Inspector window with some enchancements
#if UNITY_EDITOR
[UnityEditor.CanEditMultipleObjects]
[UnityEditor.CustomEditor(typeof(RectangleOfFieldsGenerator))]
public class SimpleRectOfFieldsGeneratorEditor : PGGGeneratorBaseEditor
{
public RectangleOfFieldsGenerator Get { get { if (_get == null) _get = (RectangleOfFieldsGenerator)target; return _get; } }
private RectangleOfFieldsGenerator _get;
bool drawGen = false;
protected override void DrawGUIHeader()
{
UnityEditor.EditorGUILayout.HelpBox("This component is just simple generator for choosed 'Field Setups' push-packed into defined rect size", UnityEditor.MessageType.Info);
base.DrawGUIHeader();
}
protected override void DrawGUIBody()
{
drawGen = EditorGUILayout.Foldout(drawGen, "Draw Guides Ids to Choose", true);
if (drawGen)
{
SerializedProperty sp = serializedObject.FindProperty("FromMainCorridorToRoomsGuideId");
EditorGUIUtility.labelWidth = 250;
EditorGUILayout.PropertyField(sp); sp.Next(false);
EditorGUILayout.PropertyField(sp); sp.Next(false);
EditorGUILayout.PropertyField(sp); sp.Next(false);
EditorGUILayout.PropertyField(sp);
EditorGUIUtility.labelWidth = 0;
}
GUILayout.Space(4);
if (GUILayout.Button("Preview"))
{
Get.ClearGenerated();
Get.Prepare();
SceneView.RepaintAll();
}
if (GUILayout.Button("Generate"))
{
Get.GenerateObjects();
}
if (Get.Generated != null) if (Get.Generated.Count > 0) if (GUILayout.Button("Clear Generated")) Get.ClearGenerated();
}
protected override void DrawGUIFooter()
{
base.DrawGUIFooter();
UnityEditor.EditorGUILayout.HelpBox("All FieldSetups must have same Cell Size!", UnityEditor.MessageType.Info);
UnityEditor.EditorGUILayout.HelpBox("Walls in FieldSetups must be offsetted from grid margins to be able for fat walls", UnityEditor.MessageType.Info);
}
}
#endif
#endregion
}