Java路径查找简化

时间:2018-12-16 03:27:28

标签: java 2d-games

背景:我正在制作2D Moba游戏,我需要为游戏中的所有怪物寻路。我想提供一个startPos和endPos,让怪物在那里避开物体。

问题: 我一直在尝试在我的游戏中实现寻路功能,但我看不出它能正常工作。我想要的只是一些方法/类,在其中我可以给它一个二维数组(即true =占用&false =空闲),startPos,endPos,它为我提供了到达终点的一系列动作。到目前为止,我所有的实现都失败了。任何人都可以通过给我易于实现的代码提供帮助吗?

注意到目前为止,我已经尝试实现A ,它要么忽略墙,要么将角色发送到完全随机的方向。 *我确实使它工作了,但是方式很丑陋和错误。我让角色前进,直到撞上墙。然后它向右转并继续移动,直到可以向左转并继续向目的地行驶。这行得通,但我认为人们不希望他们的团队的怪物在墙上乱跑

修改: 下面的代码现在可以使用了!我发现由于某种原因,这些点是向后的,因此我不得不反转“点”列表。我不需要做的就是在点之间进行插值以提供平滑的运动。但是,我确实问我有什么办法不能增加对墙的偏见。例如,使点永远不会进入墙的1个单位内?

package NavMesh;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import toolbox.Maths;

public class MovementPath {

    private Node[][] mapOriginal;
    private Node[][] mapPath;

    public boolean solving = true;
    public int startX, startY, finishX, finishY, cells;
    private int checks = 0;
    private int length = 0;

    int realStartX, realStartY, realFinishX, realFinishY;

    NavMesh mesh;

    private Algorithm alg;
    List<Point> path = new ArrayList<Point>();

    public MovementPath(NavMesh mesh,int startX, int startY, int finishX, int finishY) {
        this.mapOriginal = mesh.getMapCopy();
        this.mesh = mesh;
        this.startX = startX;
        this.startY = startY;
        this.finishX = finishX;
        this.finishY = finishY;
        this.cells = mapOriginal.length;

        realStartX = startX;
        realStartY = startY;
        realFinishX = finishX;
        realFinishY = finishY;

        this.startX = (int) (Math.floor((float) startX / (float) mesh.cellWidth));
        this.startY = (int) (Math.floor((float) startY / (float) mesh.cellHeight));
        this.finishX = (int) (Math.floor((float) finishX / (float) mesh.cellWidth));
        this.finishY = (int) (Math.floor((float) finishY / (float) mesh.cellHeight));

        mapPath = new Node[mapOriginal.length][mapOriginal.length];
        System.arraycopy(mapOriginal, 0, mapPath, 0, mapOriginal.length);

        mapPath[this.startX][this.startY] = new Node(0,this.startX,this.startY);;
        mapPath[this.finishX][this.finishY] = new Node(1,this.finishX,this.finishY);

        addPointCentered(realFinishX,realFinishY);
        alg = new Algorithm();
        //alg.AStar();
        alg.Dijkstra();
        addPointCentered(realStartX,realStartY);
        mesh.drawMap(Integer.toString(Maths.randomRange(0, 1000)), mapPath);
    }

    public Path getPath(){
        //System.out.println("Returning path with " + getPathPoints().size() + " points");
        return new Path(getPathPoints());
    }

    private void addPointCentered(int x, int y) {
        path.add(new Point(x+(mesh.cellWidth/2),y+(mesh.cellHeight/2)));
    }

    public List<Point> getPathPoints(){
        List<Point> rPath = new ArrayList<Point>();
        for(int i = path.size()-1; i >= 0; i--) {
            rPath.add(path.get(i));
        }
        return rPath;
    }

    class Algorithm {   //ALGORITHM CLASS

        //A STAR WORKS ESSENTIALLY THE SAME AS DIJKSTRA CREATING A PRIORITY QUE AND PROPAGATING OUTWARDS UNTIL IT FINDS THE END
        //HOWEVER ASTAR BUILDS IN A HEURISTIC OF DISTANCE FROM ANY NODE TO THE FINISH
        //THIS MEANS THAT NODES THAT ARE CLOSER TO THE FINISH WILL BE EXPLORED FIRST
        //THIS HEURISTIC IS BUILT IN BY SORTING THE QUE ACCORDING TO HOPS PLUS DISTANCE UNTIL THE FINISH
        public void AStar() {
            ArrayList<Node> priority = new ArrayList<Node>();
            priority.add(mapPath[startX][startY]);
            while(solving) {
                if(priority.size() <= 0) {
                    solving = false;
                    break;
                }
                int hops = priority.get(0).getHops()+1;
                ArrayList<Node> explored = exploreNeighbors(priority.get(0),hops);
                if(explored.size() > 0) {
                    priority.remove(0);
                    priority.addAll(explored);
                } else {
                    priority.remove(0);
                }
                sortQue(priority);  //SORT THE PRIORITY QUE
            }
        }

