Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: New generation steps #222

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions GoRogue/MapGeneration/Steps/BackRoomGeneration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System.Collections.Generic;
using System.Linq;
using GoRogue.MapGeneration.ContextComponents;
using GoRogue.Random;
using JetBrains.Annotations;
using SadRogue.Primitives;
using SadRogue.Primitives.GridViews;
using Troschuetz.Random;

namespace GoRogue.MapGeneration.Steps
{
/// <summary>
/// Creates a series of irregularly-sized rectangles.
/// </summary>
/// <remarks>
///
/// </remarks>
[PublicAPI]
public class BackRoomGeneration : GenerationStep
{
/// <summary>
/// Optional tag that must be associated with the component used to store rooms generated by this algorithm.
/// </summary>
public readonly string? RoomsComponentTag;

/// <summary>
/// Optional tag that must be associated with the component used to set wall/floor status of tiles changed by this
/// algorithm.
/// </summary>
public readonly string? WallFloorComponentTag;

/// <summary>
/// RNG to use for maze generation.
/// </summary>
public IGenerator RNG = GlobalRandom.DefaultRNG;

/// <summary>
/// The width of a side of the parallelogram
/// </summary>
public int RoomWidth = 7;

/// <summary>
/// Vertical Height of the Parallelogram
/// </summary>
public int RoomHeight = 4;

/// <summary>
/// Creates a new grid of parallelograms.
/// </summary>
/// <param name="name">The name of the generation step. Defaults to <see cref="ParallelogramGeneration" />.</param>
/// <param name="roomsComponentTag">
/// Optional tag that must be associated with the component used to store rooms. Defaults
/// to "Rooms".
/// </param>
/// <param name="wallFloorComponentTag">
/// Optional tag that must be associated with the map view component used to store/set
/// floor/wall status. Defaults to "WallFloor".
/// </param>
public BackRoomGeneration(string? name = null, string? roomsComponentTag = "Parallelograms",
string? wallFloorComponentTag = "WallFloor")
: base(name)
{
RoomsComponentTag = roomsComponentTag;
WallFloorComponentTag = wallFloorComponentTag;
}

/// <inheritdoc />
protected override IEnumerator<object?> OnPerform(GenerationContext context)
{
// Get or create/add a wall-floor context component
var wallFloorContext = context.GetFirstOrNew<ISettableGridView<bool>>(
() => new ArrayView<bool>(context.Width, context.Height),
WallFloorComponentTag
);

// Get or create/add a rooms context component
var roomsContext = context.GetFirstOrNew(
() => new ItemList<Rectangle>(),
RoomsComponentTag
);

var largeRooms = new List<Rectangle>();

int thirdWidth = wallFloorContext.Width / 3;
int halfWidth = wallFloorContext.Width / 2;
int thirdHeight = wallFloorContext.Height / 3;
int halfHeight = wallFloorContext.Height / 2;

if (RNG.Next(0, 2) % 2 == 0)
{
if (RNG.Next(0, 2) % 2 == 0)
{
largeRooms.Add(new Rectangle(halfWidth - 1, 0, halfWidth, wallFloorContext.Height));
largeRooms.Add(new Rectangle(0, 0, halfWidth, thirdHeight));
largeRooms.Add(new Rectangle(0, thirdHeight - 1, halfWidth, thirdHeight));
largeRooms.Add(new Rectangle(0, thirdHeight * 2 - 1, halfWidth, thirdHeight));
}
else
{
largeRooms.Add(new Rectangle(0, 0, halfWidth, wallFloorContext.Height));
largeRooms.Add(new Rectangle(halfWidth - 1, 0, halfWidth, thirdHeight));
largeRooms.Add(new Rectangle(halfWidth - 1, thirdHeight - 1, halfWidth, thirdHeight));
largeRooms.Add(new Rectangle(halfWidth - 1, thirdHeight * 2 - 1, halfWidth, thirdHeight));
}
}
else
{
if (RNG.Next(0, 2) % 2 == 0)
{
largeRooms.Add(new Rectangle(0,0, wallFloorContext.Width, halfHeight));
largeRooms.Add(new Rectangle(0, halfHeight - 1, thirdWidth, halfHeight));
largeRooms.Add(new Rectangle(thirdWidth - 1, halfHeight - 1, thirdWidth, halfHeight));
largeRooms.Add(new Rectangle(thirdWidth * 2 - 1, halfHeight - 1, thirdWidth, halfHeight));
}
else
{
largeRooms.Add(new Rectangle(0,halfHeight - 1, wallFloorContext.Width, halfHeight));
largeRooms.Add(new Rectangle(0, 0, thirdWidth, halfHeight));
largeRooms.Add(new Rectangle(thirdWidth - 1, 0, thirdWidth, halfHeight));
largeRooms.Add(new Rectangle(thirdWidth * 2 - 1, 0, thirdWidth, halfHeight));
}
}

foreach(var rectangle in largeRooms)
roomsContext.AddRange(rectangle.BisectRecursive(RNG.Next(3,9)), Name);

foreach (var room in roomsContext)
{
foreach (var point in room.Item.Positions())
{
if (point.X == room.Item.MinExtentX || point.Y == room.Item.MaxExtentY)
wallFloorContext[point] = false;
else
wallFloorContext[point] = true;
}

yield return null;
}

yield return null;
}
}
}
92 changes: 92 additions & 0 deletions GoRogue/MapGeneration/Steps/CompositeGenerationStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.Linq;
using SadRogue.Primitives;
using SadRogue.Primitives.GridViews;

