A* (AStar) 寻路

//调用工具类获取路线

let route = AStarSearch.getRoute(start_point, end_point, this.mapFloor.map_point);

map_point 是所有可走点的集合

TypeScript 复制代码
import { _decorator, Component, Node, Prefab, instantiate, v3, Vec2 } from 'cc';
import { oops } from "../../../../../extensions/oops-plugin-framework/assets/core/Oops";
import { GameWorld } from "../../../GameWorld";
import { MapFloor, RowColData } from "../../../../Scripts/MapEditor/MapFloor";

export class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
    G: number = 0;   //G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。
    H: number = 0;   //H = 从网格上那个方格移动到终点B的预估移动耗费
    F: number = 0;   //F = G + H
    father: Point = null;   //这个点的上一个点,通过回溯可以找到起点 
    is_close: boolean = false;   //是否关闭搜索
}

export class AStarSearch {

    static start: Point = null;      //起点
    static end: Point = null;        //终点
    static map: Map<string, Point> = null;   //地图point

    static openSet: Set<Point> = new Set();  //开放队列

    static pppp: Point = null;       //执行完寻路,它就有值了,除非没找到

    /**
     * 获取路线 (此寻路不走斜线)
     */
    static getRoute(start: Point, end: Point, map_point: Map<string, { row: number, col: number }>): Point[] {
        //清空上次寻路,并赋值
        this.is_find = false;
        this.openSet.clear();
        this.pppp = null;
        this.start = { ...start };
        this.end = { ...end };
        this.map = new Map<string, Point>();
        map_point.forEach((value, key) => {
            let point = new Point(value.row, value.col);
            this.map.set(key, point);
        });

        let route = new Array<Point>();
        let keyStr = this.start.x + "_" + this.start.y;
        if (!this.map.has(keyStr)) {
            return route;
        }
        this.map.get(keyStr).G = 0;       //起点的G是0
        //开始寻路
        try {
            this.search(this.start);     //内存不够会报错,一般是起点或终点封闭
        } catch (error) {
            console.warn("位置不对", error);
            return route;
        }
        if (this.pppp) {
            this.getFather(this.pppp, route);
        }
        return route;
    }

    /**
     * 寻路
     */
    static is_find = false;    //是否已经找到路线
    static search(point: Point) {
        if (point.x == this.end.x && point.y == this.end.y) {
            this.is_find = true;
            this.pppp = point;
            return;
        }
        let arr = this.getAround(point);
        arr.forEach(p => {
            this.setFather(p, point);
        });
        //arr按照F排序 从小到大
        this.openSet = new Set([...this.openSet].sort(this.compare));
        //递归继续找
        this.openSet.forEach((pp, index, arr) => {
            if (pp.is_close) {        //删除没用的
                this.openSet.delete(pp);
            }
            if (!this.is_find) {
                this.search(pp);
            }
        });
    }

    /**
     * 获取周围4个点,上下左右
     */
    static getAround(point: Point) {
        point.is_close = true;
        let arr = new Array<Point>();
        let index: string;
        let p: Point;

        //上、下、左、右
        let aroundPos = [
            { x: point.x, y: point.y - 1 },
            { x: point.x, y: point.y + 1 },
            { x: point.x - 1, y: point.y },
            { x: point.x + 1, y: point.y }
        ]
        aroundPos.forEach(point => {
            index = point.x + "_" + point.y;
            p = this.map.get(index);
            if (p && !p.is_close) {
                arr.push(p);
                this.openSet.add(p);
            }
        })
        return arr;
    }

    /**
     * point换父亲,并重新计算G、H、F
     */
    static setFather(son: Point, father: Point) {
        if (!son.father || son.father.G > father.G) {
            son.father = father;
            son.G = son.father.G + 1;
            son.H = Math.abs(son.x - this.end.x) + Math.abs(son.y - this.end.y);
            son.F = son.G + son.H;
        }
    }

    /**
     * 比较器
     */
    static compare(p1: Point, p2: Point) {
        if (p1.F > p2.F) {
            return 1;
        } else {
            return -1;
        }
    }

    /**
     * 递归 把祖宗放进route里面
     */
    static getFather(point: Point, route: Array<Point>) {
        let father = point.father;
        if (father) {
            this.getFather(father, route);
        }
        route.push(point);
    }
}
相关推荐
流影ng1 天前
【HarmonyOS】并发线程间的通信
typescript·harmonyos
duansamve1 天前
TS在Vue3中的使用实例集合
typescript·vue3
应用市场2 天前
无人机编队飞行原理与Python仿真实现完整指南
python·无人机·cocos2d
FanetheDivine2 天前
ts中如何描述一个复杂函数的类型
前端·typescript
云卓SKYDROID2 天前
无人机中继器模式技术对比
人工智能·游戏引擎·php·无人机·cocos2d·高科技·云卓科技
struggle20253 天前
AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
css·人工智能·typescript·go·shell·powershell
执剑、天涯3 天前
通过一个typescript的小游戏,使用单元测试实战(二)
javascript·typescript·单元测试
chéng ௹3 天前
Vue3+Ts+Element Plus 权限菜单控制节点
前端·javascript·vue.js·typescript
武清伯MVP4 天前
阮一峰《TypeScript 教程》学习笔记——基本用法
笔记·学习·typescript
ttod_qzstudio5 天前
解决 Vue 3 + TypeScript 中 v-for 循环类型推断问题
前端·vue.js·typescript