miduo_client/Assets/ManagedResources/~Lua/Modules/Map/Logic/TileMapData.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