namespace GoRogue.MapGeneration.Steps
{
/// <summary>
/// This generation step sections the map into regions and then applies a different generation step to each region.
/// </summary>
public class CompositeGenerationStep : GenerationStep
{
private readonly System.Random _random;
private readonly IEnumerable<Region> _regions;
private readonly int _width;
private readonly int _height;

private readonly List<GenerationStep[]> _stepSets;

/// <summary>
/// Constructor for the default Composite Generation Algorithm
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
public CompositeGenerationStep(int width, int height)
{
_width = width;
_height = height;
_stepSets = new List<GenerationStep[]>()
{
DefaultAlgorithms.DungeonMazeMapSteps(null, 0, 0).ToArray(),
new GenerationStep[] { new BackRoomGeneration() },
new GenerationStep[] { new ParallelogramGeneration() },
new GenerationStep[] { new SpiralGeneration() },

new GenerationStep[]
{
new RandomViewFill(),
new CellularAutomataAreaGeneration(),
},
};
_random = new System.Random();
_regions = GenerateRegions();
}

/// <inheritdoc/>
protected override IEnumerator<object?> OnPerform(GenerationContext context)
{
var map = context.GetFirstOrNew<ISettableGridView<bool>>
(() => new ArrayView<bool>(context.Width, context.Height));

foreach (var region in _regions)
{
var generator = new Generator(region.Width, region.Height);
generator.AddSteps(SelectSteps());
generator = generator.Generate();
var subMap = generator.Context.GetFirst<ISettableGridView<bool>>();

foreach (var here in region.Points)
{
if (map.Contains(here))
{
map[here] = subMap[here - (region.Left, region.Top)];
}
}

yield return null;
}
yield return null;
}

/// <summary>
/// Picks a random set of generation steps among those registered
/// </summary>
/// <returns></returns>
private IEnumerable<GenerationStep> SelectSteps() => _stepSets[_random.Next(0, _stepSets.Count)];

/// <summary>
/// Sections the map into regions of equal size
/// </summary>
/// <returns></returns>
private IEnumerable<Region> GenerateRegions()
{
double rotationAngle = 45;//_random.Next(360);
int minimumDimension = 14;//_random.Next(25, 50);

var wholeMap = new Rectangle(-_width, -_height,_width * 2,_height * 2);
foreach (var room in wholeMap.BisectRecursive(minimumDimension))
yield return Region.FromRectangle("room", room).Rotate(rotationAngle);
}
}
}
93 changes: 93 additions & 0 deletions GoRogue/MapGeneration/Steps/ParallelogramGeneration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.Linq;
using GoRogue.MapGeneration.ContextComponents;
using JetBrains.Annotations;
using SadRogue.Primitives.GridViews;

namespace GoRogue.MapGeneration.Steps
{
/// <summary>
/// Carves out non-overlapping parallelograms in a map.
/// </summary>
/// <remarks>
///
/// </remarks>
[PublicAPI]
public class ParallelogramGeneration : GenerationStep
{
/// <summary>
/// Optional tag that must be associated with the component used to store rooms generated by this algorithm.
/// </summary>
public readonly string? RoomsComponentTag;

/// <summary>
/// Optional tag that must be associated with the component used to set wall/floor status of tiles changed by this
/// algorithm.
/// </summary>
public readonly string? WallFloorComponentTag;

/// <summary>
/// The width of a side of the parallelogram
/// </summary>
public int RoomWidth = 7;

/// <summary>
/// Vertical Height of the Parallelogram
/// </summary>
public int RoomHeight = 4;

/// <summary>
/// Creates a new grid of parallelograms.
/// </summary>
/// <param name="name">The name of the generation step. Defaults to <see cref="ParallelogramGeneration" />.</param>
/// <param name="roomsComponentTag">
/// Optional tag that must be associated with the component used to store rooms. Defaults
/// to "Rooms".
/// </param>
/// <param name="wallFloorComponentTag">
/// Optional tag that must be associated with the map view component used to store/set
/// floor/wall status. Defaults to "WallFloor".
/// </param>
public ParallelogramGeneration(string? name = null, string? roomsComponentTag = "Parallelograms",
string? wallFloorComponentTag = "WallFloor")
: base(name)
{
RoomsComponentTag = roomsComponentTag;
WallFloorComponentTag = wallFloorComponentTag;
}

/// <inheritdoc />
protected override IEnumerator<object?> OnPerform(GenerationContext context)
{
// Get or create/add a wall-floor context component
var wallFloorContext = context.GetFirstOrNew<ISettableGridView<bool>>(
() => new ArrayView<bool>(context.Width, context.Height),
WallFloorComponentTag
);

// Get or create/add a rooms context component
var roomsContext = context.GetFirstOrNew(
() => new ItemList<Region>(),
RoomsComponentTag
);

for (int i = -5; i < wallFloorContext.Width; i += RoomWidth)
{
for (int j = 0; j < wallFloorContext.Height; j += RoomHeight)
{
var region = Region.RegularParallelogram("parallelogram", (i,j), RoomWidth, RoomHeight, 0);
roomsContext.Add(region, Name);

foreach (var point in region.InnerPoints.Positions.Where(p => wallFloorContext.Contains(p)))
wallFloorContext[point] = true;

foreach (var point in region.OuterPoints.Positions.Where(p => wallFloorContext.Contains(p)))
wallFloorContext[point] = false;

}

yield return null;
}
}
}
}
Loading