背景:我正在制作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;
}
}
}
答案 0 :(得分:0)
尝试A *,我将其用于查找路径的问题。它很容易实现基于网格的移动,而且速度非常快。我是在Wikipedia页面上使用伪代码实现的。