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);
One thought on “Java Roguelike notes (2/13): Creating a procedurally generated dungeon”