        public void Dijkstra() {
            ArrayList<Node> priority = new ArrayList<Node>();   //CREATE A PRIORITY QUE
            priority.add(mapPath[startX][startY]);  //ADD THE START TO THE QUE
            while(solving) {
                if(priority.size() <= 0) {  //IF THE QUE IS 0 THEN NO PATH CAN BE FOUND
                    solving = false;
                    break;
                }
                int hops = priority.get(0).getHops()+1; //INCREMENT THE HOPS VARIABLE
                ArrayList<Node> explored = exploreNeighbors(priority.get(0), hops); //CREATE AN ARRAYLIST OF NODES THAT WERE EXPLORED
                if(explored.size() > 0) {
                    priority.remove(0); //REMOVE THE NODE FROM THE QUE
                    priority.addAll(explored);  //ADD ALL THE NEW NODES TO THE QUE
                } else {    //IF NO NODES WERE EXPLORED THEN JUST REMOVE THE NODE FROM THE QUE
                    priority.remove(0);
                }
            }
        }

        public ArrayList<Node> sortQue(ArrayList<Node> sort) {  //SORT PRIORITY QUE
            int c = 0;
            while(c < sort.size()) {
                int sm = c;
                for(int i = c+1; i < sort.size(); i++) {
                    if(sort.get(i).getEuclidDist(finishX,finishY)+sort.get(i).getHops() < sort.get(sm).getEuclidDist(finishX,finishY)+sort.get(sm).getHops())
                        sm = i;
                }
                if(c != sm) {
                    Node temp = sort.get(c);
                    sort.set(c, sort.get(sm));
                    sort.set(sm, temp);
                }   
                c++;
            }
            return sort;
        }

        /*
        public ArrayList<Node> exploreNeighbors(Node current, int hops) {   //EXPLORE NEIGHBORS
            ArrayList<Node> explored = new ArrayList<Node>();   //LIST OF NODES THAT HAVE BEEN EXPLORED
            for(int a = -1; a <= 1; a++) {
                for(int b = -1; b <= 1; b++) {
                    int xbound = current.getX()+a;
                    int ybound = current.getY()+b;
                    if((xbound > -1 && xbound < cells) && (ybound > -1 && ybound < cells)) {    //MAKES SURE THE NODE IS NOT OUTSIDE THE GRID
                        Node neighbor = mapPath[xbound][ybound];
                        if((neighbor.getHops()==-1 || neighbor.getHops() > hops) && neighbor.getType()!=2) {    //CHECKS IF THE NODE IS NOT A WALL AND THAT IT HAS NOT BEEN EXPLORED
                            explore(neighbor, current.getX(), current.getY(), hops);    //EXPLORE THE NODE
                            explored.add(neighbor); //ADD THE NODE TO THE LIST
                        }
                    }
                }
            }
            return explored;
        }
        */

        public ArrayList<Node> exploreNeighbors(Node current, int hops) {   //EXPLORE NEIGHBORS
            ArrayList<Node> explored = new ArrayList<Node>();   //LIST OF NODES THAT HAVE BEEN EXPLORED
            //test(hops, current, explored,current.getX(),current.getY());
            //test(hops, current, explored,current.getX()+1,current.getY());
            //test(hops, current, explored,current.getX()-1,current.getY());
            //test(hops, current, explored,current.getX(),current.getY()+1);
            //test(hops, current, explored,current.getX(),current.getY()-1);
            for(int a = -1; a <= 1; a++) {
                for(int b = -1; b <= 1; b++) {
                    test(hops, current, explored,current.getX()+a,current.getY()+b);
                }
            }
            return explored;
        }

        private void test(int hops, Node current, ArrayList<Node> explored, int xbound, int ybound) {
            if((xbound > -1 && xbound < cells) && (ybound > -1 && ybound < cells)) {    //MAKES SURE THE NODE IS NOT OUTSIDE THE GRID
                Node neighbor = mapPath[xbound][ybound];
                if((neighbor.getHops()==-1 || neighbor.getHops() > hops) && neighbor.getType()!=2) {    //CHECKS IF THE NODE IS NOT A WALL AND THAT IT HAS NOT BEEN EXPLORED
                    explore(neighbor, current.getX(), current.getY(), hops);    //EXPLORE THE NODE
                    explored.add(neighbor); //ADD THE NODE TO THE LIST
                }
            }
        }

        public void explore(Node current, int lastx, int lasty, int hops) { //EXPLORE A NODE
            if(current.getType()!=0 && current.getType() != 1)  //CHECK THAT THE NODE IS NOT THE START OR FINISH
                current.setType(4); //SET IT TO EXPLORED
            current.setLastNode(lastx, lasty);  //KEEP TRACK OF THE NODE THAT THIS NODE IS EXPLORED FROM
            current.setHops(hops);  //SET THE HOPS FROM THE START
            checks++;
            if(current.getType() == 1) {    //IF THE NODE IS THE FINISH THEN BACKTRACK TO GET THE PATH
                backtrack(current.getLastX(), current.getLastY(),hops);
            }
        }

        public void backtrack(int lx, int ly, int hops) {   //BACKTRACK
            length = hops;
            while(hops > 1) {   //BACKTRACK FROM THE END OF THE PATH TO THE START
                Node current = mapPath[lx][ly];
                current.setType(5);
                addPointCentered(lx*mesh.cellWidth,ly*mesh.cellHeight);
                //System.out.println("New Point: " + path.get(path.size()-1).toString());
                lx = current.getLastX();
                ly = current.getLastY();
                hops--;
            }
            solving = false;
        }
    }

}

1 个答案:

答案 0 :(得分:0)

尝试A *,我将其用于查找路径的问题。它很容易实现基于网格的移动,而且速度非常快。我是在Wikipedia页面上使用伪代码实现的。