egret 简单的四方向的a星寻路,在wing中可以直接跑

/**

* main类中加载场景
* 创建游戏场景
* Create a game scene
*/
private createGameScene() {
MtwGame.Instance.init(this.stage);
}

/**

*-----------------------------------------场景类--------------------------------

*/

class MtwGame {

public constructor() {
}
private static _instance: MtwGame;

public static get Instance(): MtwGame {
if (this._instance == null || this._instance == undefined) {
this._instance = new MtwGame();
}
return this._instance;
}

public stage: egret.Stage;
// X ↓; Y →
public mapTitle: Array<Array<number>>;
//障碍
public mapObstacle: Array<Array<number>> = [

[1, 4], [2, 4], [3, 4], [4, 4], [5, 4], [6, 4], [7, 4], [8, 4],
[9, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4],//[15, 4],

[12, 3],
[12, 2],

[2, 8], [3, 8], [4, 8], [5, 8], [6, 8], [7, 8], [8, 8],
[9, 8], [10, 8], [11, 8], [12, 8], [13, 8], [14, 8], [15, 8],

[1, 12], [2, 12], [3, 12], [4, 12], [5, 12], [6, 12], [7, 12], [8, 12],
[9, 12], [10, 12], [11, 12], [12, 12], [13, 12], [14, 12], //[15, 12],

[2, 14], [3, 14], [4, 14], [5, 14], [6, 14], [7, 14], //[8, 14],
[9, 14], [10, 14], [11, 14], [12, 14], [13, 14], [14, 14], [15, 14],
];
public path: Array<Array<number>>;
public number = 20;
public strokeWid: number = 3;
public color1: number = 0x00000;//线和阻挡的颜色
public color2: number = 0xe60b0b;//路径的颜色
// public color3: number = 0x00000;

public showTxt: eui.Label;
public showTxt2: eui.Label;
public x1: eui.EditableText;
public y1: eui.EditableText;
public x2: eui.EditableText;
public y2: eui.EditableText;
pathRect = [];//用于存储路径方块,便于管理
map: aStar;

//初始化舞台
public init(stage: egret.Stage): void {
this.stage = stage;
this.initMap(17, 17);//输入地图的长宽(格子个数)
this.initmenu();
this.initBlock();
this.findPath(2, 2, 15, 15);
}
/**初始化菜单*/
protected initmenu(): void {
let shp: egret.Shape = new egret.Shape();
shp.graphics.beginFill(0xffffff, 1);
shp.graphics.drawRect(0, 0, this.stage.stageWidth, this.stage.stageHeight);
shp.graphics.endFill();
this.stage.addChild(shp);

this.x1 = new eui.EditableText();
this.stage.addChild(this.x1);
this.x1.text = "请输入x1";
this.x1.y = 700;

this.y1 = new eui.EditableText();
this.stage.addChild(this.y1);
this.y1.text = "请输入y1";
this.y1.y = 740;

this.x2 = new eui.EditableText();
this.stage.addChild(this.x2);
this.x2.text = "请输入x2";
this.x2.y = 780;

this.y2 = new eui.EditableText();
this.stage.addChild(this.y2);
this.y2.text = "请输入y2";
this.y2.y = 820;

this.x1.x = this.y1.x = this.x2.x = this.y2.x = 30;
this.x1.textColor = this.y1.textColor = this.x2.textColor = this.y2.textColor = 0x0;
this.x1.size = this.y1.size = this.x2.size = this.y2.size = 22;

this.showTxt = new eui.Label();
this.stage.addChild(this.showTxt);

this.showTxt2 = new eui.Label();
this.stage.addChild(this.showTxt2);
this.showTxt2.text = "重新生成路径";
this.showTxt.size = 24
this.showTxt2.size = 32;
this.showTxt.textAlign = this.showTxt2.textAlign = "center";
this.showTxt.fontFamily = this.showTxt2.fontFamily = "SimHei";
this.showTxt.textColor = this.showTxt2.textColor = 0xf3c382;
this.showTxt.strokeColor = this.showTxt2.strokeColor = 0x0;
this.showTxt.stroke = this.showTxt2.stroke = 1;
this.showTxt.width = this.showTxt2.width = Math.floor(this.stage.stageWidth / 3 * 2);
this.showTxt.x = this.showTxt2.x = this.stage.stageWidth - this.showTxt.width >> 1;
this.showTxt2.y = 680;
this.showTxt2.addEventListener(egret.TouchEvent.TOUCH_END, this.touchHandler, this);
}
/**重新寻路*/
protected touchHandler(evt: egret.TouchEvent): void {
if (Number(this.x1.text) && Number(this.y1.text) && Number(this.x2.text) && Number(this.y2.text)) {
this.showTxt.text = "";
if (this.tt > 0)
clearInterval(this.tt);
this.findPath(Number(this.x1.text), Number(this.y1.text), Number(this.x2.text), Number(this.y2.text));
} else {
this.showTxt.text = "请重新选择起点和终点";
}

}
/**开始寻路*/
protected findPath(x1: number, y1: number, x2: number, y2: number): void {

let returns = this.map.getPath(x1, y1, x2, y2);//输入起点和终点(2,2),(5,5)
if (typeof returns == "string") {
this.path = null;
this.showTxt.text = returns + ",请重新选择起点和终点";
} else {
this.path = returns;
}
this.showTxt.y = this.stage.stageHeight - 250 - this.showTxt.height;
//显示路径
this.initPath();
}
/**渲染地图*/
protected initBlock(): void {
//横
for (let i = 0; i < this.mapTitle.length + 1; i++) {
let y = i * (this.width + this.strokeWid);
this.setLine(0, y, this.stage.stageWidth, y)
}
//竖
for (let i = 0; i < this.mapTitle[0].length + 1; i++) {
let x = i * (this.width + this.strokeWid);
let height = this.width * this.mapTitle[0].length + this.strokeWid * (this.mapTitle[0].length + 1)
this.setLine(x, 0, x, height)
}
//阻挡点
for (let i = 0; i < this.mapTitle.length; i++) {
for (let j = 0; j < this.mapTitle[i].length; j++) {
if (this.mapTitle[i][j] == 1) {
this.setRect(this.strokeWid * (j + 1) + this.width * j, this.strokeWid * (i + 1) + this.width * i, this.color1, 0.8)
}
}
}
}
tt;
/**
* 将路径显示在地图上
*/
protected initPath(): void {
if (this.pathRect.length > 0) {
for (let i = 0; i < this.pathRect.length; i++) {
this.stage.removeChild(this.pathRect[i]);
}
this.pathRect = [];
}
if (this.path && this.path.length > 0) {
let i = 0;
this.tt = setInterval(() => {
if (!this.path[i]) {
clearInterval(this.tt);
return;
}
let x = this.strokeWid * (this.path[i][1] + 1) + this.width * this.path[i][1];
let y = this.strokeWid * (this.path[i][0] + 1) + this.width * this.path[i][0];
this.setRect(x, y, this.color2, 0.3, true);
i++;
}, 50);
}

// for (let i = 0; i < this.path.length; i++) {
// let x = this.strokeWid * (this.path[i][1] + 1) + this.width * this.path[i][1];
// let y = this.strokeWid * (this.path[i][0] + 1) + this.width * this.path[i][0];
// this.setRect(x, y, this.color2, 0.3, true)
// }
}

/**
* 初始化地图
* */
protected initMap(w: number, h: number): void {
if (w < 2 || h < 2) console.error("地图格子长宽数不对");
this.mapTitle = [];
for (let i = 0; i < h; i++) {
this.mapTitle.push([]);
for (let j = 0; j < w; j++) {
if (i == 0 || j == 0 || i == h - 1 || j == w - 1) {
this.mapTitle[i][j] = 1;
} else {
this.mapTitle[i][j] = 0;
}
}
}
this.width = (this.stage.stageWidth - (this.mapTitle[0].length + 1) * this.strokeWid) / this.mapTitle[0].length;
this.map = new aStar(this.mapTitle);
this.initObstacle();
for (let i in this.mapObstacle) {
this.map.update(this.mapObstacle[i][0], this.mapObstacle[i][1], true)
}
}
/**
* 将障碍显示在地图上
* */
protected initObstacle(): void {
for (let i = 0; i < this.mapObstacle.length; i++) {
if (this.mapObstacle[i][0] < this.mapTitle.length - 1 && this.mapObstacle[i][0] > 0
&& this.mapObstacle[i][1] < this.mapTitle[0].length - 1 && this.mapObstacle[i][1] > 0)
this.mapTitle[this.mapObstacle[i][0]][this.mapObstacle[i][1]] = 1;
}
}

//划线
public setLine(x: number, y: number, x1: number, y1: number): egret.Shape {
var shp: egret.Shape = new egret.Shape();
shp.graphics.lineStyle(this.strokeWid, this.color1);
shp.graphics.moveTo(x, y);
shp.graphics.lineTo(x1, y1);
shp.graphics.endFill();
this.stage.addChild(shp);
return shp;
}
//划块
protected setRect(x: number, y: number, col: number, alpha: number = 1, bool: boolean = false): egret.Shape {
var shp: egret.Shape = new egret.Shape();
shp.graphics.beginFill(col, alpha);
shp.graphics.drawRect(x, y, this.width, this.width);
shp.graphics.endFill();
this.stage.addChild(shp);
if (bool) {
this.pathRect.push(shp);
}
return shp;
}


//每次显示器的宽高变化时,重新渲染
protected onResizeHandler(e: egret.Event): void {
if (this.showTxt) this.showTxt.x = this.stage.stageWidth - this.showTxt.width >> 1;
if (this.showTxt) this.showTxt.y = this.stage.stageHeight - 50 - this.showTxt.height;
}
}

/**

*----------------------------------------------------------寻路--------------------------------------------------------------------

*/

//F:G和H的和,一般走最小值//G:A到该方块的距离//H:该方块到B的最近距离(不管有没有障碍物)
class aStar {
public closeArr: { [pos: string]: number };//不能走的格子
public openArr: { [pos: string]: Array<number> };//可以走的格子
public Arr: { [pos: string]: number };//所有的格子
openObj;//记录所有用过的格子的信息,用于最后找到终点后的寻路

public constructor(mapArr: Array<Array<number>>) {
this.Arr = {};
for (let i = 0; i < mapArr.length; i++) {
for (let j = 0; j < mapArr.length; j++) {
this.Arr[i + "_" + j] = mapArr[i][j];
}
}
}
/**
* 获得最短路径;
* x1,y1是起点;x2,y2是终点
*/
public getPath(x1: number, y1: number, x2: number, y2: number): any {
this.closeArr = {};
this.openObj = {};
this.openArr = {}
this.openArr[x1+"_"+y1] = [x1, y1, 0];//x,y,G
let curP = [];
let count = 0;//循环次数
let fourP;
let lastFNum:string = "";
if (this.Arr[x1 + "_" + y1] == 1 || this.Arr[x2 + "_" + y2] == 1) {
return "起点和终点不能是障碍物";
}
if (x1 ==x2 &&y2 == y1) {
return "起点和终点不能是同一个点";
}
if (this.Arr[x1 + "_" + y1] == null || this.Arr[x2 + "_" + y2] == null) {
return "起点和终点只能选中图中的格子";
}
let startTime: number = egret.getTimer();
for (; ;) {
lastFNum = this.getLastFNum(x2, y2);
curP = this.openArr[lastFNum];
count++;
if (curP[0] == x2 && curP[1] == y2) {
//生成路径
let ab = [[x2, y2]];
for (let i = 0; i < Object.keys(this.openObj).length; i++) {
let infor = this.openObj[ab[ab.length - 1][0] + "_" + ab[ab.length - 1][1]];
if (!infor) {//没有父节点的就是起点
console.log("找到最短的路了,终点是(" + x2 + "," + y2 + "),需要走" + ab.length + "步", "主循环" + count + "次");
console.log("计算所用时间:" + (egret.getTimer() - startTime));
return ab.reverse();
}
ab.push([infor[3], infor[4]]);
}
return ab.reverse();
}
//将格子加到close,并从open中删除
this.closeArr[curP[0] + "_" + curP[1]] = 1;
delete this.openArr[lastFNum];

fourP = this.getfour(curP[0], curP[1], curP[2])//获取四个方向的格子
if (fourP && fourP.length > 0) {
for (let i = 0; i < fourP.length; i++) {
let names:string = fourP[i][0]+"_"+fourP[i][1];
if(!this.openArr[names])
this.openArr[names] = fourP[i];
else{
//记录G小的数据
this.openArr[names] = fourP[i][2]<this.openArr[names][2]?fourP[i]:this.openArr[names];
}
}
}
this.getPointInfor();
if (Object.keys(this.openArr).length==0) {
console.log("死路一条", "主循环" + count + "次");
console.log("计算所用时间:" + (egret.getTimer() - startTime));
return "死路一条";
}
}
}

/**
* 获得估计路径长度;不管障碍物;
* x1,y1是起点;x2,y2是终点
*/
public getLastPath(x1: number, y1: number, x2: number, y2: number): number {
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
}
/**
* 获得f最小的格子;
*
*/
public getLastFNum(x2: number, y2: number): string {
let lastf: number;
let g: number;
let h: number;
let name:string;
for (let i in this.openArr) {
g = this.openArr[i][2];
h = this.getLastPath(this.openArr[i][0], this.openArr[i][1], x2, y2);
if (!lastf) {
lastf = g + h;
name = i;
} else {
if (g + h < lastf) {
lastf = g + h;
name = i;
}
}
}
return name;
}
/**
* 所有用过的点的信息
* 同时去重
*/
public getPointInfor(): void {
let point = [];
let newOpenArr = [];
for (let i in this.openArr) {
point = this.openArr[i];
if (!this.openObj[i])//新的点
this.openObj[i] = point;
else {
if (point[2] < this.openObj[i][2]) {
this.openObj[i] = point;
}
}
}
}
//获得四个方向的格子[x,y,]
public getfour(x1: number, y1: number, g: number): any {
let siGe = [];
let i = g + 1;
let str1: string = x1 + 1 + "_" + y1;
let str2: string = x1 - 1 + "_" + y1;
let str3: string = x1 + "_" + (y1 + 1);
let str4: string = x1 + "_" + (y1 - 1);
if (this.Arr[str1] == 0 && !this.closeArr[str1])
siGe.push([x1 + 1, y1, i, x1, y1]);
if (this.Arr[str2] == 0 && !this.closeArr[str2])
siGe.push([x1 - 1, y1, i, x1, y1]);
if (this.Arr[str3] == 0 && !this.closeArr[str3])
siGe.push([x1, y1 + 1, i, x1, y1]);
if (this.Arr[str4] == 0 && !this.closeArr[str4])
siGe.push([x1, y1 - 1, i, x1, y1]);
//八方向的格子
// let str5: string = x1 + 1 + "_" + (y1 + 1);
// let str6: string = x1 + 1 + "_" + (y1 - 1);
// let str7: string = x1 - 1 + "_" + (y1 + 1);
// let str8: string = x1 - 1 + "_" + (y1 - 1);
// if (this.Arr[str5] == 0 && !this.closeArr[str5])
// siGe.push([x1 + 1, y1 + 1, i, x1, y1]);
// if (this.Arr[str6] == 0 && !this.closeArr[str6])
// siGe.push([x1 + 1, y1 - 1, i, x1, y1]);
// if (this.Arr[str7] == 0 && !this.closeArr[str7])
// siGe.push([x1 - 1, y1 + 1, i, x1, y1]);
// if (this.Arr[str8] == 0 && !this.closeArr[str8])
// siGe.push([x1 - 1, y1 - 1, i, x1, y1]);
return siGe;
}

/**更新地图的阻挡物 */
public update(x1: number, y1: number, bool: boolean): void {
this.Arr[x1 + "_" + y1] = bool ? 1 : 0;
}

public dispose(): void {
this.closeArr = null;
this.openArr = null;
this.Arr = null;
this.openObj = null;
}

}

//代码还有很多可以优化,但怕忘记,先存到这里

//简单优化了一波

原文地址:https://www.cnblogs.com/jiajunjie/p/9519804.html