AStarHelper.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * @Author: gyw
  3. * @Date: 2019-09-09
  4. * @Desc: A*寻路
  5. * tilemap专用
  6. */
  7. export class AStarHelper {
  8. //其中的MAP.arr是二维数组
  9. public static searchRoad(map: cc.TiledLayer, start_x: number, start_y: number, end_x: number, end_y: number, colliderTiles?: any[]) {
  10. if (start_x == end_x && start_y == end_y) return null;
  11. let layerSize = map.getLayerSize();
  12. let rows = layerSize.width; //行
  13. let cols = layerSize.height; //列
  14. // let rows = PathMgr.getInstance().mapJson.length; //行
  15. // let cols = PathMgr.getInstance().mapJson[0].length; //列
  16. var openList = [], //开启列表
  17. closeList = [], //关闭列表
  18. result = [], //结果数组
  19. result_index; //结果数组在开启列表中的序号
  20. openList.push({ x: start_x, y: start_y, G: 0 });//把当前点加入到开启列表中,并且G是0
  21. do {
  22. var currentPoint = openList.pop();
  23. closeList.push(currentPoint);
  24. // if (Math.abs(currentPoint.x - start_x) > 10 || Math.abs(currentPoint.y - start_y) > 10) continue;
  25. var surroundPoint = this.SurroundPoint(currentPoint);
  26. for (var i in surroundPoint) {
  27. var item = surroundPoint[i]; //获得周围的八个点
  28. if (
  29. item.x >= 0 && //判断是否在地图上
  30. item.y >= 0 &&
  31. item.x < rows &&
  32. item.y < cols &&
  33. (this.checkCell(map, item.x, item.y) == 0 || this.checkCell(map, item.x, item.y) == 65) && //判断是否是障碍物 0代表是空位
  34. this.existList(item, closeList) == -100 //判断是否在关闭列表中
  35. && (!colliderTiles || !colliderTiles[item.x] || !colliderTiles[item.x][item.y])
  36. ) {
  37. //g 到父节点的位置
  38. //如果是上下左右位置的则g等于10,斜对角的就是14
  39. var g = currentPoint.G + ((currentPoint.x - item.x) * (currentPoint.y - item.y) == 0 ? 10 : 14);
  40. if (this.existList(item, openList) == -100) { //如果不在开启列表中
  41. //计算H,通过水平和垂直距离进行确定
  42. item['H'] = Math.abs(end_x - item.x) * 10 + Math.abs(end_y - item.y) * 10;
  43. item['G'] = g;
  44. item['F'] = item['H'] + item['G'];
  45. item['parent'] = currentPoint;
  46. openList.push(item);
  47. }
  48. else { //存在在开启列表中,比较目前的g值和之前的g的大小
  49. var index = this.existList(item, openList);
  50. //如果当前点的g更小
  51. if (g < openList[index].G) {
  52. openList[index].parent = currentPoint;
  53. openList[index].G = g;
  54. openList[index].F = g + openList[index].H;
  55. }
  56. }
  57. }
  58. }
  59. //如果开启列表空了,没有通路,结果为空
  60. if (openList.length == 0) {
  61. break;
  62. }
  63. openList.sort(this.sortF);//这一步是为了循环回去的时候,找出 F 值最小的, 将它从 "开启列表" 中移掉
  64. } while ((result_index = this.existList({ x: end_x, y: end_y }, openList)) == -100);
  65. //判断结果列表是否为空
  66. if (result_index == -100 || result_index == void 0) {
  67. result = [];
  68. }
  69. else {
  70. var currentObj = openList[result_index];
  71. do {
  72. //把路劲节点添加到result当中
  73. result.unshift({
  74. x: currentObj.x,
  75. y: currentObj.y
  76. });
  77. currentObj = currentObj.parent;
  78. } while (currentObj.x != start_x || currentObj.y != start_y);
  79. }
  80. return result;
  81. }
  82. //用F值对数组排序
  83. private static sortF(a, b) {
  84. return b.F - a.F;
  85. }
  86. //获取周围八个点的值
  87. public static SurroundPoint(curPoint) {
  88. var x = curPoint.x, y = curPoint.y;
  89. return [
  90. { x: x - 1, y: y - 1 },
  91. { x: x, y: y - 1 },
  92. { x: x + 1, y: y - 1 },
  93. { x: x + 1, y: y },
  94. { x: x + 1, y: y + 1 },
  95. { x: x, y: y + 1 },
  96. { x: x - 1, y: y + 1 },
  97. { x: x - 1, y: y }
  98. ]
  99. }
  100. //判断点是否存在在列表中,是的话返回的是序列号
  101. private static existList(point, list) {
  102. for (var i in list) {
  103. if (point.x == list[i].x && point.y == list[i].y) {
  104. return i;
  105. }
  106. }
  107. return -100;
  108. }
  109. //检测单元格是否是障碍物
  110. public static checkCell(mapLayer: cc.TiledLayer, x: number, y: number) {
  111. let res = mapLayer.getTileGIDAt(x, y);
  112. // let res = PathMgr.getInstance().mapJson[x][y];
  113. return res;
  114. }
  115. }