3d地图的a*寻路

对于2d地图的a星算法其实很多。原理都是一样的,我做这个的3d的寻路其实只是在2d地图数据中加入了一个高度的数据,而在权重中由原来的两个坐标的勾股定理变为三维坐标系的勾股定理,以前我做cocos2dx开发时曾写过一个lua版的a星,就用这个作为说明吧(涉及a星的原理就不必再说明了,很多博客都会有):

3d地图的a*寻路_第1张图片

其中的mapInfo可以更改为如下

self.MapInfo = 
    {
            [8] = {{"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}, {"obstacle" = 0, "height" = 255}},

...


地图的点也需要记录一个高度值

local xSub = math.abs(x - endx)
function MapPoint:init(x, y, h)
self.parent = nil;     --父节点,最后回溯使用
self.x = x;            --x坐标
self.y = y;            --y坐标

self.h = h;  --高度
    self.cost = 0;         --寻路到此点累计的消耗
    self.dist = 0;         --该点距离目的地直线距离(大约)
    self.power = 0;        --该点的累计消耗以及直线距离总和
end


再来看看具体寻路的代码:

--[[
 * @authors: liangjian
 * @date:    2014-09-01 21:30:09
 * @desc: a*算法
--]]


module( "Astar", package.seeall )


function new()
    local obj = {}
    setmetatable(obj, {__index = Astar})
    obj:init()
    return obj
end


function Astar:init()
    self.openList = {};     --打开,表示可以进行寻路的节点列表
    self.closeList = {};    --关闭,表示节点已经搜索过
    self.mapData = {};      --地图数据
    self.width = 0;         --地图的宽
    self.height = 0;        --地图的高
    self.startX = 0;        --开始点x
    self.startY = 0;        --开始点y
    self.endX = 0;          --终点x
    self.endY = 0;          --终点y
    self.path = {};         --保存路径
end
--设置地图数据
function Astar:setMapData(mapData)
    if mapData ~= nil and #mapData ~= 0 then
        self.mapData = mapData;
        self.width = #self.mapData[1];
        self.height = #self.mapData;
    end
end
--搜索,寻路前准备
function Astar:search(startX, startY, endX, endY)
    self.startX = startX;
    self.startY = startY;
    self.endX = endX;
    self.endY = endY;
    
    --判断是否超出地图外
    if (self.startX<0 or self.startX>=self.width) or (self.startY<0 or self.startY>=self.height) then
        print("出发点不在地图范围内!");
        return;
    elseif (self.endX<0 or self.endX>=self.width) or (self.endY<0 or self.endY>=self.height) then
        print("目的点不在地图范围内!");
        return;
    end
     
    --判断目的地以及出发地是否符合,1为障碍物,0通行
    if self.mapData[startY + 1][startX + 1] == 1 then
        print("出发地为障碍点!");
        return;
    end
    if self.mapData[endY + 1][endX + 1] == 1 then
        print("目的地为障碍点!");
        return;
    end
    
    --判断出发地与目的地是否相同
    if self.startX == self.endX and self.startY == self.endY then
        print("目的地与出发地相同!");
        return;
    end
    
    --根节点,第一个放进开放列表中
    local root = MapPoint.new(startX, startY);
    table.insert(self.openList, root);
    
    
    --开始寻路
    self:start(endX, endY);
    if self.path==nil or #self.path==0 then
        print("没有找到路径!");
    else
        print("输出路径:\n");
        for i = 1, #self.path do
            print("("..self.path[i].x..","..self.path[i].y..")\n");
        end
    end
end


--开始寻路,是个递归函数
function Astar:start(endX, endY)
    if self.openList == nil or #self.openList == 0 then return 0; end
    
    local least = self.openList[1];
    if least.x == endX and least.y == endY then
        self:recallGetPath(least)
        print("找到路径了!");
        return self.path;  
    end
    
    --八个方向检查
    self:check(least.x-1, least.y,   10, least, endX, endY) --左
    self:check(least.x+1, least.y,   10, least, endX, endY) --右
    self:check(least.x,   least.y+1, 10, least, endX, endY) --上
    self:check(least.x,   least.y-1, 10, least, endX, endY) --下
    self:check(least.x-1, least.y+1, 14, least, endX, endY) --左上
    self:check(least.x+1, least.y+1, 14, least, endX, endY) --右上
    self:check(least.x-1, least.y-1, 14, least, endX, endY) --左下
    self:check(least.x+1, least.y-1, 14, least, endX, endY) --右下
    
    --将当前节点放进关闭节点中
    table.insert(self.closeList, least)
    --将此节点从打开列表移除
    table.remove(self.openList, 1)
    self.openList = self:sortByPower(self.openList)
    
    self:start(endX, endY)
end


--检查是否通路
function Astar:check(x, y, cost, parent, endX, endY)
if (x<0 or x>=self.width) or (y<0 or y>=self.height) then
  print("该点处于地图外!");
  return;
end

if self:isContain(x, y, self.closeList) ~= -1 then
        print("该点已经访问过!");
        return;
end

    if self.mapData[y + 1][x + 1] == 1 then
        print("该点为障碍物!");
        return;
    end
    
    --累计到此点的消耗
    local node = MapPoint.new(x, y);
    node.parent = parent
    node.cost = parent.cost + cost
    
    --如果访问到开放列表中的点,则将此点重置为消耗最小的路径,否则添加到开放列表
    local index = self:isContain(x, y, self.openList)
    if index ~= -1 then
        if node.cost<self.openList[index].cost then
            node.dist = self.openList[index].dist
            node.power = node.dist + node.cost
            table.remove(self.openList, index)
            table.insert(self.openList, index, node)
    end
    else
        node.dist = self:getDist(x, y, endX, endY)
        node.power = node.dist + node.cost
        table.insert(self.openList, node)
    end
end


--计算点到目的地距离
function Astar:getDist(x, y, endx, endy)
    local xSub = math.abs(x - endx)
    local ySub = math.abs(y - endy)
    
    return math.sqrt(xSub*xSub + ySub*ySub)
end


--开启列表按照消耗排序
function Astar:sortByPower(list)
local sortList = {};
local size = #list
    for i = 1, size do
        local minIndex = 1
        for j = 2, #list do
            if list[minIndex].power > list[j].power then
                minIndex = j;
            end
        end
        table.insert(sortList, list[minIndex]);
        table.remove(list, minIndex);
end
    return sortList;
end


--判断点是否包含,返回索引值
function Astar:isContain(x, y, list)
for i = 1, #list do
if x == list[i].x and y == list[i].y then
 return i;
end
end

return -1;
end


--回溯找到路径
function Astar:recallGetPath(node)
    table.insert(self.path, 1, {x = node.x, y = node.y})
    if node.parent ~= nil then
        self:recallGetPath(node.parent)
    end
end


--没有找到路径
function Astar:notFoundPath()
self.path = {}
end


需要修改getDist(x, y, endx, endy)函数,增加一个高度差值

function(x, y, h,  endx, endy, endz)

local xSub = math.abs(x - endx)
    local ySub = math.abs(y - endy)

local zSub = math.abs(z - endz)

return 勾股定理

end

local xSub = math.abs(x - endx)

你可能感兴趣的:(3d地图的a*寻路)