【游戏跨场景寻路】基于egret(白鹭)的游戏地图跨场景寻路功能的实现

2024-08-27 03:58

本文主要是介绍【游戏跨场景寻路】基于egret(白鹭)的游戏地图跨场景寻路功能的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

每次时间久了算法就会淡忘,温故耗时,故做下整理,方便日后取材。

参考网址:

        原理性讲解:https://www.toutiao.com/a6540828594954830340/ 

        基于as3的代码:https://blog.csdn.net/sjt223857130/article/details/77199601

        堆优化理解:https://www.cnblogs.com/jason2003/p/7222182.html

        基于C++的代码:https://blog.csdn.net/qq_35644234/article/details/60870719

        相关注释:https://www.cnblogs.com/zzzPark/p/6060780.html

        代码参考:https://blog.csdn.net/u013052238/article/details/80273042

此文主要讲跨地图间的最短路径,AI 寻路参考 A* 算法:https://blog.csdn.net/u013052238/article/details/53375860,以及A*算法的优化:https://blog.csdn.net/u013052238/article/details/78126019

 

一、以下图作为多地图顶点:

二、地图数据字典配置简要设置如下:

{"A": {"B": {"len": 6},"C": {"len": 3}},"B": {"A": {"len": 6},"C": {"len": 2},"D": {"len": 5}},"C": {"A": {"len": 3},"B": {"len": 2},"D": {"len": 3},"E": {"len": 4}},"D": {"B": {"len": 5},"C": {"len": 3},"E": {"len": 2},"F": {"len": 3}},"E": {"C": {"len": 4},"D": {"len": 2},"F": {"len": 5}},"F": {"D": {"len": 3},"E": {"len": 5}}
}

三、为地图设置Vo类,这里简单设置MapVo类,带有mapId属性(如上的A~F顶点)


/**顶点地图数据 */
class MapVo {public mapID: string = "";
}

四、新建地图数据类存储对应矩阵的相关数据,这里设置MGraph(邻接矩阵)类:

/**邻接矩阵 */
class MGraph {/**邻接矩阵数组 */public edgeMatrixList: number[][];/**顶点数 */public pointNumber: number;/**存放顶点信息 */public mapDataList: MapVo[];public constructor() {this.edgeMatrixList = [];this.mapDataList = [];this.pointNumber = 0;}
}

五、新建类CrossMap初始化地图数据:

