MPewsey.ManiaMap
2.0.2
See the version list below for details.
dotnet add package MPewsey.ManiaMap --version 2.0.2
NuGet\Install-Package MPewsey.ManiaMap -Version 2.0.2
<PackageReference Include="MPewsey.ManiaMap" Version="2.0.2" />
paket add MPewsey.ManiaMap --version 2.0.2
#r "nuget: MPewsey.ManiaMap, 2.0.2"
// Install MPewsey.ManiaMap as a Cake Addin #addin nuget:?package=MPewsey.ManiaMap&version=2.0.2 // Install MPewsey.ManiaMap as a Cake Tool #tool nuget:?package=MPewsey.ManiaMap&version=2.0.2
ManiaMap
About
This package allows for the creation of procedurally generated metroidvania style layouts from user-defined level layout graphs and room templates. The resulting layouts can be used in games, such as those of the rouge-like genre, and to render maps, such as that shown below.
Features
- Single and multi-layer 2D room layout generation.
- Graph-based procedural generation.
- Specification of room connection constraints by defining door directions and matching door codes.
- Rendering of generated layouts to image files using built-in or custom map tiles.
- Procedural distribution of collectables throughout layout.
- Supports gradual map discovery through cell filters.
- Persistence of layout and layout state data through serialization.
- Supports .NET Standard 2.0.
- Works with Windows, Mac, and Linux.
Game Engine Support
- Unity: ManiaMap.Unity
Layout Generator Example
The following subsections outline how to use the LayoutGenerator
class to generate a room layout.
Step 1: Create Room Templates
The generator creates rooms by pulling from user-defined room templates. Room templates consist of a 2D array of cells, that may be empty (a null value) or filled. Each cell includes the possible door connections (north, south, east, west, top, and/or bottom) that can be made from that cell to other rooms. Furthermore, each door includes a door code, which requires a match in another template for a connection to be made, as well as a traversal type, such the door being one-way or two-way.
Depending on how much variety you want to be included in your layout, one or more templates are required by the generator. The following code provides an example for the creation of a simple 3x3 square room template. In it, a series of cells are created and have doors set to them via directional characters ("N" = North, "S" = South, etc.). The cells are then assigned to a 2D array to create the geometry of the layout. Finally, these cells are passed to the RoomTemplate
initializer, along with a unique ID, to create the room template.
var o = Cell.New;
var a = Cell.New.SetDoors("WN", Door.TwoWay);
var b = Cell.New.SetDoors("N", Door.TwoWay);
var c = Cell.New.SetDoors("NE", Door.TwoWay);
var d = Cell.New.SetDoors("W", Door.TwoWay);
var e = Cell.New.SetDoors("E", Door.TwoWay);
var f = Cell.New.SetDoors("WS", Door.TwoWay);
var g = Cell.New.SetDoors("S", Door.TwoWay);
var h = Cell.New.SetDoors("SE", Door.TwoWay);
var cells = new Cell[,]
{
{ a, b, c },
{ d, o, e },
{ f, g, h },
};
var roomTemplate = new RoomTemplate(id: 1, name: "Square", cells);
Step 2: Assign Room Templates to Template Groups
Once some room template have been defined, they must be added to one or more room template groups, which can be referenced by name later. This is accomplished by simply adding them to a TemplateGroups
object:
var templateGroups = new TemplateGroups();
templateGroups.Add("Default", roomTemplate);
Step 3: Create a Layout Graph
To provide a designed feel to generated layouts, the generator uses a room layout graph as the basis for generating layouts. The layout graph consists of nodes, representing rooms, and edges, representing door connections between rooms. Ultimately, the layout graph contains information to help guide the features of a room layout. Each graph element can be assigned one or more room template groups (created in Step 2) from which room templates can be drawn for that location. Z (layer) values can also be assigned to elements to create a multi-level room layout. In addition, properties such as names and colors can be assigned that will be passed on to the generated rooms, allowing for their use elsewhere in a game or other application.
In the below example, the graph shown in the image is created by adding edges to a graph. In the process, the nodes, representing rooms, are automatically created. Afterwards, the code loops over all of the created nodes and assigns a "Default" template group to them, from which room templates will be drawn by the generator.
var graph = new LayoutGraph(id: 1, name: "ExampleGraph");
// Define edges between nodes. Nodes not already in graph will automatically be created.
graph.AddEdge(0, 1);
graph.AddEdge(1, 2);
graph.AddEdge(0, 3);
graph.AddEdge(0, 4);
graph.AddEdge(0, 5);
// Add "Default" template group to nodes.
foreach (var node in graph.GetNodes())
{
node.TemplateGroup = "Default";
}
Step 4: Run the Layout Generator
To create repeatable layouts, a random seed is used by the layout generator. To generate a room layout, simply select a seed and pass your layout graph and room template groups to the LayoutGenerator
, as shown below. In the example, a map of the layout is also rendered and saved using the LayoutMap
class. For this instance, the default built-in tiles are used. However, custom tiles can also be specified by the user.
var seed = new RandomSeed(12345);
var generator = new LayoutGenerator();
var layout = generator.Generate(layoutId: 1, graph, templateGroups, seed);
// Render map and save it to file
var map = new LayoutMap();
map.SaveImage("Map.png", layout);
Collectable Generator Example
The collectable generator distributes collectables throughout a layout.
var seed = new RandomSeed(12345);
var generator = new CollectableGenerator();
// Add collectable ID's to groups. Multiple ID's may be added for the same item.
// These groups will also need to be assigned to some room template cells.
var collectableGroups = new CollectableGroups();
collectableGroups.Add("Group1", new int[] { 1, 1, 1, 2, 3, 4, 5 });
collectableGroups.Add("Group2", new int[] { 6, 7, 7, 8, 8, 9, 10 });
generator.Generate(layout, collectableGroups, seed);
Layout Graph Selector Example
The layout graph selector draws a random layout graph from a supplied list. This is useful when used as an early step in a GenerationPipeline
.
// Create a list of graphs from which to draw.
var graphs = new List<LayoutGraph>
{
new LayoutGraph(id: 1, name: "ExampleGraph1"),
new LayoutGraph(id: 2, name: "ExampleGraph2"),
new LayoutGraph(id: 3, name: "ExampleGraph3"),
};
var seed = new RandomSeed(12345);
var selector = new LayoutGraphSelector();
var graph = selector.DrawSelection(graphs, seed);
Layout Graph Randomizer Example
The layout graph randomizer generates variations of a layout graph based on user-defined swappable nodes.
var seed = new RandomSeed(12345);
var graph = new LayoutGraph(id: 1, name: "ExampleGraph");
// Add any nodes and edges to the graph.
// See the previous Layout Generator example.
// Add nodes to variation groups.
// The nodes in these groups will be shuffled and swapped by the randomizer.
graph.AddNodeVariation("Group1", new int[] { 1, 5, 3 });
graph.AddNodeVariation("Group2", new int[] { 0, 7, 10, 12 });
// Create a randomizer and create a new graph variation.
var randomizer = new LayoutGraphRandomizer();
var graphVariation = randomizer.RandomizeGraph(graph, seed);
Generation Pipeline Example
The generation pipeline provides a way for multiple generation steps to be chained together. This is often easier than making manual calls to each generation step.
// Create a dictionary of arguments to be passed to each pipeline step.
var args = new Dictionary<string, object>
{
{ "LayoutId", 1 },
{ "LayoutGraph", graph },
{ "TemplateGroups", templateGroups },
{ "CollectableGroups", collectableGroups },
{ "RandomSeed", seed },
};
// Use the default pipeline
var pipeline = GenerationPipeline.CreateDefaultPipeline();
// Or create your own
pipeline = new GenerationPipeline(new LayoutGenerator(), new CollectableGenerator());
var results = pipeline.Generate(args);
var layout = (Layout)results.Outputs["Layout"];
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- SixLabors.ImageSharp (>= 2.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.5.1 | 128 | 7/23/2024 |
2.5.0 | 157 | 5/13/2024 |
2.4.0 | 244 | 11/5/2023 |
2.3.0 | 392 | 10/17/2022 |
2.2.0 | 408 | 9/27/2022 |
2.1.0 | 391 | 9/9/2022 |
2.0.3 | 396 | 9/3/2022 |
2.0.2 | 374 | 8/27/2022 |
2.0.1 | 390 | 8/11/2022 |
2.0.0 | 414 | 6/29/2022 |
1.5.0 | 427 | 5/30/2022 |
1.4.1 | 410 | 5/30/2022 |
1.4.0 | 409 | 5/29/2022 |
1.3.0 | 413 | 5/26/2022 |
1.2.0 | 441 | 4/19/2022 |
1.1.0 | 421 | 4/15/2022 |
1.0.0 | 416 | 4/3/2022 |