A*寻路算法(纯lua),看到有同学分享了,我这里也跟上一个吧

我这里分享一个,这个也是纯lua实现的,可以用作前期测试,后期基于效率考虑,可以改用C++来导出接口即可
先看张效果图吧

这里直接贴上寻路算法的代码,基本注释都有,这里默认采用4方向处理,具体的可以参考下面的demo

--
        A*寻路算法,目前只适用于 01图, 0可通行, 1不可通行
--]]

-- 行走的4个方向
local four_dir = {
        {1, 0},
        {0, 1},
        {0, -1},
        {-1, 0},
}

-- 行走的8个方向
local eight_dir = {
        {1, 1},
        {1, 0},
        {1, -1},
        {0, 1},
        {0, -1},
        {-1, 1},
        {-1, 0},
        {-1, -1}
}

local AStar = {}

-- 地图、起始点、终点
AStar.init = function(self, map, startPoint, endPoint, four_dir)
        self.startPoint = startPoint
        self.endPoint   = endPoint
        self.map        = map
        self.cost       = 10 -- 单位花费
        self.diag       = 1.4 -- 对角线长, 根号2 一位小数
        self.open_list  = {}
        self.close_list = {}
        self.mapRows    = #map
        self.mapCols    = #map
        self.four_dir   = four_dir -- 使用4方向的寻路还是八方向的寻路
end

-- 搜索路径 ,核心代码
AStar.searchPath = function(self)
        -- 验证终点是否为阻挡,如果为阻挡,则直接返回空路径
        if self.map ~= 0 then
                Logger.info("(", self.endPoint.row, ",", self.endPoint.col, ") 是阻挡!!!无法寻路")
                return nil
        end

        -- 把第一节点加入 open_list中
        local startNode = {}  
        startNode.row = self.startPoint.row
        startNode.col = self.startPoint.col
        startNode.g = 0
        startNode.h = 0
        startNode.f = 0
        table.insert(self.open_list, startNode)
        
        -- 检查边界、障碍点 
        local check = function(row, col)
                if 1 <= row and row <= self.mapRows and 1 <= col and col <= self.mapCols then
                        if self.map == 0 or (row == self.endPoint.row and col == self.endPoint.col) then
                                return true
                        end
                end

                return false
        end

        local dir = self.four_dir and four_dir or eight_dir
        while #self.open_list > 0 do
                local node = self:getMinNode()
                if node.row == self.endPoint.row and node.col == self.endPoint.col then
                        -- 找到路径
                        return self:buildPath(node)
                end

                for i = 1, #dir do
                        local row = node.row + dir*
                        local col = node.col + dir*
                        if check(row, col) then
                                local curNode = self:getFGH(node, row, col, (row ~= node.row and col ~= node.col))
                                local openNode, openIndex = self:nodeInOpenList(row, col)
                                local closeNode, closeIndex = self:nodeInCloseList(row, col)

                                if not openNode and not closeNode then
                                        -- 不在OPEN表和CLOSE表中
                                        -- 添加特定节点到 open list
                                        table.insert(self.open_list, curNode)
                                elseif openNode then
                                        -- 在OPEN表
                                        if openNode.f > curNode.f then
                                                -- 更新OPEN表中的估价值
                                                self.open_list = curNode
                                        end
                                else
                                        -- 在CLOSE表中
                                        if closeNode.f > curNode.f then
                                                table.insert(self.open_list, curNode)
                                                table.remove(self.close_list, closeIndex)
                                        end
                                end
                        end
                end

                -- 节点放入到 close list 里面
                table.insert(self.close_list, node)
        end

        -- 不存在路径
        return nil 
end

-- 获取 f ,g ,h, 最后参数是否对角线走
AStar.getFGH = function(self, father, row, col, isdiag)
        local node = {}
        local cost = self.cost
        if isdiag then
                cost = cost * self.diag
        end

        node.father = father
        node.row = row
        node.col = col
        node.g = father.g + cost
        -- 估计值h
        if self.four_dir then
                node.h = self:manhattan(row, col)
        else
                node.h = self:diagonal(row, col)
        end
        node.f = node.g + node.h  -- f = g + h 
        return node
end

-- 判断节点是否已经存在 open list 里面
AStar.nodeInOpenList = function(self, row, col)
        for i = 1, #self.open_list do
                local node = self.open_list*
                if node.row == row and node.col == col then
                        return node, i   -- 返回节点和下标
                end
        end

        return nil
end

-- 判断节点是否已经存在 close list 里面
AStar.nodeInCloseList = function(self, row, col)
        for i = 1, #self.close_list do
                local node = self.close_list*
                if node.row == row and node.col == col then
                        return node, i
                end
        end

        return nil
end

-- 在open_list中找到最佳点,并删除
AStar.getMinNode = function(self)
        if #self.open_list < 1 then
                return nil
        end

        local min_node = self.open_list
        local min_i = 1
        for i,v in ipairs(self.open_list) do
                if min_node.f > v.f then
                        min_node = v
                        min_i = i
                end
        end

        table.remove(self.open_list, min_i)
        return min_node
end

-- 计算路径
AStar.buildPath = function(self, node)
        local path = {}
        local sumCost = node.f -- 路径的总花费
        while node do
                path#path + 1] = {row = node.row, col = node.col}
                node = node.father
        end

        return path, sumCost
end

-- 估价h函数
-- 曼哈顿估价法(用于不能对角行走)
AStar.manhattan = function(self, row, col)  
        local h = math.abs(row - self.endPoint.row) + math.abs(col - self.endPoint.col)
        return h * self.cost
end

-- 对角线估价法,先按对角线走,一直走到与终点水平或垂直平行后,再笔直的走
AStar.diagonal = function(self, row, col)
        local dx = math.abs(row - self.endPoint.row)
        local dy = math.abs(col - self.endPoint.col)
        local minD = math.min(dx, dy)
        local h = minD * self.diag + dx + dy - 2 * minD
        return h * self.cost
end

return AStar


```


这里可以直接用quick-cocos2dx-3.3final创建一个空白工程,然后用下面的src.zip去覆盖就好了
 src.rar (5 KB) ****
4赞

https://github.com/Yonaba/Jumper

1赞

比我的分享好多了

这个封装的 挺好 伸手党

先mark到,后面用到再说