本帖最后由 隔壁老吕 于 2021-2-16 18:36 编辑
虽然说寻路算法在一般插件开发中很少用,但是因为某些客户奇奇怪怪的要求不得不研究了这个东西,
顺便与大家分享一下。
一.寻路算法的种类
比较适合MC这类开放地图的寻路算法是A*,BFS,Dijkstra
A*兼具高速度与较高的准确性,所以本文会主要讲A*算法
二.开始寻路之旅
A*算法的始祖是Dijkstra
Dijkstra算法的实质就是不断向四周搜索,
向四周搜索的具体方法是维护
复制代码首先,g表示离出发点的距离
1.将开始节点put入open
2.循环获取离初始节点最近并且未到达的节点#getMinGNode()
3.判断该节点是否为终点(终点直接跳出循环输出结果)
否则从open中remove该节点(HashMap的作用在此体现,快速删除减少时间损耗)
并且将该节点存入close中(表示已经到达过这个节点)
4.随后获取该节点四周的节点,即为子节点判断close中是否存在(HashSet快速判断)
5.接下来是非常重要的一步,更新子节点
如果这个子节点已经到达过了(判断open中是否存在这个节点的Block)
若该节点到子节点比过去的路径更近,就需要更新子节点实现最短路径
否则直接将节点存入open复制代码
三.从Dijkstra进入A*
Dijkstra算法是由起点向四周发散搜索,浪费了大量的时间搜索没有必要的节点,
那么就需要为他指明道路,于是,A*算法诞生了
由Dijkstra进入A*很简单。
在“二”中已经提到,g定义了由当前节点到初始节点的距离,
于是再定义h为当前节点到终节点的理论距离,这里用曼哈顿路径处理
定义f=h+g,表示理论上这条路径的距离
随后将"2.循环获取离初始节点..."修改成获取理论路径最小的节点#getMinFNode()
曼哈顿距离
复制代码
此外就是获取四周子节点时连通性的判断,在样例插件中已经提供了我写的样本当然,也欢迎大佬来优化
到此,A*算法就完成了附参考插件样本以及源代码:
src.rar
(5.98 KB, 下载次数: 8)
Pathfinder.jar
(23 KB, 下载次数: 5)
插件使用:
/pf astar x y z 对从玩家所处点向该点A*寻路
/pf dijks x y z 对从玩家所处点向该点Dijkstra寻路
/pf bfs x y z 对从玩家所处点向该点BFS寻路
虽然说寻路算法在一般插件开发中很少用,但是因为某些客户奇奇怪怪的要求不得不研究了这个东西,
顺便与大家分享一下。
一.寻路算法的种类
比较适合MC这类开放地图的寻路算法是A*,BFS,Dijkstra
A*兼具高速度与较高的准确性,所以本文会主要讲A*算法
二.开始寻路之旅
A*算法的始祖是Dijkstra
Dijkstra算法的实质就是不断向四周搜索,
向四周搜索的具体方法是维护
- HashMap<Block, Node> open;
- HashSet<Node> close;
1.将开始节点put入open
2.循环获取离初始节点最近并且未到达的节点#getMinGNode()
3.判断该节点是否为终点(终点直接跳出循环输出结果)
否则从open中remove该节点(HashMap的作用在此体现,快速删除减少时间损耗)
并且将该节点存入close中(表示已经到达过这个节点)
4.随后获取该节点四周的节点,即为子节点判断close中是否存在(HashSet快速判断)
5.接下来是非常重要的一步,更新子节点
如果这个子节点已经到达过了(判断open中是否存在这个节点的Block)
若该节点到子节点比过去的路径更近,就需要更新子节点实现最短路径
否则直接将节点存入open
- Node start = new Node(begin, 0, BlockUtil.getDistance(begin, target), null);
- open.put(start.block, start);
- while (!open.isEmpty()) {
- Node n = getMinGNode();
- if (n.equals(target)) {
- result = n;
- //完成
- break;
- } else {
- open.remove(n.block);
- close.add(n);
- for (Node m : n.getNextNodes(target)) {
- if (!close.contains(m)) {
- if (open.containsKey(m.block)) {
- open.get(m.block).update(m);
- } else {
- open.put(m.block, m);
- }
- }
- }
- }
- }
三.从Dijkstra进入A*
Dijkstra算法是由起点向四周发散搜索,浪费了大量的时间搜索没有必要的节点,
那么就需要为他指明道路,于是,A*算法诞生了
由Dijkstra进入A*很简单。
在“二”中已经提到,g定义了由当前节点到初始节点的距离,
于是再定义h为当前节点到终节点的理论距离,这里用曼哈顿路径处理
定义f=h+g,表示理论上这条路径的距离
随后将"2.循环获取离初始节点..."修改成获取理论路径最小的节点#getMinFNode()
曼哈顿距离
- public static double getDistance(Location begin, Location target) {
- int x1 = begin.getBlockX();
- int y1 = begin.getBlockY();
- int z1 = begin.getBlockZ();
- int x2 = target.getBlockX();
- int y2 = target.getBlockY();
- int z2 = target.getBlockZ();
- return Math.abs(x1 - x2) + Math.abs(y1 - y2) + Math.abs(z1 - z2);
- }
此外就是获取四周子节点时连通性的判断,在样例插件中已经提供了我写的样本当然,也欢迎大佬来优化
到此,A*算法就完成了附参考插件样本以及源代码:


插件使用:
/pf astar x y z 对从玩家所处点向该点A*寻路
/pf dijks x y z 对从玩家所处点向该点Dijkstra寻路
/pf bfs x y z 对从玩家所处点向该点BFS寻路
最喜欢dijkstra了~~~
A*我记得是依赖于估值的
A*我记得是依赖于估值的
不过使用堆优化Dijkstra算法的话其时间复杂度可以从O(n^2)降到O(nlogn)的,实际上还是挺快的
dengyu 发表于 2021-2-16 18:33
不过使用堆优化Dijkstra算法的话其时间复杂度可以从O(n^2)降到O(nlogn)的,实际上还是挺快的 ...
Dijkstra用在mc地图里就和广搜差不多了,效率较低
另外那几句争议性的话先去掉了,尚待考证