unity使用Dijkstra算法实现自动寻路

前言

最近开始做新的功能模块——章节关卡。在做的过程中看到一个要求:根据当前关卡位置,点击任意已开放的关卡,主角自动寻路至该处。

数据准备

关卡配置表如下:

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
    
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱上游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值