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

com.github.mathiewz.slick.util.pathfinding.navmesh.NavMeshBuilder Maven / Gradle / Ivy

Go to download

The main purpose of this libraryis to modernize and maintain the slick2D library.

The newest version!
package com.github.mathiewz.slick.util.pathfinding.navmesh;

import java.util.ArrayList;

import com.github.mathiewz.slick.util.pathfinding.Mover;
import com.github.mathiewz.slick.util.pathfinding.PathFindingContext;
import com.github.mathiewz.slick.util.pathfinding.TileBasedMap;

/**
 * The builder responsible for converting a tile based map into
 * a navigation mesh
 *
 * @author kevin
 */
public class NavMeshBuilder implements PathFindingContext {
    /** The current x position we're searching */
    private int sx;
    /** The current y position we've searching */
    private int sy;
    /** The smallest space allowed */
    private final float smallestSpace = 0.2f;
    /** True if we're working tile based */
    private boolean tileBased;

    /**
     * Build a navigation mesh based on a tile map
     *
     * @param map
     *            The map to build the navigation mesh from
     *
     * @return The newly created navigation mesh
     */
    public NavMesh build(TileBasedMap map) {
        return build(map, true);
    }

    /**
     * Build a navigation mesh based on a tile map
     *
     * @param map
     *            The map to build the navigation mesh from
     * @param tileBased
     *            True if we'll use the tiles for the mesh initially
     *            rather than quad spacing
     * @return The newly created navigation mesh
     */
    public NavMesh build(TileBasedMap map, boolean tileBased) {
        this.tileBased = tileBased;

        ArrayList spaces = new ArrayList<>();

        if (tileBased) {
            for (int x = 0; x < map.getWidthInTiles(); x++) {
                for (int y = 0; y < map.getHeightInTiles(); y++) {
                    if (!map.blocked(this, x, y)) {
                        spaces.add(new Space(x, y, 1, 1));
                    }
                }
            }
        } else {
            Space space = new Space(0, 0, map.getWidthInTiles(), map.getHeightInTiles());

            subsection(map, space, spaces);
        }

        while (mergeSpaces(spaces)) {
        }
        linkSpaces(spaces);

        return new NavMesh(spaces);
    }

    /**
     * Merge the spaces that have been created to optimize out anywhere
     * we can.
     *
     * @param spaces
     *            The list of spaces to be merged
     * @return True if a merge occured and we'll have to start the merge
     *         process again
     */
    private boolean mergeSpaces(ArrayList spaces) {
        for (int source = 0; source < spaces.size(); source++) {
            Space a = spaces.get(source);

            for (int target = source + 1; target < spaces.size(); target++) {
                Space b = spaces.get(target);

                if (a.canMerge(b)) {
                    spaces.remove(a);
                    spaces.remove(b);
                    spaces.add(a.merge(b));
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Determine the links between spaces
     *
     * @param spaces
     *            The spaces to link up
     */
    private void linkSpaces(ArrayList spaces) {
        for (int source = 0; source < spaces.size(); source++) {
            Space a = spaces.get(source);

            for (int target = source + 1; target < spaces.size(); target++) {
                Space b = spaces.get(target);

                if (a.hasJoinedEdge(b)) {
                    a.link(b);
                    b.link(a);
                }
            }
        }
    }

    /**
     * Check if a particular space is clear of blockages
     *
     * @param map
     *            The map the spaces are being built from
     * @param space
     *            The space to check
     * @return True if there are no blockages in the space
     */
    public boolean clear(TileBasedMap map, Space space) {
        if (tileBased) {
            return true;
        }

        float x = 0;
        boolean donex = false;

        while (x < space.getWidth()) {
            float y = 0;
            boolean doney = false;

            while (y < space.getHeight()) {
                sx = (int) (space.getX() + x);
                sy = (int) (space.getY() + y);

                if (map.blocked(this, sx, sy)) {
                    return false;
                }

                y += 0.1f;
                if (y > space.getHeight() && !doney) {
                    y = space.getHeight();
                    doney = true;
                }
            }

            x += 0.1f;
            if (x > space.getWidth() && !donex) {
                x = space.getWidth();
                donex = true;
            }
        }

        return true;
    }

    /**
     * Subsection a space into smaller spaces if required to find a non-blocked
     * area.
     *
     * @param map
     *            The map being processed
     * @param space
     *            The space being sections
     * @param spaces
     *            The list of spaces that have been created
     */
    private void subsection(TileBasedMap map, Space space, ArrayList spaces) {
        if (!clear(map, space)) {
            float width2 = space.getWidth() / 2;
            float height2 = space.getHeight() / 2;

            if (width2 < smallestSpace && height2 < smallestSpace) {
                return;
            }

            subsection(map, new Space(space.getX(), space.getY(), width2, height2), spaces);
            subsection(map, new Space(space.getX(), space.getY() + height2, width2, height2), spaces);
            subsection(map, new Space(space.getX() + width2, space.getY(), width2, height2), spaces);
            subsection(map, new Space(space.getX() + width2, space.getY() + height2, width2, height2), spaces);
        } else {
            spaces.add(space);
        }
    }

    /**
     * Path finding context implementation
     *
     * @return The current mover
     */
    @Override
    public Mover getMover() {
        return null;
    }

    /**
     * Path finding context implementation
     *
     * @return The current search distance
     */
    @Override
    public int getSearchDistance() {
        return 0;
    }

    /**
     * Path finding context implementation
     *
     * @return The current x location
     */
    @Override
    public int getSourceX() {
        return sx;
    }

    /**
     * Path finding context implementation
     *
     * @return The current y location
     */
    @Override
    public int getSourceY() {
        return sy;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy