您好,登錄后才能下訂單哦!
游戲中有敵我雙方,有四十個方格,當(dāng)輪到我方武將行動的時候,要先顯示出我方武將可以行動的方位,這個就涉及到我方武將的行動力的大小來決定,預(yù)先做出路徑的預(yù)算。這里還要考慮敵方以及地標(biāo)(例如:×××、勢頭)的阻擋,以及特殊方格對武將行動力的消耗以及敵方的間隔阻擋規(guī)則。
當(dāng)碰到這個問題的時候,問老大選擇用什么尋路算法,他推薦的是Dijstra算法,但我看了之后感覺還不是很適合我的需求,第一:我覺得Dijstra算法是有向圖的最佳路徑選擇,節(jié)點之間路徑長度必須先知曉,但我這里四十個方格如果要兩兩制定感覺稍微復(fù)雜,而且隨著武將的移動,地圖還是時時變化的,感覺更復(fù)雜。第二:Distra算法沒有阻擋考慮,當(dāng)然也可以記錄若干路徑然后考慮阻擋選擇最優(yōu)路徑,我感覺也稍復(fù)雜。
然而我的第一反應(yīng)該需求A*算法挺接近的,然后咨詢老大,老大說A*方格之間距離必須要均等不然比較復(fù)雜。然后再咨詢公司其他稍有經(jīng)驗同事,當(dāng)然各有個的說法,什么深度、廣度遍歷,感覺沒一個確定的說法。讓我選擇就糾結(jié)了一天,不敢輕易選擇,如果稍有考慮不慎,說不定就要做幾天白用工,但最后我還是堅持自己的想法用A*來實現(xiàn)。
A*通用的計算公式F=G+H
G:表示從起點A移動到網(wǎng)格上指定方格的移動耗費(我這里沒考慮斜方向移動),也可理解為節(jié)點的權(quán)重
H:表示從制定方格移動到終點B的預(yù)計耗費,這里一般就是計算距離*系數(shù)
1.從起點A開始,把它添加到"開啟列表"
2.尋找A點可到到的周圍四個點,這里可到達(dá)是指沒有阻擋并且已經(jīng)不再關(guān)閉列表中的節(jié)點,并把他們添加進(jìn)開啟列表,并設(shè)置他們的父節(jié)點為A
3.從開啟列表中刪除A點并添加進(jìn)關(guān)閉列表中,關(guān)閉列表就是存放的不需要檢測的方格節(jié)點
4.檢查它所有相鄰并且合一到達(dá)的方格,如果這些方格還不再開啟列表里的話就把他們加入開啟列表,計算這些方格的GHF值并設(shè)置它的父節(jié)點
5.如果某個相鄰方格 D 已經(jīng)在 "開啟列表" 里了, 檢查如果用新的路徑 (就是經(jīng)過C 的路徑) 到達(dá)它的話, G值是否會更低一些, 如果新的G值更低, 那就把它的 "父方格" 改為目前選中的方格 C, 然后重新計算它的 F 值和 G 值 (H 值不需要重新計算, 因為對于每個方塊, H 值是不變的). 如果新的 G 值比較高, 就說明經(jīng)過 C 再到達(dá) D 不是一個明智的選擇, 因為它需要更遠(yuǎn)的路, 這時我們什么也不做
6.當(dāng)發(fā)現(xiàn)開啟列表中有終點目標(biāo)方格的時候則說明路徑已經(jīng)找到。
關(guān)于詳細(xì)的圖解可以參考其他網(wǎng)友的詳解,我這里就不詳細(xì)寫了。
我們找到最后一個點的時候然后層層往之前找到他的父節(jié)點迭代到最后不為空結(jié)束
Point類
[plain] view plaincopyprint?
module('Point', package.seeall)
-- require("script/battle/BattleCommon")
--計算F值
function CalcF( point )
point.F = point.G + point.H
end
function create( posId )
local point = {}
point.parentPoint = {}
point.step = 1 --用于計算h值
local x,y = BattleCommon.convertPosIdToCoord(posId)
point.F = 0
point.G = 0
point.H = 0
point.X = y --point.X范圍[1,5]
point.Y = x --point.Y范圍[1,8]
point.posId = posId
point.CalcF = CalcF
return point
end
return Point
地形(Maze)結(jié)構(gòu)
[plain] view plaincopyprint?
--根據(jù)一個table創(chuàng)建一個地形
function create( tb )
local maze = {}
maze.step = 1 --格子與格子的基本距離,用于計算H值
maze.mazeArray = tb
maze.openList = TabledArray.create() --開啟列表
maze.closeList = TabledArray.create() --關(guān)閉列表
maze.findPath = findPath
return maze
end
[plain] view plaincopyprint?
module('Maze', package.seeall)
require("script/battle/TabledArray")
require("script/battle/BattleCommon")
require ("script/battle/Point")
-- --獲取列表中F值最小的點
function getMinPoint( pointsList )
local minPoint = pointsList.tbl[1]
for i = 1,pointsList:getSize() do
if minPoint.F > pointsList.tbl[i].F then
minPoint = pointsList.tbl[i]
end
end
return minPoint
end
-- --檢測是否有阻擋,沒有阻擋為true
function checkBlock( maze,x,y,roleFlag) --x范圍[1,5] y范圍[1,8]
if roleFlag == BattleCommon.BATTLE_GROUP_ALLIES then --我方陣營
if maze.mazeArray[x][y][1] == 0 or maze.mazeArray[x][y][1] == 1 then
return true --沒有阻擋
else
return false
end
elseif roleFlag == BattleCommon.BATTLE_GROUP_ENEMY then
if maze.mazeArray[x][y][1] == 0 or maze.mazeArray[x][y][1] == 2 then
return true --沒有阻擋
else
return false
end
end
end
-- --列表中是否包含x,y的點
function existsXY( list,x,y )
if list:getSize()>0 then
for i,point in pairs(list.tbl) do
if point.X == x and point.Y == y then
return true
end
end
end
return false
end
--列表中是否包含某個點
function existsPoint( list,point )
for i, p in pairs(list.tbl) do
if (p.X == point.X) and (p.Y == point.Y) then
return true
end
end
return false
end
-- --檢測能達(dá)到的點
function canReach( maze,startPoint,x,y,roleFlag)
if (not checkBlock(maze,x,y,roleFlag)) or existsXY(maze.closeList,x,y) then --關(guān)閉列表中包含這個點或者有阻擋
return false
else
if (math.abs(x-startPoint.X)+math.abs(y-startPoint.Y) == 1 ) then
return true
end
end
end
-- --獲取相鄰的點
function getSurroundPoints( maze,point,roleFlag )
local surroundPoints = TabledArray.create()
for i = point.X - 1 ,point.X + 1 do
for j=point.Y - 1,point.Y + 1 do
if i>0 and i<6 and j > 0 and j < 9 then --排除超過表姐
if BattleCommon.distanceFromTo(point.posId,BattleCommon.convertToPositionId(j-1,i-1)) < 2 then
if canReach(maze,point,i,j,roleFlag) then
surroundPoints:append(maze.mazeArray[i][j][2])
end
end
end
end
end
return surroundPoints --返回point點的集合
end
-- --計算G值
function CalcG( point )
local G = point.G
local parentG = 0
if point.parentPoint then
parentG = point.parentPoint.G
end
return G + parentG
end
function foundPoint( tempStart,point )
local G = CalcG(point)
if G < point.G then
point.parentPoint = tempStart
point.G = G
point:CalcF()
end
end
function notFoundPoint( maze,tempStart,point )
point.parentPoint = tempStart
point.G = CalcG(point)
point:CalcF()
maze.openList:append(point)
end
function getPoint( list,data )
for i,point in pairs(list.tbl) do
if point.posId == data.posId then
return point
end
end
return nil
end
-- --尋找路徑(起始路徑)
local function findPath( maze,startPoint,endPoint,roleFlag)
maze.openList:append(startPoint)
while maze.openList:getSize() ~= 0 do
--找出F的最小值
local tempStart = getMinPoint(maze.openList)
maze.openList:removeById(1)
maze.closeList:append(tempStart)
--找出它相鄰的點
local surroundPoints = getSurroundPoints(maze,tempStart,roleFlag)
for i,point in pairs(surroundPoints.tbl) do
if existsPoint(maze.openList,point) then
--計算G值,如果比原來大,就什么都不做,否則設(shè)置他的父節(jié)點為當(dāng)前節(jié)點,并更新G和F
foundPoint(tempStart,point)
else
--如果他們不再開始列表里面,就加入,并設(shè)置父節(jié)點,并計算GHF
notFoundPoint(maze,tempStart,point)
end
end
--如果最后一個存在則返回
if getPoint(maze.openList,endPoint) then
return getPoint(maze.openList,endPoint)
end
end
return getPoint(maze.openList,endPoint)
end
--根據(jù)一個table創(chuàng)建一個地形
function create( tb )
local maze = {}
maze.step = 1 --格子與格子的基本距離,用于計算H值
maze.mazeArray = tb
maze.openList = TabledArray.create() --開啟列表
maze.closeList = TabledArray.create() --關(guān)閉列表
maze.findPath = findPath
return maze
end
return Maze
調(diào)用方法
[plain] view plaincopyprint?
function printPath( presentPoint )
local pathArray = TabledArray.create()
while presentPoint do
pathArray:preppend(presentPoint.posId)
presentPoint = presentPoint.parentPoint
end
local startPoint = pathArray:get(2)
local endPoint = pathArray:getLast()
cclog(startPoint)
cclog(endPoint)
cclog("從"..startPoint.."到"..endPoint.."的路徑是:")
for i,p in pairs(pathArray.tbl) do
cclog(p)
end
end
[plain] view plaincopyprint?
local array = battleBoard:createBoxPoints(cRole:getFlag(),40)
local maze = Maze.create(array)
local startPoint = Point.create(cRole:getPositionId())
local endPoint = Point.create(40)
local presentPoint = maze:findPath(startPoint,endPoint,cRole:getFlag())
printPath(presentPoint)
七、運行效果
手機(jī)測試效果還可以,貌似在255*255規(guī)模的方格規(guī)模上采用A*還是不會有太大的效率影響。如果需要交流歡迎聯(lián)系。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。