So I am getting a Cellular Automator (CA) generator ready for this years 7DRL and hoping to create the same game in iOS and HTML5 – I am sure I am biting too much off. However, I have a basic implementation of a Dungeon generator and detailed how to create it below in X-Code using Objective-C. It’s a very simple implementation – so feel free to comment if you think we can clean the code up!!!!
In terms of CA there are some great references to get you going:
http://pcg.wikidot.com/pcg-algorithm:cellular-automata
http://www.futuredatalab.com/proceduraldungeon/
http://csharpcodewhisperer.blogspot.com.au/2013/07/Rouge-like-dungeon-generation.html
For this tutorial the dungeon is represented by 0’s as Rock and 1’s as Path (or moveable space).
This is the output so far:
So its a pretty simple set of steps to get us going.
Firstly create a OSX->Application->Command LineTool->Foundation project in Xcode
Then add a class called Dungeon
The header for Dungeon should look like this
#import <Foundation/Foundation.h> @interface Dungeon : NSObject { int map[100][100]; //max size of dungeon int maxRows; //size of this dungeon int maxCols; //size of this dungeon } - (id)initWithRows:(int)rows AndCol:(int)cols; -(void)printMap; @end
The implementation for this should look like
#import "Dungeon.h" @implementation Dungeon - (id)initWithRows:(int)rows AndCol:(int)cols { self = [super init]; if (self) { [self initMap]; maxRows = rows; maxCols = cols; [self createCellularAutomatorDungeon:maxRows ForCols:maxCols]; } return self; } //set all the map to rock -(void)initMap { for(int i=0;i<maxRows;i++) for(int j=0;j<maxCols;j++) map[i][j] = 0; } //Loop through the 2 dim array and add space (not rock) if the wall has a specific minimum neighbourCount - (void)createCellularAutomatorCellsForNeighbourCount:(int)neighbourCount { //first pass CA for(int i=0;i<maxRows;i++) { for(int j=0;j<maxCols;j++) { if (map[i][j] == 0 && ([self getNeighboursForRow:i ForCol:j]>=neighbourCount)) map[i][j] = 1; } } } //use a classic CA algorithm -(void)createCellularAutomatorDungeon:(int)rows ForCols:(int)cols { //randomly initialize wih a few random spaces in the rock for(int i=1;i<maxRows;i++) for(int j=1;j<maxCols;j++) if (arc4random()%4==1) map[i][j] = 1; [self createCellularAutomatorCellsForNeighbourCount:4];//first pass [self createCellularAutomatorCellsForNeighbourCount:5];//second pass } //Count of the number of neighbours for this point -(int)getNeighboursForRow:(int)row ForCol:(int)col { int n = 0; //top neighbours if (row>0 && col>0) { for(int i=col-1;i<col+2;i++) { if (map[row-1][i]==1) n++; } } //middle neighbour left if (col>0 && col<maxCols) if (map[row][col-1]==1) n++; //middle neighbour right if (col>0 && col<maxCols) if (map[row][col+1]==1) n++; //bottom neighbours if (row<maxRows && col<maxCols) { for(int i=col-1;i<col+2;i++) { if (map[row+1][i]==1) { n++; } } } return n; } -(BOOL)ifValidCoordinateForRow:(int)row ForCol:(int)col { return (map[col][row]==0 && row>0 && col > 0 && row<maxRows && col<maxCols); } -(void)printMap { for(int i=0;i<maxRows;i++) { for(int j=0;j<maxCols;j++) printf("%u", map[i][j] ); printf("\n"); } }
And make sure that main.m looks like
#import <Foundation/Foundation.h> #import "Dungeon.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Basic Dungeon CA Algorithm"); Dungeon *dungeon =[[Dungeon alloc]initWithRows:30 AndCol:50]; [dungeon printMap]; } return 0;
}
Ok so if you look at the code above in dungeon.m you should get a pretty good idea of how we are doing the generation of the dungeon using a CA algorithm. Read the comments as I have tried to explain anything a little unusual. If anything doesn’t make sense – leave a comment and I’ll get back to you.
Happy coding.
Pingback: My latest tutorial on Dungeon Generation for Xcode/Objective-C | Dungeon Bard