123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import { Size, TiledMap, UITransform, v3, Vec2 } from "cc";
- import { BinaryHeap } from "./BinaryHeap";
- export namespace AStar {
- //寻路方向
- export enum Type {
- error = 0,
- four, //4个方向
- eight, //8个方向
- }
- //寻路节点
- export class Node {
- x: number = 0;
- y: number = 0;
- f: number = 0; //总消耗
- g: number = 0; //起点到当前点的消耗
- h: number = 0; //当前点到终点的距离
- close: boolean = false; //是否被访问过
- prev: Node = null; //该节点的上个节点
- idx: number = 0; //在地图中的下标
- open: boolean = false; //是否是在开放列表中
- constructor(x: number, y: number, idx: number) {
- this.x = x;
- this.y = y;
- this.idx = idx;
- }
- clear() {
- this.f = this.g = this.h = 0;
- this.open = this.close = false;
- this.prev = null;
- }
- }
- const oblique_cost = 1.25; //斜走消耗
- const straight_cost = 1; //直走消耗
- export class Path {
- private _node_list = new Map<number, Node>(); //节点列表
- private _found_node: Node = null; //找到的节点(递归用)
- private _map_size: Size = null; //地图尺寸
- private _tile_size: Size = null; //地图块尺寸
- private _start_node = new Node(0, 0, 0); //起点节点
- private _end_node = new Node(0, 0, 0); //终点节点
- private _path_type = Type.four; //寻路方向
- private _find_path: Node[] = []; //路径列表(tiledmap坐标)
- private _min_heap = new BinaryHeap<Node>((node: Node) => { return node.f });//开放列表二叉堆
- private _tiled_map: TiledMap = null;
- /**
- * 寻路初始化函数
- * @param nodes 地图数据(只包含可走的节点)
- * @param map 地图
- * @param type 寻路方向
- */
- constructor(nodes: Map<number, Node>, map: TiledMap, type: Type = Type.four) {
- this._node_list = nodes;
- this._tiled_map = map;
- this._map_size = this._tiled_map.getMapSize();
- this._tile_size = this._tiled_map.getTileSize();
- this._path_type = type;
- }
- /**
- * 搜索路径
- * @param start 起点(tiledmap坐标)
- * @param end 终点(tiledmap坐标)
- */
- async search(start: Vec2, end: Vec2): Promise<Node[]> {
- //清理路径节点
- this._node_list.forEach((value) => {
- value.clear();
- });
- //清理列表
- this._min_heap.clear();
- this._find_path = [];
- this._start_node.x = start.x;
- this._start_node.y = start.y;
- this._start_node.idx = this._start_node.x + this._start_node.y * this._map_size.width;
- this._start_node.clear();
- this._end_node.x = end.x;
- this._end_node.y = end.y;
- this._end_node.idx = this._end_node.x + this._end_node.y * this._map_size.width;
- this._end_node.clear();
- //开始寻路
- this._search(this._start_node);
- //删除起点
- this._find_path.shift();
- return this._find_path;
- }
- private _search(start: Node) {
- if (start.x == this._end_node.x && start.y == this._end_node.y) {
- this._found_node = start;
- this._getPrev(this._found_node);
- return true;
- }
- this._getRoundNodes(start);
- let node = this._min_heap.root();
- (node) && this._search(node);
- }
- //依次获取上个节点
- private _getPrev(node: Node) {
- if (node.prev) this._getPrev(node.prev);
- this._find_path.push(node);
- }
- //获取周围的节点
- private _getRoundNodes(current: Node) {
- current.close = true;
- current.open = false;
- //四个方向
- //上
- if (current.y != 0) {
- this._addToHeap(current.idx - this._map_size.width, current, straight_cost);
- }
- //右
- if (current.x != this._map_size.width - 1) {
- this._addToHeap(current.idx + 1, current, straight_cost);
- }
- //下
- if (current.y != this._map_size.height - 1) {
- this._addToHeap(current.idx + this._map_size.width, current, straight_cost);
- }
- //左
- if (current.x != 0) {
- this._addToHeap(current.idx - 1, current, straight_cost);
- }
- if (this._path_type == Type.eight) {
- //右上
- if (current.y != 0 && current.x != this._map_size.width - 1) {
- this._addToHeap(current.idx - this._map_size.width + 1, current, oblique_cost);
- }
- //右下
- if (current.x != this._map_size.width - 1 && current.y != this._map_size.height - 1) {
- this._addToHeap(current.idx + this._map_size.width + 1, current, oblique_cost);
- }
- //左下
- if (current.x != 0 && current.y != this._map_size.height - 1) {
- this._addToHeap(current.idx + this._map_size.width - 1, current, oblique_cost);
- }
- //左上
- if (current.x != 0 && current.y != 0) {
- this._addToHeap(current.idx - this._map_size.width - 1, current, oblique_cost);
- }
- }
- }
- private _addToHeap(idx: number, current: Node, cost: number) {
- let node = this._node_list.get(idx);
- if (node && !node.close) {
- //如果在开放列表中则从表中移除
- (node.open) && this._min_heap.remove(node);
- //更新权重
- node.prev = current;
- node.g = current.g + cost;
- node.h = Math.abs(node.x - this._end_node.x) + Math.abs(node.y - this._end_node.y);
- node.f = node.g + node.h;
- node.open = true;
- this._min_heap.insert(node);
- }
- }
- }
- }
|