Using the Generator - frasergeorgeking/UE4_BP_MazeGen_MIT GitHub Wiki
Mazes can be generated either directly within the editor using the provided Editor Utility Widget or, alternatively, at runtime. This section has been divided into two main sections to reflect these separate approaches.
The following guide presumes you have followed the prerequisites of the Getting Started page and have imported and set-up any custom tile geometry that you wish to use. This guide is using the default tiles provided with the project - please follow Custom Extensions to see how to import custom tiles. The guide also presumes that a single BP_MazeController
is present within the Unreal Engine level you are working in (see below).
A breakdown of individual generation properties and specific variables/events implemented by the generator is available here.
Whilst it is possible to implement in-editor generation using alternative methods (such as enabling Call in Editor for the required generator events), it is recommended that the provided Editor Utility Widget interface is used. This interface has been custom designed to make the in-editor generation process as streamlined as possible. A guide on how to render the Widget and dock it amongst the Unreal Engine interface is found here.
The Editor Utility Widget has been designed with a hierarchy of relevance in mind. Functions that are frequently used (such as Generate Maze
) are placed at the top of the interface, with less frequently used functions (such as Save Maze as CSV
) appearing at the bottom.
Procedurally generates a maze with the characteristics defined by the Maze Properties
section (the options here are explored in greater detail below). If a maze has already been generated and the Generate Maze
button is clicked again, the existing maze will be destroyed and a new maze will be procedurally generated.
Destroys the tiles associated with a previously spawned maze.
Opens an Asset Picker interface, upon which the user can select a data table from a previously exported and re-imported CSV file (see Asset Picker interface below). Data tables must be placed in the Content/Blueprints/ImportedCSVs
directory to appear in list. Upon double clicking the desired data table, spawns the associated maze. If a maze already exists in the scene before importing, it will be destroyed.
Please see here for instructions on creating a compatible data table from an exported CSV file.
Opens an Asset Picker interface, upon which the user can select the Tile Data Table to Spawn
. Data tables must be placed in the Content/Blueprints/TileDataTables
directory to appear in list.
The characteristics of the output of the maze can be configured by editing the variables found directly underneath the Maze Properties
header. For example, the position of the starting cell of the maze in world space can be directly effected by editing the value of Maze Spawn Loc
, as shown below. When a user is happy with the assigned properties, a maze can be generated by clicking the Generate Maze
button.
A Generated Maze with a 'MazeSpawnLoc' value of X: 0.0, Y: 0.0, Z: 0.0
.
A Generated Maze with a 'MazeSpawnLoc' value of X: 3000.0, Y: -4500.0, Z: 0.0
.
The dimensions of the maze can be directly edited by updating the Maze Height
and Maze Width
values. Please find examples of this below.
A Generated Maze with values of Maze Width = 5
and Maze Height = 5
.
A Generated Maze with values of Maze Width = 10
and Maze Height = 5
.
A Generated Maze with values of Maze Width = 10
and Maze Height = 5
.
By default the generator is configured to create and use a new random seed with every generation. This behaviour can be overridden by enabling Use Custom Seed?
and entering the desired seed. Overriding the seed ensures that the output of the generator is constant whenever the same seed is used. For example, using the seed 1159641216
with dimension values of Maze Width = 5
and Maze Height = 5
would create the following maze every single time it was generated:
If you wish to save a generated maze to file, fill out the parameters of the CSV Options
section and click the Save Maze as CSV
button (see below). If no CSV File Name
is provided, a name is automatically created based on the current date and time. Allow File Overwriting?
is set to false by default, setting it to true will allow the overwriting of files with identical names.
Exported CSVs are saved to a custom MazeCSVExports
folder in the root of the project (see below).
In order to regenerate the maze (either within the same project or another instance), a previously exported CSV must be added back into the project as a data table. We'll use the table exported in the previous Saving to CSV section as an example.
First, navigate to the directory where you wish to import the CSV within the Unreal Engine Editor. A folder has been pre-configured for this in the Content/Blueprints/ImportedCSVs
directory, however you can also import to custom locations (please note that if you intend to use the Editor Utility Widget, you'll need to update the Asset Registry Filter to your custom location - see below).
The Asset Registry Filter properties of ImportedCSVDataTableAssetPicker
- the PackagePaths
array determines which directories are included in the asset picker window.
Once you've navigated to the directory you'd like to use, click the Import
button - this will open the traditional UE4 Import window where you can then navigate to and select the CSV file you wish to use.
Once you've selected the CSV file, a DataTable Options
window will open. Please ensure that you configure the settings as per the screenshot below, paying special attention to ensure that the Data Table Row Type
has been set to TileCSVDataStructure
. This ensures that the contents of the CSV file is parsed correctly by Unreal Engine.
The CSV file has now been parsed into a UDataTable asset. As with any newly imported asset, please remember to save your changes.
To respawn the maze, simply click Import Maze from CSV
and select the Data Table that was just imported.
Once you've double clicked the data table asset, the maze will immediately spawn (be careful, this process will delete any pre-existing maze in the scene)!
To implement the generator in any dynamic capacity, understanding how runtime generation works is very important. This section provides a demonstration of how to utilise key generator events in the context of an example application (a program that auto-generates mazes every 1.5 seconds to showcase a 3D artist's assets). For the sake of simplicity, this application will be written inside of the Level Blueprint.
For more specific information about each key variable and event of the BP_MazeController
class, please see the 'Events' section of the Generation Properties documentation here.
Create and save a new level in the project. The image below uses the 'Default' new level preset and, as such, contains a pre-configured sky-sphere and lighting setup. With a new level craeted, add a single BP_MazeController
object into the scene.
Next, open the Level Blueprint (see below).
With the BP_MazeController
object selected in the main scene, right click in the Level Blueprint and select 'Create a Reference to BP_MazeController'. This will create a reference to the object in our level which we can then use to call the necessary generator functions.
With a reference to the BP_MazeController
in the scene, we can create a Single Cast Delegate in the form of the Create Event node. This delegate will let us execute the delegate functions of the BP_MazeController
class, including the custom GenerateMaze
event. This functionality can then be paired with the Set Timer by Event node to loop the function repeatedly (see below).
The Set Timer by Event Settings - Remember to add a negative Initial Start Delay, otherwise there will be a 1.5 second initial delay with no maze spawned!
Clicking 'Play' in Unreal Engine will produce the the following effect (the gif has been sped up for demonstration purposes).
This result is fine for a basic application, however what if we want to change the properties of the maze at runtime? For this, we'll need some form of User Interface where a user can input their desired dimensions. As per below, create a Widget Blueprint with a Spin Box for Width
values and a Spin Box for Height
values.
Remember to update the min & max slider values to clamp the range of Width and Height. You can also force the Spin Box to update in integers by lowering Min Fractional Digits
and Max Fractional Digits
to 0.
Next, implement the On Value Committed
events for each Spin Box - these events will fire when the spin box values are updated.
After these events are implemented, create a new function called GetMazeController
using the logic below. In the same way that we needed to reference the BP_MazeController
in the Level Blueprint, we also need to reference the controller in our Widget Blueprint.
Note: Get All Actors of Class
isn't the most efficient method of directly referencing an Actor, however it is used here for the purpose of brevity (it won't make a real difference for a project of this scope, either).
Next, when the value of one of the spin boxes is updated, we need to use our new GetMazeController
function to pull a reference to the maze controller and update the respective Width
or Height
value.
Lastly, we need to update our Level Blueprint with some basic logic to render the new Widget Blueprint - simply add the following nodes to our existing Begin Play
logic.
The final result should look something like the following: