zoukankan      html  css  js  c++  java
  • cocos2dx for lua A*寻路算法实现2

    关于A*算法的实现过程,简单来说就是一个计算权限的过程。

    首先,创建一个地图节点类,"MapNode.lua"

     local MapNode = class("MapNode")
     
    function MapNode:ctor()
        self._row = 0--
        self._col = 0--
        self._parent = nil--父节点
        self._f = 0--当前节点的总开销
        self._g = 0--当前节点的累计开销
        self._h = 0--启发因子
    end
    
    return MapNode

    "AStar.lua"逻辑实现

    local Direction = {}--方向
    Direction.Right = 0
    Direction.Right_Down = 1
    Direction.Down = 2
    Direction.Left_Down = 3
    Direction.Left = 4
    Direction.Left_Up = 5
    Direction.Up = 6
    Direction.Right_Up = 7
    
    local MapNode = require "app.views.MapNode"
    
    AStar = {}
    AStar.__index = AStar
    
    function AStar.create()
        local temp = {}
        setmetatable(temp, AStar)
        return temp
    end
    
    --mapData:二维数组,存放底图数据,0是可行走格子,1是有障碍格子
    function AStar:init(mapData)
        self._mapData = mapData--地图数据
        
        self._map = {}
        self._lPath = {}--收集的路径
        self._bFind = false
        
        local mapRow = #mapData
        local mapCol = #mapData[1]
    
        for i = 0, mapRow -1 do
            self._map[i] = {}
            for j = 0, mapCol -1 do
                local mapNode = MapNode.new()
                mapNode._row = i
                mapNode._col = j
                self._map[i][j] = mapNode
            end
        end
    end
    
    --开始寻路
    --from:开始格子位置(非坐标)
    --to:目标格子位置
    function AStar:getSearchPath(from, to)
        self:processAStar(from, to)--收集路径到_lPath
        return self._lPath
    end
    
    function AStar:canPass(row,col)--判断是否能够通过
        if self._mapData[col][row] == 0 then
            return true
        end
        return false
    end
     
    function AStar:getAdjacent(currentPos,dir)--根据方向获取相邻格子的位置
    if dir == Direction.Right then
            return cc.p(currentPos.x + 1,currentPos.y)
        elseif dir == Direction.Right_Down then
            return cc.p(currentPos.x + 1,currentPos.y - 1)
        elseif dir == Direction.Down then
            return cc.p(currentPos.x,currentPos.y - 1)
        elseif dir == Direction.Left_Down then
            return cc.p(currentPos.x - 1,currentPos.y - 1)
        elseif dir == Direction.Left then
            return cc.p(currentPos.x - 1,currentPos.y)
        elseif dir == Direction.Left_Up then
            return cc.p(currentPos.x - 1,currentPos.y + 1)
        elseif dir == Direction.Up then
            return cc.p(currentPos.x,currentPos.y + 1)
        elseif dir == Direction.Right_Up then
            return cc.p(currentPos.x + 1,currentPos.y + 1)
    end
    end
     
    function AStar:AStarCore(fromPos,toPos)--算法核心代码
        local open = {}
        local close = {}
        
        local targetNode = self._map[toPos.y][toPos.x]
        local fromNode = self._map[fromPos.y][fromPos.x]
        
        local f,g,h;
        fromNode._g = 0
        fromNode._h = math.abs(fromPos.x - toPos.x) +  math.abs(fromPos.y - toPos.y)
        fromNode._f = fromNode._h
        
        open[#open + 1] = fromNode
        while #open > 0 do
        local mapNode = open[1]
            table.remove(open,1)
        
        if mapNode._row == toPos.x and mapNode._col == toPos.y then
           return true
        end
        
        close[#close + 1]  = mapNode
        local parentPos = cc.p(mapNode._col,mapNode._row)
        local adjacentPos = nil
        local adjacentNode = nil
        
        for i = 0,7 do
                adjacentPos = self:getAdjacent(parentPos,i)
                if adjacentPos.x >= 0 and adjacentPos.x < mapCol and adjacentPos.y >= 0 and adjacentPos.y < mapRow then     
                    adjacentNode = self._map[adjacentPos.y][adjacentPos.x]
                    if self:canPass(adjacentPos.y,adjacentPos.x) == true and self:isContain(close,adjacentNode) == false and 
                        self:isContain(open,adjacentNode) == false then
                        if i % 2 == 0 then
                            g = adjacentNode._g + 1
                        else
                            g = adjacentNode._g + 1.4
                        end
                        h = math.abs(adjacentPos.x -toPos.x) + math.abs(adjacentPos.y - toPos.y)
                        f = g + h
                        
                        adjacentNode._parent = mapNode
                        adjacentNode._f = f
                        adjacentNode._g = g
                        adjacentNode._h = h
                        open[#open + 1] = adjacentNode
                    end
                end
        end
        table.sort(open,function(a,b)
           return a._f < b._f
        end)
        end
        return false
    end
     
    function AStar:processAStar(from,to)--执行A*算法
        local f = self:AStarCore(from,to)
        if f ==  true then
            self:collectRoute(from,to)
            return true
        end
        return false
    end
     
    function AStar:collectRoute(from, to)--收集路线
        self._lPath = {}
        local mapNode = self._map[to.y][to.x]
        self._lPath[#self._lPath + 1] = mapNode
        while mapNode._col ~= from.x or mapNode._row ~= from.y do
            mapNode = mapNode._parent
            self._lPath[#self._lPath + 1] = mapNode
        end
    end
     
    function AStar:isContain(tbl,cell) --在table中是否包含某个单元
        for k,v in pairs(tbl) do
            if tbl[k] == cell then
                return true
            end
        end
        return false
    end

    测试一下:

    TestScene.lua

    require "AStar.lua"
    local TestScene = class("TestScene",cc.load("mvc").ViewBase)
    
    function TestScene:ctor()
        local mapData = {
        {0, 0, 0, 0, 0, 0, 0, 0}
        {0, 0, 0, 0, 0, 0, 0, 0}
        {0, 0, 1, 1, 0, 0, 0, 0}
        {0, 0, 1, 0, 1, 0, 0, 0}
        {0, 0, 0, 1, 0, 1, 0, 0}
        {0, 0, 0, 0, 0, 0, 0, 0}
        {0, 0, 0, 0, 0, 0, 0, 0}
        {0, 0, 0, 0, 0, 0, 0, 0}
        }--地图数据
     
        self.mapData = mapData
        for i = 1, #mapData do--创建地图快图片
            for j = 1, #mapData[1] do
                local tileSp = cc.Sprite:create("tilemap.png")
                self:addChild(tileSp)
                tileSp:setPosition(i * tileWidth-(tileWidth * 0.5), j * tileHeight - (tileWidth * 0.5))
            end
        end
        
        local from = cc.p(0,0)--起点
        local to = cc.p(7,8)--目标点
        local sp1 = display.newSprite("qizi.png",to.x *tileWidth+(tileWidth*0.5),to.y *tileHeight+(tileWidth*0.5))--目标点图片
        self:addChild(sp1)
        
        local sp2 = display.newSprite("qizi.png",from.x *tileWidth+(tileWidth*0.5),from.y *tileHeight+(tileWidth*0.5))--起点图片
        self:addChild(sp2)
        
        self:setCollisionSp()
        
        self._sprite = sp.SkeletonAnimation:create("spine/116_m_fks/116_m_fks.json","spine/116_m_fks/116_m_fks.atlas",0.08)
        self._sprite:setAnimation(0,"stanby_1",true)--创建角色
        self._sprite:setScale(-1,1)
        self._sprite:setPosition(from.x *tileWidth+(tileWidth*0.5),from.y *tileHeight)
        self:addChild(self._sprite)
        
        local astar_logic = AStar.create()
        astar_logic:init(mapData)
        self._lPath = astar_logic:getSearchPath(from, to)
        self:drawPathNode()
        self._posIndex = #self._lPath
        self:moveSprite()
    end
    
    function TestScene:setCollisionSp()--设置障碍物
        for k, v in pairs(self.mapData) do
            for m, n in pairs(v) do
                if n == 1 then--障碍物
                    local sp = display.newSprite("collision.png",i*tileWidth+(tileWidth*0.5),j*tileHeight+(tileWidth*0.5))
                    self:addChild(sp)
                end
            end
        end
    end
    
    function TestScene:moveSprite()--移动精灵
        local x = self._lPath[self._posIndex]._col *tileWidth+(tileWidth*0.5)
        local y = self._lPath[self._posIndex]._row *tileWidth+(tileWidth*0.5)
        transition.moveTo(self._sprite,{x = x,y = y,time = 1,onComplete = function() 
            self._posIndex = self._posIndex - 1
            if self._posIndex == 0 then
                return
            end
            self:moveSprite()
        end})
    end
    
    function TestScene:drawPathNode()--画路径图片
        for k,v in pairs(self._lPath) do
            local sp3 = display.newSprite("redPoint.png",v._col *tileWidth+(tileWidth*0.5),v._row  *tileWidth+(tileWidth*0.5))
            self:addChild(sp3)
        end
    end

    转载请注明出处,from 博客园HemJohn

  • 相关阅读:
    AX ERROR: Could not find my mock parent, most likely I am stale 不及格的程序员
    利用Segue在视图控制器间传值的问题 不及格的程序员
    Creating a Singleton Instance 不及格的程序员
    iPad 通知 UIKeyboardWillShowNotification 不会在keyBoard处在Undock状态下接到通知 不及格的程序员
    Why RootViewController's view is rotated Automatically by System when the app first loaded? 不及格的程序员
    如何弹出UIDatePicker最好 不及格的程序员
    jQuery开始做恶了 不及格的程序员
    what is the SEL,id and IMP,Class ,Method? 不及格的程序员
    Objectivec 字符串比较的陷井 不及格的程序员
    Unable to create any keyboard shortcuts after the iOS 6.1.3 update on iPad. 不及格的程序员
  • 原文地址:https://www.cnblogs.com/HemJohn/p/4983221.html
Copyright © 2011-2022 走看看