3d地圖的a*尋路

對於2d地圖的a星算法其實很多。原理都是一樣的,我做這個的3d的尋路其實只是在2d地圖數據中加入了一個高度的數據,而在權重中由原來的兩個座標的勾股定理變爲三維座標系的勾股定理,以前我做cocos2dx開發時曾寫過一個lua版的a星,就用這個作爲說明吧(涉及a星的原理就不必再說明了,很多博客都會有):


其中的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)
發佈了39 篇原創文章 · 獲贊 17 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章