223 lines
6.4 KiB
Lua
223 lines
6.4 KiB
Lua
---定义地图逻辑数据
|
|
TileData = {}
|
|
TileData.__index = TileData
|
|
|
|
function TileData.New(u, v, val)
|
|
local instance = {}
|
|
instance.u = u
|
|
instance.v = v
|
|
instance.val = val
|
|
instance.isOpen = false
|
|
instance.nearVal = 0
|
|
setmetatable(instance, TileData)
|
|
return instance
|
|
end
|
|
|
|
TileMapData = {}
|
|
TileMapData.__index = TileMapData
|
|
local this = TileMapData
|
|
|
|
local _getTileCost = function (u, v)
|
|
return 1
|
|
end
|
|
|
|
local _getDistance = function (u, v, eu, ev)
|
|
return math.abs(u-eu) + math.abs(v-ev)
|
|
end
|
|
|
|
local _getCost = function (self, u, v)
|
|
return self._openList[Map_UV2Pos(u, v)][4]
|
|
end
|
|
|
|
local _initCloseList = function (self)
|
|
self._closeList = {}
|
|
for i = 1, self.uLen do
|
|
for j = 1, self.vLen do
|
|
self._closeList[Map_UV2Pos(i, j)] = false
|
|
end
|
|
end
|
|
end
|
|
|
|
local _initOpenList = function (self, eu, ev)
|
|
self._openList = {}
|
|
for i = 1, self.uLen do
|
|
for j = 1, self.vLen do
|
|
local list = {}
|
|
list[1] = 0 --定义地块是否存在 0不存在 1存在
|
|
list[2] = _getTileCost(i, j) --定义地块消耗值
|
|
list[3] = _getDistance(i, j, eu, ev) --定义总距离
|
|
list[4] = list[2] + list[3] --定义路径总损耗
|
|
list[5] = 0 --定义方向值 0无 1下 2上 3左 4右
|
|
self._openList[Map_UV2Pos(i, j)] = list
|
|
end
|
|
end
|
|
self._openListLen = 0
|
|
end
|
|
|
|
local _addOpenList = function (self, u, v)
|
|
if self._openList[Map_UV2Pos(u, v)][1] == 0 then
|
|
self._openList[Map_UV2Pos(u, v)][1] = 1
|
|
self._openListLen = self._openListLen + 1
|
|
end
|
|
end
|
|
|
|
local _removeOpenList = function (self, u, v)
|
|
if self._openList[Map_UV2Pos(u, v)][1] == 1 then
|
|
self._openList[Map_UV2Pos(u, v)][1] = 0
|
|
self._openListLen = self._openListLen - 1
|
|
end
|
|
end
|
|
|
|
local _setCost = function (self, u, v, eu, ev)
|
|
local list = self._openList[Map_UV2Pos(u, v)]
|
|
local newlist = self._openList[Map_UV2Pos(eu, ev)]
|
|
list[2] = newlist[2] + _getTileCost(u, v)
|
|
list[3] = _getDistance(u, v, eu, ev)
|
|
list[4] = list[2] + list[3]
|
|
end
|
|
|
|
local _setFatherDir = function (self, u, v, dir)
|
|
self._openList[Map_UV2Pos(u, v)][5] = dir
|
|
end
|
|
|
|
local _isCanPass = function (self, u, v)
|
|
--超出边界
|
|
if u < 1 or u > self.uLen or v < 1 or v > self.vLen then
|
|
return false
|
|
end
|
|
--在关闭列表中
|
|
if self._closeList[Map_UV2Pos(u, v)] then
|
|
return false
|
|
end
|
|
--地图不通
|
|
if not self._checkPassFunc(self:GetMapData(u, v)) then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
local _addNewOpenList = function (self, u, v, nU, nV, dir)
|
|
if _isCanPass(self, nU, nV) then
|
|
local list = self._openList[Map_UV2Pos(u, v)]
|
|
local newlist = self._openList[Map_UV2Pos(nU, nV)]
|
|
if list[1] == 1 then
|
|
if list[2] + _getTileCost(u, v) < newlist[2] then
|
|
_setFatherDir(self,nU, nV, dir)
|
|
_setCost(self,nU, nV, u, v)
|
|
end
|
|
else
|
|
_addOpenList(self, nU, nV)
|
|
_setFatherDir(self, nU, nV, dir)
|
|
_setCost(self, nU, nV, u, v)
|
|
end
|
|
end
|
|
end
|
|
|
|
local _aStar = function (self, tileStart, tileEnd)
|
|
local x = tileStart.u
|
|
local y = tileStart.v
|
|
local cost
|
|
local minDistance = _getDistance(tileEnd.u, tileEnd.v, tileStart.u, tileStart.v)
|
|
local nearestData = tileStart --当目标点不可达时,选择最近的可达点
|
|
local distance
|
|
for t = 1, 5000 do --控制算法深度
|
|
if x == tileEnd.u and y == tileEnd.v then
|
|
return nearestData
|
|
elseif self._openListLen == 0 then
|
|
return nearestData
|
|
end
|
|
|
|
_removeOpenList(self,x, y)
|
|
self._closeList[Map_UV2Pos(x, y)] = true
|
|
|
|
--该点周围能够行走的点
|
|
_addNewOpenList(self,x,y,x,y+1,2)
|
|
_addNewOpenList(self,x,y,x,y-1,1)
|
|
_addNewOpenList(self,x,y,x-1,y,4)
|
|
_addNewOpenList(self,x,y,x+1,y,3)
|
|
|
|
--找到估值最小的点,进行下一轮算法
|
|
cost = 2 ^ 32
|
|
--随机选择遍历方式,从而得到随机寻路路径
|
|
for k, v in pairs(self._openList) do
|
|
if v[1] == 1 then
|
|
local i, j = Map_Pos2UV(k)
|
|
if cost > _getCost(self, i, j) then
|
|
cost = _getCost(self, i, j)
|
|
x = i
|
|
y = j
|
|
distance = _getDistance(tileEnd.u, tileEnd.v, i, j)
|
|
if distance < minDistance then
|
|
nearestData = self:GetMapData(i, j)
|
|
minDistance = distance
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--算法超深
|
|
return nearestData
|
|
end
|
|
|
|
function this.New(ulen, vlen)
|
|
local instance = {}
|
|
instance.uLen = ulen
|
|
instance.vLen = vlen
|
|
instance.mapData = {}
|
|
for i = 0, ulen do
|
|
for j = 0, vlen do
|
|
instance.mapData[Map_UV2Pos(i, j)] = TileData.New(i, j,0)
|
|
end
|
|
end
|
|
setmetatable(instance, TileMapData)
|
|
return instance
|
|
end
|
|
|
|
function this:GetMapData(u, v)
|
|
return self.mapData[Map_UV2Pos(u, v)]
|
|
end
|
|
|
|
function this:UpdateFogArea(u, v, rad)
|
|
-- Log("位置和迷雾范围: "..u.."|"..v.."|"..rad)
|
|
for i = math.max(u-rad, 1), math.min(u+rad, self.uLen) do
|
|
for j = math.max(v-rad, 1), math.min(v+rad, self.vLen) do
|
|
if math.abs(i-u) + math.abs(j-v) <= rad then
|
|
self:GetMapData(i, j).isOpen = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--寻路算法 返回的结果是从终点指向起点(包括起点)的坐标列表
|
|
function this:FindPath(tileStart, tileEnd, checkPassFunc)
|
|
if not tileStart or not tileEnd or tileStart == tileEnd then
|
|
return nil
|
|
end
|
|
|
|
self._checkPassFunc = checkPassFunc
|
|
|
|
_initCloseList(self)
|
|
_initOpenList(self,tileStart.u, tileStart.v)
|
|
_addOpenList(self,tileStart.u, tileStart.v)
|
|
|
|
local targetData = _aStar(self,tileStart, tileEnd)
|
|
local resList = {}
|
|
local x = targetData.u
|
|
local y = targetData.v
|
|
while x ~= tileStart.u or y ~= tileStart.v do
|
|
table.insert(resList, self:GetMapData(x, y))
|
|
local dir = self._openList[Map_UV2Pos(x, y)][5]
|
|
if dir == 1 then
|
|
y = y + 1
|
|
elseif dir == 2 then
|
|
y = y - 1
|
|
elseif dir == 3 then
|
|
x = x - 1
|
|
elseif dir == 4 then
|
|
x = x + 1
|
|
end
|
|
end
|
|
table.insert(resList, self:GetMapData(tileStart.u, tileStart.v))
|
|
return resList
|
|
end |