A*寻路算法总体来说还是比较简单和高效的,这里对在项目中的使用记录下,源码如下
设计一个二维数组类ArrayList.ts
/** * Autor: Created by 李清风 on 2020-11-17. * Desc: ArrayList */ export class ArrayList { private _list: [any[]]; private _row;//矩阵行 private _colums;//矩阵列 public constructor(rows: number, colums: number, defalut: any = 0) { this._list = [[]]; this._row = rows; this._colums = colums; this.initRows(rows); this.initColumns(colums, defalut); } //初始化数组行 initRows(rows: number) { if (rows < 1) { return; } for (let i = 0; i < this._row; i++) { let item:any[] = []; this._list.push(item); } } //初始化数组列 initColumns(columns: number, value: any) { if (columns < 1) { return; } for (let i = 0; i < this._list.length; i++) { for (let j = 0; j < columns; j++) { this._list[i].push(value) } } } getValue(rows: number, colums: number) { if (rows < 0 || colums < 0 || rows >= this._row || colums >= this._colums) { console.error("IndexOutOfRangeException: Index was outside the bounds of the array.") return null; } return this._list[rows][colums]; } setValue(rows: number, colums: number, value) { if (rows < 0 || colums < 0 || rows >= this._row || colums >= this._colums) { console.error("IndexOutOfRangeException: Index was outside the bounds of the array.") return; } this._list[rows][colums] = value; } getArrayList(): Array<Array<any>> { return this._list; } }
设计一个优先级队列PriorityQueue.ts
import { GridNode } from "./GridNode";
/**
* Autor: Created by 李清风 on 2020-11-17.
* Desc: PriorityQueue
*/
export class PriorityQueue {
private nodes: GridNode[] = [];
public Length() {
return this.nodes.length;
}
public Contains(node: GridNode) {
return this.nodes.includes(node);
}
public First(): GridNode {
if (this.nodes.length > 0) {
return this.nodes[0];
}
return null;
}
public Add(node: GridNode) {
this.nodes.push(node);
this.sort();
}
public Remove(node: GridNode) {
let index = this.nodes.indexOf(node);
if (index > -1) {
this.nodes.splice(index, 1);
}
this.sort();
}
private sort() {
let sortCallFunc = (a, b) => {
if (a.estimatedCost < b.estimatedCost) {
return -1;
}
if (a.estimatedCost > b.estimatedCost) {
return 1;
}
return 0;
}
this.nodes.sort(sortCallFunc)
}
}
设计一个节点格子类GridNode.ts
/** * Autor: Created by 李清风 on 2020-11-17. * Desc: GridNode */ export class GridNode { public nodeTotalCost: number; public estimatedCost: number; public bObstacle: boolean; public parent: GridNode; public position: cc.Vec2; //矩阵行列式,也可代表x,y轴 public constructor() { this.estimatedCost = 0; this.nodeTotalCost = 1; this.bObstacle = false; this.parent = null; } public initWithPos(pos: cc.Vec2) { this.estimatedCost = 0; this.nodeTotalCost = 1; this.bObstacle = false; this.parent = null; this.position = pos; } public MarkAsObstacle() { this.bObstacle = true; } }
设计管理格子的管理类GridManager.ts
import { ArrayList } from "./ArrayList";
import { GridNode } from "./GridNode";
/**
* Autor: Created by 李清风 on 2020-11-17.
* Desc: 地图网格化管理器
*/
export class GridManager {
private static _instance: GridManager;
public static getInstance(): GridManager {
if (GridManager._instance == null) {
GridManager._instance = new GridManager();
}
return GridManager._instance;
}
public numOfRows: number; //行数
public numOfColumns: number;//列数
public girdCellSize: number;
public showGrid: boolean;
nodes: ArrayList;
public obstacleList: any[];
public init(row: number, column: number, mapData: any) {
if (!mapData) {
console.error(‘地图数据加载失败‘);
return;
}
this.numOfRows = row; // 53 (0,52)
this.numOfColumns = column; //45(0-44)
this.CalcuateGirdNodes(mapData);
}
/**
* 初始化网格da
* @param mapData json数据
* @param 注:网格是严格按照x,y对应来进行初始化的,但是遍历map需要额外处理下
*/
public CalcuateGirdNodes(mapData: any) {
this.nodes = new ArrayList(this.numOfRows, this.numOfColumns);
for (let i = 0; i < this.numOfColumns; i++) {
for (let j = 0; j < this.numOfRows; j++) {
let node: GridNode = new GridNode();
node.initWithPos(cc.v2(j, i))
//BlockType.disable 自己设计的标签,不可行走
//BlockType.occlusion 障碍物
//BlockType.Basket 其他
if (mapData[i][j] == BlockType.disable || mapData[i][j] == BlockType.occlusion ||
mapData[i][j] == BlockType.Basket) {
node.MarkAsObstacle();
}
this.nodes.setValue(j, i, node);
}
}
}
private GetRow(pos: cc.Vec2) {
let row = pos.x
return row;
}
private GetColumn(pos: cc.Vec2) {
let colums = pos.y;
return colums;
}
private GetGridNodeByRowColumn(row: number, column: number) {
return this.nodes.getArrayList()[row][column];
}
/**
* 取8个点
* @param node
* @param neighbors
*/
public GetNeighbours(node: GridNode, neighbors: GridNode[]) {
let neighborPos: cc.Vec2 = node.position;
let row = this.GetRow(neighborPos); // 26
let colum = this.GetColumn(neighborPos); //20
//左
let leftNodeRow = row - 2;
let leftNodeColum = colum;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//右
leftNodeRow = row + 2;
leftNodeColum = colum;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//上
leftNodeRow = row;
leftNodeColum = colum + 1;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//下
leftNodeRow = row;
leftNodeColum = colum - 1;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//左上
leftNodeRow = row - 1;
leftNodeColum = colum;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//右上
leftNodeRow = row + 1;
leftNodeColum = colum;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//左下
leftNodeRow = row - 1;
leftNodeColum = colum - 1;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
//右下
leftNodeRow = row + 1;
leftNodeColum = colum - 1;
this.AssignNeighbour(leftNodeRow, leftNodeColum, neighbors);
}
private AssignNeighbour(row: number, colum: number, neighbors: GridNode[]) {
if (row != -1 && colum != -1 && row < this.numOfRows && colum < this.numOfColumns) {
let nodeToAdd: GridNode = this.GetGridNodeByRowColumn(row, colum);
if (!nodeToAdd.bObstacle) {
neighbors.push(nodeToAdd);
}
}
}
}
设计核心的脚本AStar.ts
/** * Autor: Created by 李清风 on 2020-11-17. * Desc: A* */ import { GridManager } from "./GridManager"; import { GridNode } from "./GridNode"; import { PriorityQueue } from "./PriorityQueue"; export class AStar { private static openList: PriorityQueue; private static closeList: PriorityQueue; private static NodeCost(a: GridNode, b: GridNode): number { let vecCost: cc.Vec2 = a.position.sub(b.position); return vecCost.mag(); } public static FindPath(start: GridNode, goal: GridNode): any { AStar.openList = new PriorityQueue(); AStar.openList.Add(start); AStar.closeList = new PriorityQueue(); start.nodeTotalCost = 0; start.estimatedCost = AStar.NodeCost(start, goal); let node: GridNode = null; while (AStar.openList.Length() != 0) { node = AStar.openList.First(); if ((node.position.x == goal.position.x) && (node.position.y == goal.position.y)) { return AStar.CalculatePath(node); } let neighbours: GridNode[] = []; GridManager.getInstance().GetNeighbours(node, neighbours); for (let i = 0; i < neighbours.length; i++) { let neighbourNode: GridNode = neighbours[i]; if (!AStar.closeList.Contains(neighbourNode)) { let cost: number = AStar.NodeCost(node, neighbourNode); let totalCost = node.nodeTotalCost + cost; let neighbourNodeEstCost = AStar.NodeCost(neighbourNode, goal); neighbourNode.nodeTotalCost = totalCost; neighbourNode.estimatedCost = totalCost + neighbourNodeEstCost; neighbourNode.parent = node; if (!AStar.openList.Contains(neighbourNode)) { AStar.openList.Add(neighbourNode); } } } AStar.closeList.Add(node); AStar.openList.Remove(node); } if ((node.position.x == goal.position.x) && (node.position.y == goal.position.y)) { console.error("Arrived Goal Path Not Found"); return null; } return AStar.CalculatePath(node); } private static CalculatePath(node: GridNode): any { let list: GridNode[] = []; while (node != null) { list.push(node); node = node.parent; } list.reverse(); return list; } }
原文:https://www.cnblogs.com/makeamericagreatagain/p/14310283.html