AStar.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { Size, TiledMap, UITransform, v3, Vec2 } from "cc";
  2. import { BinaryHeap } from "./BinaryHeap";
  3. export namespace AStar {
  4. //寻路方向
  5. export enum Type {
  6. error = 0,
  7. four, //4个方向
  8. eight, //8个方向
  9. }
  10. //寻路节点
  11. export class Node {
  12. x: number = 0;
  13. y: number = 0;
  14. f: number = 0; //总消耗
  15. g: number = 0; //起点到当前点的消耗
  16. h: number = 0; //当前点到终点的距离
  17. close: boolean = false; //是否被访问过
  18. prev: Node = null; //该节点的上个节点
  19. idx: number = 0; //在地图中的下标
  20. open: boolean = false; //是否是在开放列表中
  21. constructor(x: number, y: number, idx: number) {
  22. this.x = x;
  23. this.y = y;
  24. this.idx = idx;
  25. }
  26. clear() {
  27. this.f = this.g = this.h = 0;
  28. this.open = this.close = false;
  29. this.prev = null;
  30. }
  31. }
  32. const oblique_cost = 1.25; //斜走消耗
  33. const straight_cost = 1; //直走消耗
  34. export class Path {
  35. private _node_list = new Map<number, Node>(); //节点列表
  36. private _found_node: Node = null; //找到的节点(递归用)
  37. private _map_size: Size = null; //地图尺寸
  38. private _tile_size: Size = null; //地图块尺寸
  39. private _start_node = new Node(0, 0, 0); //起点节点
  40. private _end_node = new Node(0, 0, 0); //终点节点
  41. private _path_type = Type.four; //寻路方向
  42. private _find_path: Node[] = []; //路径列表(tiledmap坐标)
  43. private _min_heap = new BinaryHeap<Node>((node: Node) => { return node.f });//开放列表二叉堆
  44. private _tiled_map: TiledMap = null;
  45. /**
  46. * 寻路初始化函数
  47. * @param nodes 地图数据(只包含可走的节点)
  48. * @param map 地图
  49. * @param type 寻路方向
  50. */
  51. constructor(nodes: Map<number, Node>, map: TiledMap, type: Type = Type.four) {
  52. this._node_list = nodes;
  53. this._tiled_map = map;
  54. this._map_size = this._tiled_map.getMapSize();
  55. this._tile_size = this._tiled_map.getTileSize();
  56. this._path_type = type;
  57. }
  58. /**
  59. * 搜索路径
  60. * @param start 起点(tiledmap坐标)
  61. * @param end 终点(tiledmap坐标)
  62. */
  63. async search(start: Vec2, end: Vec2): Promise<Node[]> {
  64. //清理路径节点
  65. this._node_list.forEach((value) => {
  66. value.clear();
  67. });
  68. //清理列表
  69. this._min_heap.clear();
  70. this._find_path = [];
  71. this._start_node.x = start.x;
  72. this._start_node.y = start.y;
  73. this._start_node.idx = this._start_node.x + this._start_node.y * this._map_size.width;
  74. this._start_node.clear();
  75. this._end_node.x = end.x;
  76. this._end_node.y = end.y;
  77. this._end_node.idx = this._end_node.x + this._end_node.y * this._map_size.width;
  78. this._end_node.clear();
  79. //开始寻路
  80. this._search(this._start_node);
  81. //删除起点
  82. this._find_path.shift();
  83. return this._find_path;
  84. }
  85. private _search(start: Node) {
  86. if (start.x == this._end_node.x && start.y == this._end_node.y) {
  87. this._found_node = start;
  88. this._getPrev(this._found_node);
  89. return true;
  90. }
  91. this._getRoundNodes(start);
  92. let node = this._min_heap.root();
  93. (node) && this._search(node);
  94. }
  95. //依次获取上个节点
  96. private _getPrev(node: Node) {
  97. if (node.prev) this._getPrev(node.prev);
  98. this._find_path.push(node);
  99. }
  100. //获取周围的节点
  101. private _getRoundNodes(current: Node) {
  102. current.close = true;
  103. current.open = false;
  104. //四个方向
  105. //上
  106. if (current.y != 0) {
  107. this._addToHeap(current.idx - this._map_size.width, current, straight_cost);
  108. }
  109. //右
  110. if (current.x != this._map_size.width - 1) {
  111. this._addToHeap(current.idx + 1, current, straight_cost);
  112. }
  113. //下
  114. if (current.y != this._map_size.height - 1) {
  115. this._addToHeap(current.idx + this._map_size.width, current, straight_cost);
  116. }
  117. //左
  118. if (current.x != 0) {
  119. this._addToHeap(current.idx - 1, current, straight_cost);
  120. }
  121. if (this._path_type == Type.eight) {
  122. //右上
  123. if (current.y != 0 && current.x != this._map_size.width - 1) {
  124. this._addToHeap(current.idx - this._map_size.width + 1, current, oblique_cost);
  125. }
  126. //右下
  127. if (current.x != this._map_size.width - 1 && current.y != this._map_size.height - 1) {
  128. this._addToHeap(current.idx + this._map_size.width + 1, current, oblique_cost);
  129. }
  130. //左下
  131. if (current.x != 0 && current.y != this._map_size.height - 1) {
  132. this._addToHeap(current.idx + this._map_size.width - 1, current, oblique_cost);
  133. }
  134. //左上
  135. if (current.x != 0 && current.y != 0) {
  136. this._addToHeap(current.idx - this._map_size.width - 1, current, oblique_cost);
  137. }
  138. }
  139. }
  140. private _addToHeap(idx: number, current: Node, cost: number) {
  141. let node = this._node_list.get(idx);
  142. if (node && !node.close) {
  143. //如果在开放列表中则从表中移除
  144. (node.open) && this._min_heap.remove(node);
  145. //更新权重
  146. node.prev = current;
  147. node.g = current.g + cost;
  148. node.h = Math.abs(node.x - this._end_node.x) + Math.abs(node.y - this._end_node.y);
  149. node.f = node.g + node.h;
  150. node.open = true;
  151. this._min_heap.insert(node);
  152. }
  153. }
  154. }
  155. }