客户端地图内寻路总结与优化

首先关于客户端的坐标体系:

菱形框是客户端使用的单位方格,也就是游戏里雷达显示的坐标。客户端中采用的等距视角,使用菱形方格能与平面的场景地图模拟出3D效果。红色矩形框则是客户端和服务端公用的坐标格。

寻路方法入口: bool StartFindPath(CPos start, CPos end, vector<Cvector2f>& path, int IgnoreSteps, int nRatio, bool bAnyDir, int nMaxStep)

(下面讲解具体的寻路实现时涉及到A*寻路和Dijkstra最短路算法的知识点,这里就不对这两者做详细介绍了。)

start和end寻路的起点和终点,均为像素点。path为引用参数,用于存储寻路结果。IgnoreSteps为忽略距离终点的格数,即离终点还有几格时即可停下。nMaxSteps是最大寻路步数,用于限制使用A*算法寻路时的超时时间。

寻路成功返回true,将线路的“拐点集”(即相邻两点间是可以直线连通没有障碍的,且任意非相邻的两点是不能直线连通的)存储在path中。否则返回false。

StartFindPath的寻路过程:

  1.先用LinePath()检验起点与终点是否可以直线连通:

    (1)LinePath需保证起点在场景内;终点参数在场景外则直接返回起点坐标。

    (2)然后由起点和重点坐标得出直线方向,以最小单位(即上面说的菱形格)遍历从起点至终点的所有格判断是否有高障碍(高障碍一般为地形,人物角色和怪物一般为低障碍),成功返回true;否则返回遇到的第一个障碍格。

  2.若直线寻路没有成功,接下来检查输入参数的起点和终点是否均不超过场景。

  3.进入A*寻路算法FindPath():

    (1)检查如果起点和终点相同则直接返回-1。

    (2)将起点添加进open list中。

    (3)循环执行下面操作直至open list为空找到终点节点 超出最大寻路步数

      I. 在open list中找到并移除总花费值最小的节点(总花费=G+H;G为从起点到该节点的花费;H为从该点到终点的估计花费。H这里采用的是“曼哈顿距离”来估计从该节点到终点的花费,公式为横纵坐标差值的和:H=abs(start.x-end.x)+abs(start.y-end.y) )。

      II. 在该处理节点的八个相邻方向上遍历,对于到达的新节点若没存入过open list则直接加入;否则检查由该处理节点到新节点的G是否更小,如果更小就更新其花费和前置节点;并重新调整open list的顺序。

实现该A*算法的过程中三个重要的数据结构:

    (1)     XPS_Node:存储位置节点的结构,包含了节点位置、G花费、H花费和到达该节点的前置节点等内容。

    (2)     XPS_Node** m_pOpenList:用数组实现的、以总花费做权值比较的最小堆。

    (3)     XPS_Node* m_aBacket:用于记录加入过open list的XPS_Node哈希表;用x、y坐标值计算哈希值;解决哈希冲突的方式是将哈希值相同的XPS_Node以链表结构存储在同一数组下标上。

  4.如果A*寻路没有成功,则进入下面的Dijkstra最短路算法:

    (1)     加载对应地图数据目录下的roadPoint.csv和pathlink.csv(这两个文件是在地图上预设好的各坐标顶点和相邻顶点间的距离),构建出Dijkstra算法需要的图。

    (2)     找到距离start和end最近的且能够与之直线连通的顶点。将该两个顶点作为Dijkstra图中的起点和终点。

    (3)     循环N次执行以下操作:

      I. 找出到达花费最小的节点node,并作标记 使下次查找时忽略该点。

      II. 对于所有与node节点相邻的顶点,检查由node到其相邻节点的到达花费是否更小( cost[node] + link[node][i] < cost[i] ),如果是则更新其到达花费,并将其前置节点置为node。

  5.若Dijkstra寻路未成功(没有csv文件或找不到与起/终直连的顶点等),则进行大范围A*寻路(这一步往往耗时就很严重了玩家会有明显的寻路延迟)。

  (如下示,虚线为起始点寻找能够直线连通的顶点;蓝色实线为Dijkstra得出的路径)

对寻路代码做的优化:

 

  1.对Dijkstra算法使用堆优化:

原先实现中,每次寻找最小花费的节点步骤中,是通过遍历一次所有节点得出的。可以用个最小堆来存储节点的到达花费,那么每次寻找最小花费节点的复杂度由O(N)降为O(logN)。 (我这里实现最小堆是直接用的std的优先队列priority_queue)。

  2.在使用Dijkstra算法寻路时,第一步是遍历图中的所有顶点中,找到能够与起点、终点位置直线连通的顶点。因为需要直线连通这一条件,因此在起/终点周围存在较多障碍格的时候很容易失效,而进入下面非常耗时的大范围A*寻路。因此将这一步改为:当直线连通失效时,则寻找与起/终点直线距离最近的若干顶点使用A*算法(超时步数限制在较小范围),来确定Dijkstra的图中起点和终点。

下面给出巨**谷地图(还是把具体地图名遮上吧 :D)上的一些测试结果:


起点


终点


原始耗时


优化后


(79,42)


(570,1097)


151ms


26ms


(17,1104)


(538,13)


114ms


32ms


(246,47)


(625,688)


97ms


23ms


(577,808)


(295,584)


31ms


29ms


(36,105)


(419,910)


39ms


39ms


(625,373)


(6,203)


28ms


27ms

上述优化有些限制,就是需要寻路地图要要有相应的csv地图,并且有数量可观的结点,否则起不到较好的优化效果。而且第一步的Dijkstra算法的堆优化的实际作用并不大,毕竟数据量有限。

