关于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
"TestScene.lua"
local MapNode = require "app.views.MapNode"
local TestScene = class("TestScene",cc.load("mvc").ViewBase)
local mapCol = 9
local mapRow = 9
local tileWidth = 50
local tileHeight = 50
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
function TestScene:ctor()
self._mapData = {}--地图数据
for i = 0,mapRow -1 do
self._mapData[i] = {}
for j = 0,mapCol -1 do
self._mapData[i][j] = 0
end
end
self._map = {}
self._lPath = {}--收集的路径
self._bFind = false
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
for i = 1,mapCol do--创建地图快图片
for j = 1,mapRow 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)
self:processAStar(from,to)--收集路径到_lPath
self:drawPathNode()
self._posIndex = #self._lPath
self:moveSprite()
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
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:setCollisionSp()--设置障碍物
for i = 3,6 do
for j = 3,6 do
self._mapData[i][j] = 1
local sp = display.newSprite("collision.png",i*tileWidth+(tileWidth*0.5),j*tileHeight+(tileWidth*0.5))
self:addChild(sp)
end
end
end
function TestScene:canPass(row,col)--判断是否能够通过
if self._mapData[col][row] == 0 then
return true
end
return false
end
function TestScene: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 TestScene: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 TestScene:processAStar(from,to)--执行A*算法
local f = self:AStarCore(from,to)
if f == true then
self:collectRoute(from,to)
release_print(true)
return true
end
return false
end
function TestScene: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 TestScene:isContain(tbl,cell) --在table中是否包含某个单元
for k,v in pairs(tbl) do
if tbl[k] == cell then
return true
end
end
return false
end
return TestScene
执行效果如下:
转载请注明出处,from 博客园HemJohn