PathFindController.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. local PathFindController = class("PathFindController")
  2. local PathFindAStar = require("logic/PathFindAStar")
  3. local function squLen(x, y)
  4. return x * x + y * y
  5. end
  6. local function convertDir(dir)
  7. if dir > global.MMO.ORIENT_LU then
  8. dir = dir - (global.MMO.ORIENT_LU+1)
  9. elseif dir < global.MMO.ORIENT_U then
  10. dir = dir + (global.MMO.ORIENT_LU+1)
  11. end
  12. return dir
  13. end
  14. local function checkMoveAbleOneStep(mapData, srcPos, moveStep, moveDir)
  15. local inputProxy = global.Facade:retrieveProxy(global.ProxyTable.PlayerInputProxy)
  16. local normalize = nil
  17. local dstPos = cc.p(0, 0)
  18. for i = 1, moveStep do
  19. normalize = inputProxy:DirToNormalizeVec2(moveDir)
  20. normalize = cc.pMul(normalize, i)
  21. dstPos.x = srcPos.x + normalize.x
  22. dstPos.y = srcPos.y + normalize.y
  23. if mapData:isObstacle(dstPos.x, dstPos.y) ~= 0 then
  24. return false
  25. end
  26. end
  27. return true, dstPos
  28. end
  29. function PathFindController:ctor()
  30. self.pathFindAStar = PathFindAStar.new()
  31. end
  32. function PathFindController:destory()
  33. if PathFindController.instance then
  34. PathFindController.instance = nil
  35. end
  36. end
  37. function PathFindController:Inst()
  38. if not PathFindController.instance then
  39. PathFindController.instance = PathFindController.new()
  40. end
  41. return PathFindController.instance
  42. end
  43. function PathFindController:IsOutBounds(movePos)
  44. local mapData = global.sceneManager:GetMapData2DPtr()
  45. if not mapData then
  46. return true
  47. end
  48. local mapRows = mapData:getMapDataRows()
  49. local mapCols = mapData:getMapDataCols()
  50. return (movePos.x < 0 or movePos.x >= mapCols or movePos.y < 0 or movePos.y >= mapRows)
  51. end
  52. function PathFindController:CheckMoveAble(movePos)
  53. local mapData = global.sceneManager:GetMapData2DPtr()
  54. if not mapData then
  55. return false
  56. end
  57. if self:IsOutBounds(movePos) then
  58. return false
  59. end
  60. if mapData:isObstacle(movePos.x, movePos.y) == 0 then
  61. return true
  62. end
  63. return false
  64. end
  65. function PathFindController:IsImpass(pos)
  66. local mapData = global.sceneManager:GetMapData2DPtr()
  67. if not mapData then
  68. return true
  69. end
  70. local around =
  71. {
  72. { pos.x + 1, pos.y }, -- right
  73. { pos.x, pos.y + 1 }, -- bottom
  74. { pos.x - 1, pos.y }, -- left
  75. { pos.x, pos.y - 1 }, -- top
  76. { pos.x + 1, pos.y - 1 }, -- right up
  77. { pos.x + 1, pos.y + 1 }, -- right bottom
  78. { pos.x - 1, pos.y + 1 }, -- left bottom
  79. { pos.x - 1, pos.y - 1 }, -- left top
  80. }
  81. for i = 1, 8 do
  82. local aroundX = around[i][1]
  83. local aroundY = around[i][2]
  84. if self:CheckMoveAble(cc.p(aroundX, aroundY)) then
  85. return false
  86. end
  87. end
  88. return true
  89. end
  90. function PathFindController:FindPathAStar(srcPos, dstPos)
  91. local findPoints = {}
  92. if not srcPos or not dstPos then
  93. return findPoints
  94. end
  95. if srcPos.x == dstPos.x and srcPos.y == dstPos.y then -- it's current pos,nothing to do
  96. return findPoints
  97. end
  98. -- 死路
  99. if true == self:IsImpass(srcPos) or true == self:IsImpass(dstPos) then
  100. return findPoints
  101. end
  102. --
  103. local mapData = global.sceneManager:GetMapData2DPtr()
  104. if not mapData then
  105. return findPoints
  106. end
  107. -- find
  108. aiManager:Inst():FindPath(srcPos.x, srcPos.y, dstPos.x, dstPos.y, mapData)
  109. findPoints = aiManager:Inst():GetPathFind():GetPathPoints()
  110. return findPoints
  111. end
  112. function PathFindController:FindPathAStarLimits(srcPos, dstPos)
  113. local points = self.pathFindAStar:find_path(srcPos.x, srcPos.y, dstPos.x, dstPos.y)
  114. return points
  115. end
  116. function PathFindController:FindDestPosJoystick(srcPos, moveDir, moveStep)
  117. -- 绝路
  118. if true == self:IsImpass(srcPos) then
  119. return nil
  120. end
  121. --
  122. local mapData = global.sceneManager:GetMapData2DPtr()
  123. if not mapData then
  124. return nil
  125. end
  126. local inputProxy = global.Facade:retrieveProxy(global.ProxyTable.PlayerInputProxy)
  127. local moveDirty = false
  128. local dstPos = cc.p(srcPos.x, srcPos.y)
  129. -- 先根据方向找格子
  130. if not moveDirty then
  131. for i = moveStep, 1, -1 do
  132. moveDirty, dstPos = checkMoveAbleOneStep(mapData, srcPos, i, moveDir)
  133. if moveDirty then
  134. break
  135. end
  136. end
  137. end
  138. -- 找邻近2个方向
  139. if not moveDirty then
  140. local dirs = {moveDir+1, moveDir-1}
  141. for _, dir in ipairs(dirs) do
  142. dir = convertDir(dir)
  143. for i = moveStep, 1, -1 do
  144. moveDirty, dstPos = checkMoveAbleOneStep(mapData, srcPos, i, dir)
  145. if moveDirty then
  146. break
  147. end
  148. end
  149. if moveDirty then
  150. break
  151. end
  152. end
  153. end
  154. -- 找更远2个方向
  155. if not moveDirty then
  156. local dirs = {moveDir+2, moveDir-2}
  157. for _, dir in ipairs(dirs) do
  158. dir = convertDir(dir)
  159. moveDirty, dstPos = checkMoveAbleOneStep(mapData, srcPos, 1, dir)
  160. if moveDirty then
  161. break
  162. end
  163. end
  164. end
  165. --
  166. if not moveDirty then
  167. local normalize = inputProxy:DirToNormalizeVec2(moveDir)
  168. local normalizeT = nil
  169. dstPos = cc.p(0, 0)
  170. for i = moveStep, SL:GetMetaValue("GAME_DATA","Joystick_Check_Range") or 0 do
  171. normalizeT = cc.pMul(normalize, i)
  172. dstPos.x = srcPos.x + normalize.x
  173. dstPos.y = srcPos.y + normalize.y
  174. if mapData:isObstacle(dstPos.x, dstPos.y) == 0 then
  175. moveDirty = true
  176. break
  177. end
  178. end
  179. end
  180. if not moveDirty then
  181. return nil
  182. end
  183. local findPoints = self:FindPathAStarLimits(srcPos, dstPos)
  184. if not findPoints then
  185. return nil
  186. end
  187. local pathLen = #findPoints
  188. if pathLen <= 0 then
  189. return nil
  190. end
  191. -- 第一步
  192. dstPos = findPoints[pathLen]
  193. -- 是否能走多步
  194. if pathLen > 1 and pathLen >= moveStep then
  195. local moveDir = CalcActorDirByPos(srcPos, findPoints[pathLen])
  196. for i = pathLen-1, 1, -1 do
  197. -- 步数超出
  198. if pathLen - i >= moveStep then
  199. break
  200. end
  201. -- 不同方向
  202. if moveDir ~= CalcActorDirByPos(findPoints[i+1], findPoints[i]) then
  203. break
  204. end
  205. dstPos = findPoints[i]
  206. end
  207. end
  208. return dstPos
  209. end
  210. --------------------------------------------------------------------------------------------
  211. function PathFindController:checkMovePosEnable(mapPos)
  212. local mapData = global.sceneManager:GetMapData2DPtr()
  213. if not mapData then
  214. return false
  215. end
  216. return mapData:isObstacle(mapPos.x, mapPos.y) == 0
  217. end
  218. function PathFindController:checkNextMovePos(player, pathPoints, currPathPoint)
  219. if currPathPoint <= 0 then
  220. return nil, nil
  221. end
  222. -- check first point
  223. local moveStep = 1
  224. local currPos = cc.p(player:GetMapX(), player:GetMapY())
  225. local nextPos = pathPoints[currPathPoint]
  226. local nextEnable = self:checkMovePosEnable(nextPos)
  227. if not nextEnable then
  228. return nil, nil
  229. end
  230. -- 寻路只有一格
  231. if currPathPoint <= 1 then
  232. return nextPos, moveStep
  233. end
  234. -- 只能走路buff
  235. if not CheckRunAble() or CheckRunStep() <= 1 then
  236. return nextPos, moveStep
  237. end
  238. local nextDir = CalcActorDirByPos(currPos, nextPos)
  239. -- check second point
  240. local next2Pos = pathPoints[currPathPoint - 1]
  241. if nextDir ~= CalcActorDirByPos(nextPos, next2Pos) or not self:checkMovePosEnable(next2Pos) then
  242. return nextPos, moveStep
  243. end
  244. -- 2 step only.
  245. moveStep = 2
  246. if CheckRunStep() <= 2 or currPathPoint <= 2 then
  247. return next2Pos, moveStep
  248. end
  249. -- check third point
  250. local next3Pos = pathPoints[currPathPoint - 2]
  251. if nextDir ~= CalcActorDirByPos(next2Pos, next3Pos) or not self:checkMovePosEnable(next3Pos) then
  252. return next2Pos, moveStep
  253. end
  254. moveStep = 3
  255. return next3Pos, moveStep
  256. end
  257. function PathFindController:CheckNextMovePosAble()
  258. local player = global.gamePlayerController:GetMainPlayer()
  259. if not player then
  260. return -1
  261. end
  262. local inputProxy = global.Facade:retrieveProxy(global.ProxyTable.PlayerInputProxy)
  263. local pathPoints = inputProxy:GetPathFindPoints()
  264. local currPathPoint = inputProxy:GetCurrPathPoint()
  265. if currPathPoint <= 0 then
  266. return 0
  267. end
  268. local nextPoint, moveStep = self:checkNextMovePos(player, pathPoints, currPathPoint)
  269. if nextPoint then
  270. -- walk, check next point has player/monster/npc
  271. if moveStep == 1 and not self:checkAbleToWalk(nextPoint) then
  272. return -1
  273. end
  274. return 1
  275. end
  276. return -1
  277. end
  278. function PathFindController:checkAbleToWalkByActor(actor)
  279. if not actor then
  280. return true
  281. end
  282. -- 死亡状态 可穿
  283. if actor:IsDie() or actor:IsDeath() or actor:IsCave() then
  284. return true
  285. end
  286. -- 该actor 可穿
  287. if actor:IsPlayer() or actor:IsMonster() or actor:IsNPC() then
  288. if actor:IsThroughAble() then
  289. return true
  290. end
  291. end
  292. local MapProxy = global.Facade:retrieveProxy(global.ProxyTable.Map)
  293. -- 地图设置 可穿
  294. if actor:IsPlayer() then
  295. if MapProxy:IsAbleWalkCrossPlayer() then
  296. return true
  297. end
  298. if MapProxy:IsCrossAllSafeArea() and actor:GetInSafeZone() then
  299. return true
  300. end
  301. if MapProxy:IsCrossPlayerEnable() then
  302. return true
  303. end
  304. end
  305. -- 地图设置 可穿
  306. if actor:IsMonster() then
  307. -- 引擎不区分安全区 走跑分开检测
  308. -- if actor:GetInSafeZone() then
  309. -- if not MapProxy:IsFirbidCrossNpcSafeArea() then
  310. -- return true
  311. -- end
  312. -- end
  313. if MapProxy:IsAbleWalkCrossMonster() then
  314. return true
  315. end
  316. end
  317. -- 地图设置 可穿
  318. if actor:IsNPC() then
  319. if MapProxy:IsCrossNpcEnable() then
  320. return true
  321. end
  322. if MapProxy:IsCrossAllSafeArea() and actor:GetInSafeZone() then
  323. return true
  324. end
  325. end
  326. return false
  327. end
  328. function PathFindController:checkAbleToWalk(nextPoint)
  329. -- 管理员不受控制
  330. local MapProxy = global.Facade:retrieveProxy(global.ProxyTable.Map)
  331. if MapProxy:IsAdmin() and MapProxy:IsGMRunAll() then
  332. return true
  333. end
  334. local actors = global.actorManager:GetMonsterActorByMapXY(nextPoint.x, nextPoint.y, true)
  335. for i, actor in ipairs(actors) do
  336. if actor and false == self:checkAbleToWalkByActor(actor) then
  337. return false
  338. end
  339. end
  340. actors = global.actorManager:GetPlayerActorByMapXY(nextPoint.x, nextPoint.y, true)
  341. for i, actor in ipairs(actors) do
  342. if actor and false == self:checkAbleToWalkByActor(actor) then
  343. return false
  344. end
  345. end
  346. actors = global.actorManager:GetNPCActorByMapXY(nextPoint.x, nextPoint.y, true)
  347. for i, actor in ipairs(actors) do
  348. if actor and false == self:checkAbleToWalkByActor(actor) then
  349. return false
  350. end
  351. end
  352. return true
  353. end
  354. -- 检测直线阻挡是否存在npc player monster
  355. function PathFindController:checkActorLimitObstacle(srcPos,dstPos)
  356. local mapData = global.sceneManager:GetMapData2DPtr()
  357. if not mapData then
  358. return false
  359. end
  360. local inputProxy = global.Facade:retrieveProxy(global.ProxyTable.PlayerInputProxy)
  361. local moveDir = inputProxy:calcMapDirection(dstPos,srcPos)
  362. local distance = inputProxy:calcMapDistance(dstPos,srcPos)
  363. local around =
  364. {
  365. { 0, -1 }, -- ORIENT_U
  366. { 1, -1 }, -- ORIENT_RU
  367. { 1, 0 }, -- ORIENT_R
  368. { 1, 1 }, -- ORIENT_RB
  369. { 0, 1 }, -- ORIENT_B
  370. {-1, 1 }, -- ORIENT_LB
  371. {-1, 0 }, -- ORIENT_L
  372. {-1, -1 }, -- ORIENT_LU
  373. }
  374. local function checkActors(actors, ncount, pos)
  375. for i = 1, ncount do
  376. local actor = actors[i]
  377. if actor and actor:GetMapX() == pos.x and actor:GetMapY() == pos.y then
  378. return actor
  379. end
  380. end
  381. return nil
  382. end
  383. local ret = false
  384. local target = nil
  385. local actors = {}
  386. local ncount = 0
  387. for i=1,distance do
  388. srcPos.x = srcPos.x + around[moveDir+1][1]
  389. srcPos.y = srcPos.y + around[moveDir+1][2]
  390. if mapData:isObstacle(srcPos.x, srcPos.y) == 1 then
  391. -- npc
  392. if not target then
  393. actors, ncount = global.npcManager:GetNpcInCurrViewField()
  394. target = checkActors(actors, ncount, srcPos)
  395. end
  396. -- player
  397. if not target then
  398. actors, ncount = global.playerManager:FindPlayerInCurrViewField()
  399. target = checkActors(actors, ncount, srcPos)
  400. end
  401. -- monster
  402. if not target then
  403. actors, ncount = global.monsterManager:FindMonsterInCurrViewField(false, false)
  404. target = checkActors(actors, ncount, srcPos)
  405. end
  406. if target then
  407. ret = true
  408. break
  409. end
  410. end
  411. end
  412. return ret
  413. end
  414. --------------------------------------------------------------------------------------------
  415. return PathFindController