PathFindDStar.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. local tremove = table.remove
  2. local tinsert = table.insert
  3. local INFINITY_COST = 0xFFFFFF
  4. local PathNode = class("PathNode")
  5. function PathNode:ctor()
  6. self.x = 0
  7. self.y = 0
  8. self.t = "new"
  9. self.h = 0
  10. self.k = 0
  11. self.isObstacle = 0
  12. self.backpointer = nil
  13. end
  14. function PathNode:cost(node)
  15. if self.isObstacle == 1 or node.isObstacle == 1 then
  16. return INFINITY_COST
  17. end
  18. local line_value = ((self.x == node.x or self.y == node.y) and 10 or 14)
  19. return ((self.x-node.x)*(self.x-node.x) + (self.y-node.y)*(self.y-node.y)) + line_value
  20. end
  21. -- local PPoint = class("PPoint")
  22. -- function PPoint:ctor()
  23. -- self._currentCost = 0
  24. -- self._minimumCost = 0
  25. -- self.x = 0
  26. -- self.y = 0
  27. -- self.t = "new"
  28. -- self.h = 0
  29. -- self.k = 0
  30. -- self.isObstacle = 0
  31. -- self.nextPoint = nil
  32. -- end
  33. -- function PPoint:cost(point)
  34. -- if self.isObstacle == 1 or point.isObstacle == 1 then
  35. -- return 0xFFFFFF
  36. -- end
  37. -- -- local line_value = ((self.x == point.x or self.y == point.y) and 10 or 14)
  38. -- local line_value = ((self.x == point.x or self.y == point.y) and 10 or 10)
  39. -- return ((self.x-point.x)*(self.x-point.x) + (self.y-point.y)*(self.y-point.y)) + line_value
  40. -- end
  41. -- function PPoint:costVia(point)
  42. -- if self.isObstacle == 1 or point.isObstacle == 1 then
  43. -- return 0xFFFFFF
  44. -- end
  45. -- return self._currentCost + self:cost(point)
  46. -- end
  47. -- function PPoint:setNextPointAndUpdateCost(p)
  48. -- self.nextPoint = p
  49. -- self._currentCost = self:cost(p)
  50. -- self._minimumCost = (self._minimumCost == 0 and cost or math.min(self._minimumCost, self._currentCost))
  51. -- end
  52. -- function PPoint:get_neighbors()
  53. -- local neighbors = {}
  54. -- local around =
  55. -- {
  56. -- { self.x + 1, self.y }, -- right
  57. -- { self.x, self.y + 1 }, -- bottom
  58. -- { self.x - 1, self.y }, -- left
  59. -- { self.x, self.y - 1 }, -- top
  60. -- { self.x + 1, self.y - 1 }, -- right up
  61. -- { self.x + 1, self.y + 1 }, -- right bottom
  62. -- { self.x - 1, self.y + 1 }, -- left bottom
  63. -- { self.x - 1, self.y - 1 }, -- left top
  64. -- }
  65. -- for i = 1, 8 do
  66. -- local x = around[i][1]
  67. -- local y = around[i][2]
  68. -- -- out of bounds
  69. -- if not (x < 0 or x >= 9999 or y < 0 or y >= 9999) then
  70. -- local point = PPoint.new()
  71. -- point.x = x
  72. -- point.y = y
  73. -- tinsert(neighbors, point)
  74. -- end
  75. -- end
  76. -- return neighbors
  77. -- end
  78. --
  79. local PathFindDStar = class('PathFindDStar', framework.Mediator)
  80. PathFindDStar.NAME = "PathFindDStar"
  81. function PathFindDStar:ctor()
  82. PathFindDStar.super.ctor(self, self.NAME)
  83. self.mapNodes = {}
  84. self.openlist = {}
  85. self.mapData = nil
  86. self.location = nil
  87. self.isMoving = false
  88. end
  89. function PathFindDStar:cleanup()
  90. self.startPathNode = nil
  91. self.endPathNode = nil
  92. self.mapNodes = {}
  93. self.openlist = {}
  94. self.location = nil
  95. self.isMoving = false
  96. end
  97. function PathFindDStar:onRegister()
  98. PathFindDStar.super.onRegister(self)
  99. local function actCallback(actor, act)
  100. if actor and (global.MMO.ACTION_WALK == act or global.MMO.ACTION_RUN == act or act == global.MMO.ACTION_RIDE_RUN) then
  101. local x = actor:GetMapX()
  102. local y = actor:GetMapY()
  103. -- local aiManager = aiManager:Inst()
  104. -- local ret = aiManager:OnMainPlayerMoved( x, y, self.mapData )
  105. -- print("retretretretretretretretretretretretretretretretretret", ret)
  106. -- if ret == 1 then
  107. -- local findPoints = aiManager:GetPathFind():GetPathPoints()
  108. -- local inputProxy = global.Facade:retrieveProxy( global.ProxyTable.PlayerInputProxy )
  109. -- inputProxy:SetPathFindPoints( findPoints )
  110. -- end
  111. self.location = self:getPathNode(x, y)
  112. if self.location and self.location.t == "closed" and self.location.backpointer and self.location.backpointer.isObstacle == 1 then
  113. self:find_path_modify()
  114. end
  115. end
  116. end
  117. global.gamePlayerController:AddHandleOnActCompleted(actCallback)
  118. end
  119. function PathFindDStar:UpdateMapData(mapData)
  120. self.mapNodes = {}
  121. self.mapData = mapData
  122. self.mapRows = self.mapData:getMapDataCols()
  123. self.mapCols = self.mapData:getMapDataRows()
  124. end
  125. function PathFindDStar:getPathNode(x, y)
  126. if self.mapNodes[x] and self.mapNodes[x][y] then
  127. return self.mapNodes[x][y]
  128. end
  129. local node = PathNode.new()
  130. node.x = x
  131. node.y = y
  132. node.h = 0
  133. node.k = 0
  134. node.t = "new"
  135. node.backpointer = nil
  136. node.isObstacle = self.mapData:isObstacle(x, y)
  137. if not self.mapNodes[x] then
  138. self.mapNodes[x] = {}
  139. end
  140. self.mapNodes[x][y] = node
  141. return node
  142. end
  143. function PathFindDStar:updateMapNode(x, y, isObstacle)
  144. -- local aiManager = aiManager:Inst()
  145. -- local ret = aiManager:DynamicObstacle( x, y, isObstacle, self.mapData )
  146. if not (self.mapNodes[x] and self.mapNodes[x][y]) then
  147. return -1
  148. end
  149. self.mapNodes[x][y].isObstacle = isObstacle
  150. -- next pointer is obstacle
  151. -- if self.location and self.location.t == "closed" and self.location.backpointer and self.location.backpointer.isObstacle == 1 then
  152. -- self:find_path_modify()
  153. -- end
  154. end
  155. function PathFindDStar:getNeighbors(node)
  156. local neighbors = {}
  157. local around =
  158. {
  159. { node.x + 1, node.y }, -- right
  160. { node.x, node.y + 1 }, -- bottom
  161. { node.x - 1, node.y }, -- left
  162. { node.x, node.y - 1 }, -- top
  163. { node.x + 1, node.y - 1 }, -- right up
  164. { node.x + 1, node.y + 1 }, -- right bottom
  165. { node.x - 1, node.y + 1 }, -- left bottom
  166. { node.x - 1, node.y - 1 }, -- left top
  167. }
  168. for i = 1, 8 do
  169. local x = around[i][1]
  170. local y = around[i][2]
  171. -- out of bounds
  172. if not (x < 0 or x >= self.mapRows or y < 0 or y >= self.mapCols) then
  173. local node = self:getPathNode(x, y)
  174. tinsert(neighbors, node)
  175. end
  176. end
  177. return neighbors
  178. end
  179. function PathFindDStar:getMinKNode()
  180. local node = nil
  181. local k = nil
  182. local index = nil
  183. for i, v in pairs(self.openlist) do
  184. if not node or v.k < node.k then
  185. node = v
  186. k = node.k
  187. index = i
  188. end
  189. end
  190. return node, k, index
  191. end
  192. function PathFindDStar:insert(node, h_new)
  193. if node.t == "new" then
  194. node.k = h_new
  195. node.h = h_new
  196. node.t = "open"
  197. tinsert(self.openlist, node)
  198. elseif node.t == "open" then
  199. node.k = math.min(node.k, h_new)
  200. elseif node.t == "closed" then
  201. node.k = math.min(node.h, h_new)
  202. node.h = h_new
  203. node.t = "open"
  204. tinsert(self.openlist, node)
  205. end
  206. return true
  207. end
  208. function PathFindDStar:process_state()
  209. if #self.openlist == 0 then
  210. return -1
  211. end
  212. local currentNode, currentK, index = self:getMinKNode()
  213. if currentK == currentNode.h then
  214. for _, neighbor in pairs(self:getNeighbors(currentNode)) do
  215. local cost = currentNode.h + currentNode:cost(neighbor)
  216. if (neighbor.t == "new") or (neighbor.backpointer == currentNode and neighbor.h ~= cost) or (neighbor.backpointer ~= currentNode and neighbor.h > cost) then
  217. neighbor.backpointer = currentNode
  218. self:insert(neighbor, cost)
  219. end
  220. end
  221. else
  222. for _, neighbor in pairs(self:getNeighbors(currentNode)) do
  223. local cost = neighbor.h + currentNode:cost(neighbor)
  224. if neighbor.h <= currentK and currentNode.h > cost then
  225. currentNode.backpointer = neighbor
  226. currentNode.h = cost
  227. end
  228. end
  229. -- for _, neighbor in pairs(self:getNeighbors(currentNode)) do
  230. -- local cost = neighbor.h + currentNode:cost(neighbor)
  231. -- -- if neighbor.h <= currentK and currentNode.h > cost then
  232. -- if currentNode.h > cost then
  233. -- currentNode.backpointer = neighbor
  234. -- currentNode.h = cost
  235. -- end
  236. -- end
  237. end
  238. currentNode.t = "closed"
  239. table.remove(self.openlist, index)
  240. if #self.openlist == 0 then
  241. return -1
  242. end
  243. local currentNode, currentK, index = self:getMinKNode()
  244. return currentK, currentNode
  245. end
  246. function PathFindDStar:modify_cost(node)
  247. if node.t == "closed" then
  248. self:insert(node, node.backpointer.h + node:cost(node.backpointer))
  249. end
  250. end
  251. function PathFindDStar:modify(node)
  252. print(" node x " .. node.x .. " y " .. node.y .. " k " .. node.k .. " h " .. node.h)
  253. self._count = 0
  254. self:modify_cost(node)
  255. print(" node modify x " .. node.x .. " y " .. node.y .. " k " .. node.k .. " h " .. node.h)
  256. while true do
  257. self._count = self._count + 1
  258. local currentNode, currentK, index = self:getMinKNode()
  259. print("x " .. currentNode.x .. " y " .. currentNode.y .. " k " .. currentNode.k .. " h " .. currentNode.h)
  260. local k_min = self:process_state()
  261. print("k_min", k_min)
  262. print(" node progressstate x " .. node.x .. " y " .. node.y .. " k " .. node.k .. " h " .. node.h)
  263. print("-------------------------------------")
  264. if self._count >= 5 then
  265. return -1
  266. end
  267. if k_min == -1 then
  268. return -1
  269. end
  270. if k_min >= node.h then
  271. break
  272. end
  273. end
  274. return 0
  275. end
  276. function PathFindDStar:find_path(begX, begY, endX, endY)
  277. print("*********************************** find path D*")
  278. self._isModify = false
  279. self:cleanup()
  280. self.startPathNode = self:getPathNode(begX, begY)
  281. self.endPathNode = self:getPathNode(endX, endY)
  282. -- impass
  283. if self.endPathNode.isObstacle == 1 or self.startPathNode.isObstacle == 1 then
  284. return {}
  285. end
  286. local neighbors = self:getNeighbors(self.startPathNode)
  287. local impass = true
  288. for k, v in pairs(neighbors) do
  289. if v.isObstacle == 0 then
  290. impass = false
  291. break
  292. end
  293. end
  294. if impass then
  295. return {}
  296. end
  297. local neighbors = self:getNeighbors(self.endPathNode)
  298. local impass = true
  299. for k, v in pairs(neighbors) do
  300. if v.isObstacle == 0 then
  301. impass = false
  302. break
  303. end
  304. end
  305. if impass then
  306. return {}
  307. end
  308. -- 开始搜寻
  309. self:insert(self.endPathNode, 0)
  310. while true do
  311. local ret = self:process_state()
  312. if ret == -1 then
  313. return {}
  314. elseif self.startPathNode.t == "closed" then
  315. break
  316. end
  317. end
  318. -- points
  319. local points = {}
  320. local node = self.startPathNode.backpointer
  321. while node ~= self.endPathNode do
  322. tinsert(points, 1, {x=node.x, y=node.y})
  323. node = node.backpointer
  324. end
  325. tinsert(points, 1, {x=self.endPathNode.x, y=self.endPathNode.y})
  326. self.isMoving = true
  327. return points
  328. end
  329. function PathFindDStar:find_path_modify()
  330. if not self.isMoving then
  331. return -1
  332. end
  333. if not self.location then
  334. return -1
  335. end
  336. if self.location.isObstacle == 1 then
  337. return -1
  338. end
  339. if not self.location.backpointer then
  340. return -1
  341. end
  342. if self.location.backpointer.isObstacle == 1 and self.location.backpointer == self.endPathNode then
  343. return -1
  344. end
  345. local neighbors = self:getNeighbors(self.location)
  346. local impass = true
  347. for k, v in pairs(neighbors) do
  348. if v.isObstacle == 0 then
  349. impass = false
  350. break
  351. end
  352. end
  353. if impass then
  354. return -1
  355. end
  356. print("--------------------modify")
  357. local temp = self.location
  358. while true do
  359. if temp.backpointer.isObstacle == 1 then
  360. local r = self:modify(temp)
  361. print("rrrrrrrrrrrrrrrrr", r)
  362. if r == -1 then
  363. break
  364. end
  365. end
  366. break
  367. -- if not temp or temp.isObstacle == 0 then
  368. -- break
  369. -- end
  370. end
  371. print("--------------------modify end")
  372. -- points
  373. local points = {}
  374. local temp = self.location.backpointer
  375. while temp do
  376. tinsert(points, 1, {x=temp.x, y=temp.y})
  377. temp = temp.backpointer
  378. end
  379. if #points > 0 then
  380. -- 更新路径
  381. local inputProxy = global.Facade:retrieveProxy( global.ProxyTable.PlayerInputProxy )
  382. inputProxy:SetPathFindPoints( points )
  383. else
  384. -- 更新路径
  385. local inputProxy = global.Facade:retrieveProxy( global.ProxyTable.PlayerInputProxy )
  386. inputProxy:SetPathFindPoints( {} )
  387. end
  388. print("*********************modify end")
  389. end
  390. -- function PathFindDStar:dstar_init()
  391. -- self._dstarOpenlist = {}
  392. -- end
  393. -- function PathFindDStar:dstar_add_to_openlist(p)
  394. -- table.insert(self._dstarOpenlist, p)
  395. -- end
  396. -- function PathFindDStar:dstar_find_path()
  397. -- while next(self._dstarOpenlist) do
  398. -- local p = self._dstarOpenlist[1]
  399. -- end
  400. -- end
  401. -- function PathFindDStar:dstar_expand(p)
  402. -- local isRaise = self:dstar_is_raise(p)
  403. -- local cost = 0
  404. -- for _, neighbor in pairs(p:get_neighbors()) do
  405. -- if isRaise then
  406. -- if neighbor.nextPoint == p then
  407. -- neighbor:setNextPointAndUpdateCost(p)
  408. -- self:dstar_add_to_openlist(neighbor)
  409. -- else
  410. -- cost = neighbor:cost(p)
  411. -- -- if
  412. -- end
  413. -- end
  414. -- end
  415. -- end
  416. -- function PathFindDStar:dstar_is_raise(p)
  417. -- local cost = 0
  418. -- if p._currentCost > p._minimumCost then
  419. -- for _, neighbor in pairs(p:get_neighbors()) do
  420. -- cost = p:costVia(neighbor)
  421. -- if cost < p._currentCost then
  422. -- p:setNextPointAndUpdateCost(neighbor)
  423. -- end
  424. -- end
  425. -- end
  426. -- return p._currentCost > p._minimumCost
  427. -- end
  428. return PathFindDStar