原文地址:https://www.cnblogs.com/geek1116/p/12122074.html

时间: 2024-10-12 21:38:08

客户端地图内寻路总结与优化的相关文章

烂泥:openvpn双网卡客户端与内网机器通信

前段时间写了一篇有关openvpn搭建与内网机器通信的文章,那篇文章是基于服务器单网卡进行配置的,文章链接为<烂泥:openvpn tun模式下客户端与内网机器通信>. 这篇文章我们再来介绍下双网卡openvpn客户端与内网机器通信的配置. 一.需求说明 为什么要写openvpn双卡的配置? 是因为一般IDC机房都是提供多网卡服务器,同时目前比较流行的云服务器阿里云提供的也是双网卡,而腾讯云以及亚马逊的aws都是单网卡.各个云服务器商的网卡配置个数,如下图: 二.业务要求 现在IDC机房那边有

烂泥:openvpn tun模式下客户端与内网机器通信

本文由秀依林枫提供友情赞助,首发于烂泥行天下 前两篇文章我们介绍了有关openvpn的搭建与配置文件的讲解,这篇文章我们再聊介绍下,在tun模式下openvpn客户端如何与内网机器通信的问题. 一.实际问题 先来介绍下目前的基本情况,如下: 1.openvpn服务器单网卡,通过硬件防火墙把openvpn服务器的1194端口映射到公网. 2.openvpn服务器所在的网段为192.168.5.1/24网段 3.openvpn客户端获得IP地址为10.8.0.1/24网段 要求10.8.0.1/24

客户端地图拼图算法解析

概述:主要是阐述如何将瓦片地图图片拼接成完整地图的一些概念以及相关算法. 基本概念: 地图瓦片地址:http://mt2.google.cn/vt/[email protected]&hl=zh-CN&gl=cn&x=420&y=193&z=9&s=Galil 现在就是要将一张张这类的地图瓦片,在客户端拼接成一幅完整的地图. 瓦片大小为:256x256. url中关键参数解析: 参数 描述 mt2.google.cn Google瓦片服务服务器,可以尝试mt

Lucene.net站内搜索1——SEO优化简介

声明:在这里,所谈的一切关于SEO的技术主要针对于我们开发人员. SEO (搜索引擎优化) SEO(搜索引擎优化)的目的(很多人都是通过搜索引擎找到我们的网站)是让搜索引擎更多的收录网站的页面,让被收录页面的权重更靠前,让更多的人能够通过搜索引擎进入这个网站 原理:蜘蛛会定时抓取网站的内容,发现网站内容变化.发现新增内容就反映到搜索引擎中 蜘蛛(spider) 爬网站:就是向网站发http get请求的客户端. SEO(搜索引擎优化*):让网站排名靠前,让网站更多的页面被搜索引擎收录.链接(外链

HBase一次客户端读写异常解读分析与优化全过程(干货)

大数据时代,HBase作为一款扩展性极佳的分布式存储系统,越来越多地受到各种业务的青睐,以求在大数据存储的前提下实现高效的随机读写操作.对于业务方来讲,一方面关注HBase本身服务的读写性能,另一方面也需要更多地关注HBase客户端参数的具体意义.这篇文章就从一个具体的HBase客户端异常入手,定位异常发生的原因以及相应的客户端参数优化. 案发现场 最近某业务在使用HBase客户端读取数据时出现了大量线程block的情况,业务方保留了当时的线程堆栈信息,如下图所示: 看到这样的问题,首先从日志和

A*寻路算法的优化与改进

提要 通过对上一篇A*寻路算法的学习,我们对A*寻路应该有一定的了解了,但实际应用中,需要对算法进行一些改进和优化. Iterative Deepening Depth-first search- 迭代深化深度优先搜索 在深度优先搜索中一个比较坑爹情形就是在搜索树的一枝上没有要搜的结果,但是却非常深,甚至深不见底,这样就根本搜索不到结果.为了防止这种情况出现,就出现了Iterative Deepening的思想. 迭代深化搜索(Iterative deepening search, IDS)或者

百度地图内网开发包

离线地图资源,完全可脱离互联网访问,正在发愁局域网或内网使用地图定位的小伙伴们福音来了......哈哈哈哈哈!!! 支持各大主流浏览器 IE7.8.9.10.11,火狐.360浏览器.谷歌浏览器 点击下载视频介绍 离线资源包括百度API所用到的40多个js文件,已全部转化成本地资源调用! 提供瓦片图下载软件,能支持全国地图下载,大伙准备台80T的硬盘就能把全国地图搬回家啦,,哈哈哈!!!!!! 以下是测试中的截图 地图标注,点击标注弹出层 地图标注,点击标注弹出层 支持多层弹出显示,也支持每次只

根据Request获取客户端IP 内网IP及外网IP

在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr() ,这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了.如果使用了反向代理软件,将http://192.168.1.110:2046/ 的URL反向代理为http://www.xxx.com/ 的URL时,用request.getRemoteAddr() 方法获取的IP地址是:127.0.0.1 或 192.168.1.110 ,而并不是客户

客户端访问内网数据库

方法一:使用SecureCRT客户端工具 通过SecureCRT工具连接到中转服务器,并创建SSH Turnal . 1.在可以连接到中转服务器的session上选择新建PortForwarding. 2.随便起一个名字,在local上填写本地ip 127.0.0.1 端口填写一个没被使用的端口,Remote是要连接道的mysql服务器的主机和端口. 3.在window的客户端填写上面的local的主机IP和端口9987,用户名和密码是mysql授权的用户名和密码,上面的secure的到中转机的