
com.almasb.fxgl.pathfinding.dungeon.DungeonGrid Maven / Gradle / Ivy
The newest version!
/*
* FXGL - JavaFX Game Library. The MIT License (MIT).
* Copyright (c) AlmasB ([email protected]).
* See LICENSE for details.
*/
package com.almasb.fxgl.pathfinding.dungeon;
import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.pathfinding.CellState;
import com.almasb.fxgl.pathfinding.astar.TraversableGrid;
import static java.lang.Math.abs;
import static java.lang.Math.sqrt;
public class DungeonGrid extends TraversableGrid {
private static final DungeonConfig DEFAULT = new DungeonConfig(
FXGLMath.getRandom(),
6,
4, 9,
4, 9
);
private DungeonCell[][] tileMap;
private DungeonConfig config;
public DungeonGrid(int width, int height) {
this(width, height, DEFAULT);
}
public DungeonGrid(int width, int height, DungeonConfig config) {
super(DungeonCell.class, width, height, DungeonCell::new);
tileMap = getData();
this.config = config;
generateDungeon();
}
private void generateDungeon() {
if (config.numRooms() < 1)
throw new IllegalArgumentException("A dungeon must have at least 1 room.");
if (config.minRoomWidth() < 2)
throw new IllegalArgumentException("Minimum room width must be at least 2.");
if (config.minRoomHeight() < 2)
throw new IllegalArgumentException("Minimum room height must be at least 2.");
record Pos(int x, int y) {}
var random = config.random();
Pos[] roomPositions = new Pos[config.numRooms()];
// Pick initial room positions
for (int i = 0; i < roomPositions.length; i++) {
roomPositions[i] = new Pos(random.nextInt(getWidth()), random.nextInt(getHeight()));
}
// Clear out rooms
for (int i = 0; i < roomPositions.length; i++) {
if (random.nextInt(3) == 0) {
clearCircle(roomPositions[i].x, roomPositions[i].y, random.nextInt(3) + 1);
} else {
clearRect(roomPositions[i].x, roomPositions[i].y, randomRectWidth(), randomRectHeight());
}
// if there is just 1 room, then there is nothing to connect it to
if (config.numRooms() == 1)
break;
// Connect room i to a random room
int randomRoom = random.nextInt(roomPositions.length);
// Ensure i is not the same as the chosen random room
while (randomRoom == i) {
randomRoom = random.nextInt(roomPositions.length);
}
clearPath(roomPositions[i].x, roomPositions[i].y, roomPositions[randomRoom].x, roomPositions[randomRoom].y);
}
}
private void clearRect(int x, int y, int width, int height) {
for (int i = 0; i < tileMap.length; i++) {
for (int j = 0; j < tileMap[0].length; j++) {
int xDis = abs(i - x);
int yDis = abs(j - y);
if (xDis <= width / 2 && yDis <= height / 2) {
tileMap[i][j].setState(CellState.WALKABLE);
}
}
}
}
private void clearCircle(int xPos, int yPos, int radius) {
for (int i = 0; i < tileMap.length; i++) {
for (int j = 0; j < tileMap[0].length; j++) {
int xDis = abs(i - xPos);
int yDis = abs(j - yPos);
double tileDis = sqrt(xDis * xDis + yDis * yDis);
if (tileDis <= radius) {
tileMap[i][j].setState(CellState.WALKABLE);
}
}
}
}
private void clearPath(int xStart, int yStart, int xEnd, int yEnd) {
int[] clearPos = new int[2];
clearPos[0] = xStart;
clearPos[1] = yStart;
while (clearPos[0] != xEnd || clearPos[1] != yEnd) {
if (clearPos[0] < xEnd) clearPos[0]++;
else if (clearPos[0] > xEnd) clearPos[0]--;
else if (clearPos[1] < yEnd) clearPos[1]++;
else if (clearPos[1] > yEnd) clearPos[1]--;
tileMap[clearPos[0]][clearPos[1]].setState(CellState.WALKABLE);
}
}
private int randomRectWidth() {
return config.minRoomWidth() + config.random().nextInt(config.maxRoomWidth() - config.minRoomWidth() + 1);
}
private int randomRectHeight() {
return config.minRoomHeight() + config.random().nextInt(config.maxRoomHeight() - config.minRoomHeight() + 1);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy