Skip to content

Project for final year Game AI Programming course at Goldsmiths, University of London

Notifications You must be signed in to change notification settings

cengared/GameAI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 

Repository files navigation

Coursework 2

My initial proposal for this coursework was to develop an engine to procedurally generate a maze and then have an AI controlled agent navigate the maze. I ran out of time to implement the navigating AI agent so this report will just cover how I built up the maze generation machine.

The first stage was to make a function that used a basic prefab which had the basic details of the maze, like the size and another prefab representing a simple floor tile (based on a quad object), and used it to generate a grid of floor tiles to the size as set by the maze prefab. At this point I research methods in which I could slow down this cell generation so the progress of it can be seen which led me into using a coroutine for the maze generation which allowed me to use the WaitForSeconds and Yield functions and so it was possible to display how the maze was being built.

At this point I was just using the size integers for controlling positions of cell tiles when I really needed to be using something like a vector to allow for the greater ease of selecting a random location for a cell tile and choosing the direction in which to place the next tile. In Unity there isn’t a vector function designed to just handle integers so I made a small struct to do just that with the added functionality of an overloaded + operator. With this MazeVector struct in place I went back to change the size integers in Maze to the new vector type and then changed the generation function to start with picking a random position within the world space of the maze and then generated tiles from that point.

That just resulted in a line of cells as the z value of the coordinate was just changed by one every time. In order for the maze to look like a maze, the tiles needed to be laid out along a path that is being generated at the same time which requires the change of direction every time a tile is generated. To facilitate this a Directions class was created which took a set of enums, that is a list of constants, which represented the four main cardinal directions and used them to enable the generation of vectors that represented each direction so when a random direction was selected a usable vector was sent back so that the generation algorithm could then use it to say where the next cell tile should go provided that it didn’t go somewhere where it had already been before which required the use of a list of activated cells. Backtracking was added here to allow the algorithm to find an unused direction in which to place the next cell and while this helps there is still a few things that needed to be added to make it so that an actual maze is being generated, things like walls and passages.

The edge between cells is very important and so a class was created to handle them by holding details of the two cells the edge is connected to and initialises them with relevant data. There are two types of edges in the maze - walls and passages, and after making the CellEdge class abstract I created classes for the edge type that use all the functionality of the abstract CellEdge class. The only differences between them are the prefabs attached to them. The Wall prefab is a simple thin box object at the north edge of the tile whereas the Passage prefab is just empty space. So now every time a cell met a cell which was already activated, or the algorithm selected a location outside of the defined maze world space, a wall edge was created between the two cells otherwise passage edges are created. An issue was left in that all the wall edges are placed on the north edge of their respective tiles and not where the actual wall should have been. To remedy this rotation data is needed and as I already had a Directions class holding directional related date I could use this to make a list of rotations required for each possible directions. Though online research I found that the best way to implement this was by using Quaternion.Euler and giving the number of degrees rotation that is required to change the wall placement from it’s default northern direction hence the first quaternion just uses an identity matrix as no rotation is necessary.

This still doesn’t completely fill the maze and some cells end up being completely walled off which isn’t what I wanted. To fix this there is need to track which edges of a cell have been initialised so that every cell edge becomes either a wall or a passage so that a cell is only removed from the active list when every edge of the cell has been initialised. After that it’s a bit trickier to select an unbiased random uninitialized direction but one method I found after a little researched used the idea of a randomly chosen number of skips, based on the number of uninitialised edges and then when looping through all of the edges of the cell it checks if the number of skips is zero and if so then that found edge is the direction return otherwise the number of skips is reduced by one and the loop continues. Unity required some protective fall back incase there was a mistake and the function was called on a cell without any uninitialised edges so an invalid operation exception was added.

The end result of this is a fully generated maze based on the Growing Tree algorithm and so when you press play in Unity a maze is generated. A new maze can be generated by pressing space bar while it’s still running. A video of this in action is linked here: https://youtu.be/x7ysHgzuOK0.

About

Project for final year Game AI Programming course at Goldsmiths, University of London

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages