zoukankan      html  css  js  c++  java
  • 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;
    }

    }

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

    //简单优化了一波

  • 相关阅读:
    window C/C++ 简单的IDE编译器
    ubuntu 安装 lamp
    架构设计
    linux 性能分析
    wifi基本原理
    openwrt 编译
    学习笔记day5:inline inline-block block区别
    脱离原来文档流产生浮动框
    meta标签清理缓存
    百度web前端面试2015.10.18
  • 原文地址:https://www.cnblogs.com/jiajunjie/p/9519804.html
Copyright © 2011-2022 走看看