在制作MMO类型游戏时,角色的寻路可以放在客户端进行(基本上现在的游戏引擎都有寻路支持),这个时候服务端只需要做些寻路校验即可。可对于NPC来说,如果放到客户端是乎就不太合理了,单人副本或许还勉强可行,对于多人联机副本来说,就不好弄了,这个时候就需要服务端来对NPC做寻路处理。
如何设计NPC寻路
假设NPC要从A点到B点,如果都是直接走直线(两点距离)也就无所谓寻路了,而在游戏场景中会有很多地方设置了障碍物,那么遇到有障碍物的地方就得绕路走,最终才到达终点。把所以经过的点串起来这就是一个路径了。
那么我们在设计算法时就得有个依据,有个规则:每走一步我们都认为走的这点到终点的直线距离最短的这个点(不能是障碍物点)就是我们要走的点,不需要考虑这点与终点之间是否有障碍物。
image.png
如图,按照这个规则从A到B,中途会经过a,b,c点。b点是个很重要点,按我们的原则来说走到a点时,肯定下一步就是要走到b点,因为此时b点距离B点的直线距离最近。而走到b之后,会发现此时没法往前走(前面都是障碍物)了。所以在设计算法时,这个时候就得往回退一步,回到a点,再找下一步(此时要把b排除在外,否则就死寻死路了),往后直到走到B点。
代码实现
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* NPC寻路封装
* @author chester
*
*/
public class WayFinding {
//有效路径
private LinkedList path = new LinkedList<>();
//当前要检测的点
private List checks = new ArrayList<>();
//起点
private int[] start;
//终点
private int[] end;
//是否寻路结束
private boolean finish = false;
private static final Boolean flag = new Boolean(true);
//存放所以已经检测过的点
private Map checked = new HashMap<>();
//
private Map> removePaths = new HashMap<>();
public WayFinding(int[] start,int[] end) {
this.start = start;
this.end = end;
this.path.add(this.start);
}
/**
* 添加检测的坐标
* 如果此坐标已经被检测过,则不能添加
* @param x
* @param y
*/
private void addCheck(int x,int y) {
boolean add = true;
for (int[] checkedOne : checked.keySet()) {
if(checkedOne[0] == x && checkedOne[1] == y) {
add = false;
break;
}
}
if(!add) {
return;
}
int[] point = new int[] {x,y};
checked.put(point, flag);
checks.add(point);
if(point[0] == end[0] && point[1] == end[1]) {
finish = true;
}
}
/**
* 增加检测点
* @param map
*/
public void addChecks(int[][] map) {
int[] point = path.getLast();
int x = point[0]; //x
int y = point[1]; //y
addCheck(x-1, y-1, map);
addCheck(x-1, y, map);
addCheck(x-1, y+1, map);
addCheck(x,