class CrossMap {/**地图配置表数据 */private gMapSource: any;/**INFINITY: 无穷大 */private INFINITY: number = 999999;/**邻接矩阵数据 */private gMGraph: MGraph;public constructor(mapSourcelist: any) {this.gMapSource = mapSourcelist;this.gMGraph = new MGraph();this.gMGraph.pointNumber = Object.keys(this.gMapSource).length;for (let point in this.gMapSource) {let _mapVo: MapVo = new MapVo();this.gMGraph.mapDataList.push(_mapVo);_mapVo.mapID = point;}//建立图的邻接矩阵for (let i: number = 0; i < this.gMGraph.pointNumber; i++) {if (!this.gMGraph.edgeMatrixList[i]) {this.gMGraph.edgeMatrixList[i] = [];}for (let j: number = 0; j < this.gMGraph.pointNumber; j++) {//计算i到j的权值let mapI: string = this.gMGraph.mapDataList[i].mapID;let mapJ: string = this.gMGraph.mapDataList[j].mapID;if (this.gMapSource[mapI]) {if (this.gMapSource[mapI][mapJ]) {				//判断地图I到地图J能不能走通this.gMGraph.edgeMatrixList[i][j] = this.gMapSource[mapI][mapJ].len;//权值设为配置// this.gMGraph.edgeMatrixList[i][j] = 1;	//默认给权值都为1continue;}}this.gMGraph.edgeMatrixList[i][j] = this.INFINITY;}}console.log("图的邻接矩阵为:", this.gMGraph.edgeMatrixList);/**导出路径数据 */this.exportPath();}/**保存搜索完后所有相关的路径字典 */private allPathDic: { [mapId: string]: string[] } = {};private exportPath(){......}
}

获得地图的邻接矩阵数据如下:

六、开始迪杰斯特拉算法查找各个点距离其他点的最短路径:

/**保存所有路径字典 */private allPathDic: { [mapId: string]: string[] } = {};private exportPath() {let time = egret.getTimer();let pointNum: number = this.gMGraph.pointNumber;for (let i: number = 0; i < pointNum; i++) {this.dijkstra(i, this.gMGraph);}console.log("跨地图数据生成耗时:" + (egret.getTimer() - time) + "ms");}private dijkstra(sourcePoint: number, _MGraph: MGraph) {let dist: number[] = [];					//从原点sourcePoint到其他的各定点当前的最短路径长度let path: number[] = [];					//path[i]表示从原点到定点i之间最短路径的前驱节点let selectList: number[] = [];  			//选定的顶点的集合let minDistance, point = 0;for (let i = 0; i < _MGraph.pointNumber; i++) {dist[i] = _MGraph.edgeMatrixList[sourcePoint][i];       		//距离初始化selectList[i] = 0;                        						//selectList[]置空  0 表示 i 不在selectList集合中if (_MGraph.edgeMatrixList[sourcePoint][i] < this.INFINITY) {   //路径初始化path[i] = sourcePoint;} else {path[i] = -1;}}selectList[sourcePoint] = 1;                  				//原点编号sourcePoint放入selectList中path[sourcePoint] = 0;for (let i = 0; i < _MGraph.pointNumber; i++) {             //循环直到所有顶点的最短路径都求出minDistance = this.INFINITY;                    		//minDistance置最小长度初值for (let j = 0; j < _MGraph.pointNumber; j++)        	//选取不在selectList中且具有最小距离的顶点pointif (selectList[j] == 0 && dist[j] < minDistance) {point = j;minDistance = dist[j];}selectList[point] = 1;                       		 	//顶点point加入selectList中for (let j = 0; j < _MGraph.pointNumber; j++)        	//修改不在selectList中的顶点的距离if (selectList[j] == 0)if (_MGraph.edgeMatrixList[point][j] < this.INFINITY && dist[point] + _MGraph.edgeMatrixList[point][j] < dist[j]) {dist[j] = dist[point] + _MGraph.edgeMatrixList[point][j];path[j] = point;}}this.putBothpath(_MGraph, dist, path, selectList, _MGraph.pointNumber, sourcePoint);//获取路径}private putBothpath(_MGraph: MGraph, dist: number[], path: number[], selectList: number[], pointNumber: number, sourcePoint: number) {for (let i = 0; i < pointNumber; i++) {if (selectList[i] == 1 && dist[i] < this.INFINITY) {/**路径点列表 */let pathVexsList: string[] = [];pathVexsList.push(_MGraph.mapDataList[sourcePoint].mapID);	//起点this.findPath(_MGraph, path, i, sourcePoint, pathVexsList);pathVexsList.push(_MGraph.mapDataList[i].mapID);			//终点/**测试 */let pathStr: string = "";for (let j: number = 0; j < pathVexsList.length; j++) {pathStr += pathVexsList[j];if (j != pathVexsList.length - 1) {						//不是结尾就加间隔符pathStr += "-";}}/**测试 */let _pathKey: string = _MGraph.mapDataList[sourcePoint].mapID + "-" + _MGraph.mapDataList[i].mapID;if (!this.allPathDic[_pathKey]) {							//不存在this.allPathDic[_pathKey] = pathVexsList;}console.log("从 " + _MGraph.mapDataList[sourcePoint].mapID + " 到 " + _MGraph.mapDataList[i].mapID + " 的最短路径长度为: " + dist[i] + "\t 路径为: " + pathStr);}else {console.log('从 ' + _MGraph.mapDataList[sourcePoint].mapID + ' 到 ' + _MGraph.mapDataList[i].mapID + ' 不存在路径      ');}}}private findPath(_MGraph: MGraph, path: number[], i: number, sourcePoint: number, pathVexsList: string[]) {  //前向递归查找路径上的顶点let point;point = path[i];if (point == sourcePoint) return;    								//找到了起点则返回this.findPath(_MGraph, path, point, sourcePoint, pathVexsList);    	//找顶点point的前一个顶点sourcePointpathVexsList.push(_MGraph.mapDataList[point].mapID);}

查找得到路径存如下:

从 A 到 A 不存在路径           
从 A 到 B 的最短路径长度为: 5	 路径为: A-C-B     
从 A 到 C 的最短路径长度为: 3	 路径为: A-C     
从 A 到 D 的最短路径长度为: 6	 路径为: A-C-D     
从 A 到 E 的最短路径长度为: 7	 路径为: A-C-E     
从 A 到 F 的最短路径长度为: 9	 路径为: A-C-D-F从 B 到 A 的最短路径长度为: 5	 路径为: B-C-A     
从 B 到 B 不存在路径           
从 B 到 C 的最短路径长度为: 2	 路径为: B-C     
从 B 到 D 的最短路径长度为: 5	 路径为: B-D     
从 B 到 E 的最短路径长度为: 6	 路径为: B-C-E     
从 B 到 F 的最短路径长度为: 8	 路径为: B-D-F 从 C 到 A 的最短路径长度为: 3	 路径为: C-A     
从 C 到 B 的最短路径长度为: 2	 路径为: C-B     
从 C 到 C 不存在路径           
从 C 到 D 的最短路径长度为: 3	 路径为: C-D     
从 C 到 E 的最短路径长度为: 4	 路径为: C-E     
从 C 到 F 的最短路径长度为: 6	 路径为: C-D-F 从 D 到 A 的最短路径长度为: 6	 路径为: D-C-A     
从 D 到 B 的最短路径长度为: 5	 路径为: D-B     
从 D 到 C 的最短路径长度为: 3	 路径为: D-C     
从 D 到 D 不存在路径           
从 D 到 E 的最短路径长度为: 2	 路径为: D-E     
从 D 到 F 的最短路径长度为: 3	 路径为: D-F  从 E 到 A 的最短路径长度为: 7	 路径为: E-C-A     
从 E 到 B 的最短路径长度为: 6	 路径为: E-C-B     
从 E 到 C 的最短路径长度为: 4	 路径为: E-C     
从 E 到 D 的最短路径长度为: 2	 路径为: E-D     
从 E 到 E 不存在路径           
从 E 到 F 的最短路径长度为: 5	 路径为: E-F  从 F 到 A 的最短路径长度为: 9	 路径为: F-D-C-A     
从 F 到 B 的最短路径长度为: 8	 路径为: F-D-B     
从 F 到 C 的最短路径长度为: 6	 路径为: F-D-C     
从 F 到 D 的最短路径长度为: 3	 路径为: F-D     
从 F 到 E 的最短路径长度为: 5	 路径为: F-E     
从 F 到 F 不存在路径

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于【游戏跨场景寻路】基于egret(白鹭)的游戏地图跨场景寻路功能的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1110566

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P