All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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