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

com.github.mathiewz.slick.util.pathfinding.navmesh.NavMesh 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;

/**
 * A nav-mesh is a set of shapes that describe the navigation of a map. These
 * shapes are linked together allow path finding but without the high
 * resolution that tile maps require. This leads to fast path finding and
 * potentially much more accurate map definition.
 *
 * @author kevin
 *
 */
public class NavMesh {
    /** The list of spaces that build up this navigation mesh */
    private final ArrayList spaces = new ArrayList<>();

    /**
     * Create a new empty mesh
     */
    public NavMesh() {

    }

    /**
     * Create a new mesh with a set of spaces
     *
     * @param spaces
     *            The spaces included in the mesh
     */
    public NavMesh(ArrayList spaces) {
        this.spaces.addAll(spaces);
    }

    /**
     * Get the number of spaces that are in the mesh
     *
     * @return The spaces in the mesh
     */
    public int getSpaceCount() {
        return spaces.size();
    }

    /**
     * Get the space at a given index
     *
     * @param index
     *            The index of the space to retrieve
     * @return The space at the given index
     */
    public Space getSpace(int index) {
        return spaces.get(index);
    }

    /**
     * Add a single space to the mesh
     *
     * @param space
     *            The space to be added
     */
    public void addSpace(Space space) {
        spaces.add(space);
    }

    /**
     * Find the space at a given location
     *
     * @param x
     *            The x coordinate at which to find the space
     * @param y
     *            The y coordinate at which to find the space
     * @return The space at the given location
     */
    public Space findSpace(float x, float y) {
        for (int i = 0; i < spaces.size(); i++) {
            Space space = getSpace(i);
            if (space.contains(x, y)) {
                return space;
            }
        }

        return null;
    }

    /**
     * Find a path from the source to the target coordinates
     *
     * @param sx
     *            The x coordinate of the source location
     * @param sy
     *            The y coordinate of the source location
     * @param tx
     *            The x coordinate of the target location
     * @param ty
     *            The y coordinate of the target location
     * @param optimize
     *            True if paths should be optimized
     * @return The path between the two spaces
     */
    public NavPath findPath(float sx, float sy, float tx, float ty, boolean optimize) {
        Space source = findSpace(sx, sy);
        Space target = findSpace(tx, ty);

        if (source == null || target == null) {
            return null;
        }

        for (int i = 0; i < spaces.size(); i++) {
            spaces.get(i).clearCost();
        }
        target.fill(source, tx, ty, 0);
        if (target.getCost() == Float.MAX_VALUE) {
            return null;
        }
        if (source.getCost() == Float.MAX_VALUE) {
            return null;
        }

        NavPath path = new NavPath();
        path.push(new Link(sx, sy, null));
        if (source.pickLowestCost(target, path)) {
            path.push(new Link(tx, ty, null));
            if (optimize) {
                optimize(path);
            }
            return path;
        }

        return null;
    }

    /**
     * Check if a particular path is clear
     *
     * @param x1
     *            The x coordinate of the starting point
     * @param y1
     *            The y coordinate of the starting point
     * @param x2
     *            The x coordinate of the ending point
     * @param y2
     *            The y coordinate of the ending point
     * @param step
     *            The size of the step between points
     * @return True if there are no blockages along the path
     */
    private boolean isClear(float x1, float y1, float x2, float y2, float step) {
        float dx = x2 - x1;
        float dy = y2 - y1;
        float len = (float) Math.sqrt(dx * dx + dy * dy);
        dx *= step;
        dx /= len;
        dy *= step;
        dy /= len;
        int steps = (int) (len / step);

        for (int i = 0; i < steps; i++) {
            float x = x1 + dx * i;
            float y = y1 + dy * i;

            if (findSpace(x, y) == null) {
                return false;
            }
        }

        return true;
    }

    /**
     * Optimize a path by removing segments that arn't required
     * to reach the end point
     *
     * @param path
     *            The path to optimize. Redundant segments will be removed
     */
    private void optimize(NavPath path) {
        int pt = 0;

        while (pt < path.length() - 2) {
            float sx = path.getX(pt);
            float sy = path.getY(pt);
            float nx = path.getX(pt + 2);
            float ny = path.getY(pt + 2);

            if (isClear(sx, sy, nx, ny, 0.1f)) {
                path.remove(pt + 1);
            } else {
                pt++;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy