The algorithm that creates a procedural map is based on my previous post and algorithm in C# , most of work was trying to adapt it to Java and had to take different approaches until I could finally translate it. The process goes as follows:

- We generate a basic Tile Board, where each point is a coordinate. Here comes the first difference, while in C# I was using Vector2, in Java I used Point2D.
- After the Tile map base is up and running, we set the Floors. Why Floors first? I’ll be using a Walkers algorithm: A bunch of Walkers will be initiated, and on each iteration they’ll go a different direction, creating the floors and opening up the map. This also assures that all rooms are reachable.
- Now we generate the Walls, which are the remaining Tiles after the Floors had been set.
The GameBoard:
System.out.println("[Board - General] WIDTH: " + SCREEN_WIDTH/UNIT_SIZE + "x HEIGHT: " + SCREEN_HEIGHT/UNIT_SIZE);
// 1. Global board:
for (int x=0; x<SCREEN_WIDTH; x += 25){
for (int y=0; y<SCREEN_HEIGHT; y += 25){
Point2D _tilePos = new Point2D.Double(x,y);
allPositions.add(_tilePos);
}
}
System.out.println("[Board - All positions] " + allPositions.size() + " tile positions");
The Floors:
public void setFloors(){
System.out.println("[Board - Floor] Setting up floors...");
// 1 - Create Walkers:
for (int i=0; i < _initialNumberOfWalkers; i++){
Walker _walker = new Walker();
_walker.walkerPosition = new Point2D.Double(12.0,12.0);
listOfWalkers.add(_walker);
}
System.out.println("[Board - Floor] Walkers: " + listOfWalkers.size());
// 2 - Set Walkers to walk randomly, and create the floor map
for (int i=0; i < _initialNumberOfWalkerIterations; i++){
walkerBehaviour(listOfWalkers);
}
System.out.println("[Board - Floor] Floor tile positions: " + listOfFloorTilePositions.size());
System.out.println("[Board - Floor] Floor tiles: " + listOfFloorTiles.size());
System.out.println("[Board - Floor] Floor Complete");
}
The Walls:
void setWalls(){
List<Point2D> _normalizedFloorPos = new ArrayList<>();
for (int i = 0; i < listOfFloorTilePositions.size(); i++){
_normalizedFloorPos.add(helperUnitMultiplier(listOfFloorTilePositions.get(i).getX(), listOfFloorTilePositions.get(i).getY()));
}
// 1. Now we find the differences: Walls = All - Floors:
List<Point2D> _wallPos = new ArrayList<>(allPositions);
_wallPos.removeAll(_normalizedFloorPos);
// 2. We generate a new list of Tiles for each valid position:
for (int i = 0; i < _wallPos.size(); i++){
Double _wallX = _wallPos.get(i).getX();
Double _wallY = _wallPos.get(i).getY();
Tile _wallTile = new Tile();
_wallTile.tilePosition = new Point2D.Double(_wallX,_wallY);
listOfWallTiles.add(_wallTile); // Tile to Tile list
listOfOccupiedTilePositions.add(_wallTile.tilePosition); //Position to Position (All) list
}
System.out.println("[Board - Walls] Drawing walls...");
System.out.println("[Board - Walls] Wall tiles: " + listOfWallTiles.size());
System.out.println("[Board - Walls] Floor Complete");
}
The Walkers:
public void walkerBehaviour(List<Walker> _inputListOfWalkers){
for (int i=0; i<_inputListOfWalkers.size();i++){
// Walkers new position will be a random direction from current position:
Point2D _walkerPos = _inputListOfWalkers.get(i).walkerPosition;
_inputListOfWalkers.get(i).walkerPosition = randomDirection(_walkerPos);
}
}
public Point2D randomDirection(Point2D _currentWalkerPosition){
// 1. Get current walker position
Double _walkerX = _currentWalkerPosition.getX();
Double _walkerY = _currentWalkerPosition.getY();
// 2. draw() will be responsible of drawing the List, we jump into Walker's Direction now:
Random _randomRange = new Random();
int _r = _randomRange.nextInt(4);
switch (_r){
case 0:
_walkerY += 1.0; // up
break;
case 1:
_walkerY -= 1.0; // down
break;
case 2:
_walkerX += 1.0; // left
break;
case 3:
_walkerX -= 1.0; // right
break;
}
// 3. Boundaries, if walker hits these tiles, turn back:
if (_walkerX < 0.0 ) { //Checks X-- and turns the walker around
_walkerX = _walkerX * -1;
}
if (_walkerY < 0.0){ // Checks Y-- and turns the walker around
_walkerY = _walkerY * -1;
}
// 4. Set new walker position:
_currentWalkerPosition.setLocation(_walkerX, _walkerY);
// 4.5 Check for duplicates and skip if needed.
if (listOfOccupiedTilePositions.contains(_currentWalkerPosition)){
assert true; // If this position already exist in our list, do nothing,
} else {
// 5. Place a new Tile as the walkers move into each new position, and save coordinates:
Tile _tile = new Tile();
_tile.tilePosition = new Point2D.Double(_walkerX,_walkerY);
listOfFloorTiles.add(_tile); // Tile to Tile list
listOfFloorTilePositions.add(_tile.tilePosition); // Position to Position (Floor) list
listOfOccupiedTilePositions.add(_tile.tilePosition); // Position to Position (All) list
}
return _currentWalkerPosition;
}
Caveats:
- Was important to set different lists for coordinates, and for the object itself. This was pretty different from C# where I could operate with the same one.
- Important to double check your UNIT_SIZE, as if any of the Tiles have the wrong one it will mess with List operations when generating the map, like .removeAll(), .commons(), and others.
- I seem unable to make work some built-in methods, this is most likely my lack of understanding of how Java works and trying to assign variables to Null, for example here I wasn’t expecting I had to instantiate a new Point2D but just assign the previous assignments of X and Y to the object via .setLocation():
// Will not work:
Tile _wallTile = new Tile();
int _wallXPos = (int)allPositions.get(i).getX();
int _wallYPos = (int)allPositions.get(i).getY();
_wallTile.tilePosition.setLocation(_wallXPos,_wallYPos);
// Will work:
Tile _wallTile = new Tile();
int _wallXPos = (int)allPositions.get(i).getX();
int _wallYPos = (int)allPositions.get(i).getY();
_wallTile.tilePosition = new Point2D.Double(_wallXPos,_wallYPos);
Leave a Reply