前言
最近开始做新的功能模块——章节关卡。在做的过程中看到一个要求:根据当前关卡位置,点击任意已开放的关卡,主角自动寻路至该处。
数据准备
关卡配置表如下:
map = {
[1] = {
coordinate = {
1, 1, }, link = {
2, 3, }, },
[2] = {
coordinate = {
2, 1, }, link = {
1, 3, }, },
[3] = {
coordinate = {
3, 2, }, link = {
4, 3, }, },
[4] = {
coordinate = {
8, 2, }, link = {
2, 3, }, },
[5] = {
coordinate = {
3, 3, }, link = {
2, 3, }, },
[6] = {
coordinate = {
5, 3, }, link = {
2, 3, }, },
[7] = {
coordinate = {
9, 3, }, link = {
2, 3, }, },
[8] = {
coordinate = {
2, 4, }, link = {
2, 3, }, },
}
map的key值代表第X关。
coordinate代表对应关卡的坐标位置,例如:{2,1}代表坐标位置为x=2,y=1。
link代表与之相连的关卡,{2,3}代表与关卡2和关卡3相连。(即表示有通路)
尝试1
看到自动寻路,第一反应就是AStar算法。毕竟自动寻路嘛,那肯定得是A了。上次使用A还是在上次…enen,还是几年前上学时候,当时也只是学习了该算法的思路伪代码。要说用到实践里,那就是一个鸡蛋了。加上这么长时间过去了,只问其名,却已忘记其身,不得不借助www:度娘,我来了~。
首先找一篇通俗易懂的文章,看看算法的思路吧,代码的事后面再说~
先说下这个算法:A*算法主要用于求最短路径。算法的主要思想是:
参考自:https://blog.csdn.net/Zhouzi_heng/article/details/115035298
(1) 把起点加入 open list 。
(2) 重复如下过程:
a. 遍历 open list ,查找 F 值最小的节点,把它作为当前要处理的节点。
b. 把这个节点移到 close list 。
c. 对当前方格的 8 个相邻方格的每一个方格?
◆ 如果它是不可抵达的或者它在 close list 中,忽略它。否则,做如下操作。
◆ 如果它不在 open list 中,把它加入 open list ,并且把当前方格设置为它的父亲,记录该方格的 F , G 和 H 值。
◆ 如果它已经在 open list 中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更好,用 G 值作参考。更小的 G 值表示这是更好的路径。如果是这样,把它的父亲设置为当前方格,并重新计算它 的 G 和 F 值。如果你的 open list 是按 F 值排序的话,改变后你可能需要重新排序。
d.停止,当你
◆把终点加入到了 open list 中,此时路径已经找到了,或者
◆查找终点失败,并且 open list 是空的,此时没有路径。
(3)保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。
详情可见:推荐一篇大佬的A*算法文章:https://blog.csdn.net/xinzhilinger/article/details/119643810
搞懂了算法的思想后,我们其实是不需要自己写代码的,因为网上已经有很多成功的案例了,我们只需要站在巨人的肩膀上操作,去使用它。找到一个A算法的脚本如下:
https://mp.csdn.net/mp_download/manage/download/UpDetailed
那么怎么去使用它呢?
由于A算法是在网格上寻路的,因此我们需要先创建地图网格,使用Star.New(),观察发现Astar.cs脚本发现,需要的参数是String该网格是由网格的长宽,以及每个位置的信息(是否能通过,1代表可通过0代表不可通过)构成的,类似于这样:
第一行的两个值分表达标地图网格的长宽,除去第一行后可以发现,剩下的是一个10*10的网格,每个格子上有一个数字(值为0或者1),代表是否可以通过。
那么,第一步,我们需要先将上面给我们的配置信息转换为对应的网格字段,方法如下:
--判断某个位置是路还是障碍物
local function CheckRoadOrBarrier(x,y)
for k,v in pairs(map) do
local coordinate = v.coordinate
if coordinate[1] == x and coordinate[2] == y then
return 1--是路
end
end
return 0--障碍物
end
local fu
nction CreateMapData()
--长宽
local width = 10
local heigth = 10
local map = string.format("%s,%s",width,heigth)
for i=1,heigth do
map = map.."\n"
for j=1,width do
if j == 1 then
map = string.format("%s%s",map,CheckRoadOrBarrier(i,j))
else
map = string.format("%s,%s",map,CheckRoadOrBarrier(i,j))
end
end
end
printlog(map,"生成的地图信息????")
return map
end
网格数据转换好后,我们需要开始初始化Astar算法:
local function InitAStar()
current = AStarPoint.New(0,0)--默认初始位置在(0,0)坐标点
local map = CreateMapData()
astar = AStar.New(map)
astar:SetMapWidthAndHeigth(10, 10)
end
接下来,是时候展现我们真正的技术了:我们开始真正使用Astar算法了。
local function GetShortPath(_x,_y,_finishfunc)
local _next = AStarPoint.New(_x,_y)
local path = astar:FindPath(current, _next)
if path == nil or path.Count == 0 then
_finishfunc(false)
return