aStar.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import { tableData } from "./DataConfig"
  2. import { bindShowFindPos } from "./game"
  3. const enum DirectionType {
  4. FOURTH_DIR,
  5. EIGHT_DIR
  6. }
  7. export class AStartStep {
  8. g: number = 0
  9. h: number = 0
  10. private _f: number
  11. get f() {
  12. return this.g + this.h
  13. }
  14. set f(n) {
  15. this._f = n
  16. }
  17. pos: cc.Vec2 = cc.v2()
  18. last: AStartStep = null
  19. constructor(MapPos) {
  20. // if(arguments.length>0 && arguments[0] instanceof cc.Vec2){
  21. // this.pos=arguments[0]
  22. // }
  23. this.pos = MapPos
  24. }
  25. equalTo(other: AStartStep) {
  26. if (other instanceof AStartStep) {
  27. return this.pos.x === other.pos.x && this.pos.y === other.pos.y
  28. }
  29. }
  30. }
  31. export class AStar {
  32. //默认是 四方向的
  33. _moveDirection = DirectionType.FOURTH_DIR
  34. _isShowProcess = false
  35. _openList: AStartStep[]
  36. _closeList: AStartStep[]
  37. constructor() {
  38. this._openList = []
  39. this._closeList = []
  40. }
  41. private findeIndexOfStepList = (v: cc.Vec2, stepList: AStartStep[]) => {
  42. for (let i = 0; i < stepList.length; i++) {
  43. if (v.x === stepList[i].pos.x && v.y === stepList[i].pos.y)
  44. return i
  45. }
  46. return -1
  47. }
  48. insetStepToOpen(step: AStartStep) {
  49. let i = 0
  50. for (; i < this._openList.length; ++i) {
  51. if (step.f <= this._openList[i].f) {
  52. break
  53. }
  54. }
  55. // cc.log('---ToOpen----',i,step.f,step.pos.x,this._openList[i]?.f,this._openList[i]?.pos.x)
  56. this._openList.splice(i, 0, step)
  57. }
  58. setIsShowProcess(_isShowProcess: boolean) {
  59. this._isShowProcess = _isShowProcess
  60. }
  61. changeDeriction() {
  62. this._moveDirection = this._moveDirection === DirectionType.EIGHT_DIR ? DirectionType.FOURTH_DIR : DirectionType.EIGHT_DIR
  63. }
  64. //每个砖块的消耗
  65. _costToMoveStep(left, right) {
  66. // 不是直走
  67. return (left.x !== right.x) && left.y !== right.y ? 14 : 10
  68. }
  69. _getH(current, finish) {
  70. return (Math.abs(current.x - finish.x) + Math.abs(current.y - finish.y)) * 10
  71. }
  72. // 判断是否
  73. // 获得可加入的点 zhe一步不管是否已经加入到开放列表,只管周围是否可通行
  74. _getNextCanMovePos(currentPos) {
  75. let funPushPos = (pos, list) => {
  76. if (tableData[pos.y][pos.x] === 0) {
  77. list.push(pos)
  78. }
  79. }
  80. let results = []
  81. let left = cc.v2(currentPos.x - 1, currentPos.y)
  82. if (left.x >= 0) {
  83. // 左三
  84. funPushPos(left, results)
  85. if (this._moveDirection === DirectionType.EIGHT_DIR) {
  86. let leftTop = cc.v2(currentPos.x - 1, currentPos.y + 1)
  87. if (leftTop.y < tableData.length) {
  88. funPushPos(leftTop, results)
  89. }
  90. let leftBottom = cc.v2(currentPos.x - 1, currentPos.y - 1)
  91. if (leftBottom.y >= 0) {
  92. funPushPos(leftBottom, results)
  93. }
  94. }
  95. }
  96. // 右三
  97. let right = cc.v2(currentPos.x + 1, currentPos.y)
  98. if (right.x < tableData[0].length) {
  99. // 左三
  100. funPushPos(right, results)
  101. if (this._moveDirection === DirectionType.EIGHT_DIR) {
  102. let rightTop = cc.v2(currentPos.x + 1, currentPos.y + 1)
  103. if (rightTop.y < tableData.length) {
  104. funPushPos(rightTop, results)
  105. }
  106. let rightBottom = cc.v2(currentPos.x + 1, currentPos.y - 1)
  107. if (rightBottom.y >= 0) {
  108. funPushPos(rightBottom, results)
  109. }
  110. }
  111. }
  112. // 上下
  113. let top = cc.v2(currentPos.x, currentPos.y + 1)
  114. if (top.y < tableData.length) {
  115. funPushPos(top, results)
  116. }
  117. let bottom = cc.v2(currentPos.x, currentPos.y - 1)
  118. if (bottom.y >= 0) {
  119. funPushPos(bottom, results)
  120. }
  121. return results
  122. }
  123. async findePaths(start, finish) {
  124. // cc.log('----start--finish-',start,finish)
  125. this._openList = []
  126. this._closeList = []
  127. let tempOpenPos = []
  128. let paths = []
  129. this._openList.push(new AStartStep(start))
  130. let pathFound = false
  131. do {
  132. let currentStep = this._openList.shift()
  133. this._closeList.push(currentStep)
  134. if (this._isShowProcess) {
  135. await this.sleep(1)
  136. this.findPos(currentStep.pos)
  137. }
  138. // cc.log('----currentStep-',currentStep.pos.x,currentStep.pos.y)
  139. if (currentStep.pos.x === finish.x && currentStep.pos.y === finish.y) {
  140. pathFound = true
  141. do {
  142. // to do 测试效率
  143. paths.unshift(currentStep.pos)
  144. currentStep = currentStep.last
  145. } while (currentStep !== null)
  146. break
  147. }
  148. // 根据当前点,找到下一个点
  149. let canMoveList = this._getNextCanMovePos(currentStep.pos)
  150. // 找到需要加列表的点加入后比较
  151. for (let i = 0; i < canMoveList.length; ++i) {
  152. let pos1 = canMoveList[i]
  153. if (this.findeIndexOfStepList(pos1, this._closeList) != -1) {
  154. canMoveList.splice(i, 1)
  155. i--;
  156. continue
  157. }
  158. // 不在的话,判断是否放入开放列表中
  159. let step = new AStartStep(pos1)
  160. let costMove = this._costToMoveStep(pos1, currentStep.pos)
  161. let openIndex = this.findeIndexOfStepList(pos1, this._openList)
  162. if (openIndex === -1) {
  163. step.last = currentStep
  164. step.g = currentStep.g + costMove
  165. step.h = this._getH(pos1, finish)
  166. this.insetStepToOpen(step)
  167. tempOpenPos.push([currentStep.pos.x, currentStep.pos.y])
  168. } else {
  169. // 如果open列表中有的,直接用、
  170. let stepOp = this._openList[openIndex]
  171. // 也可以用f
  172. if (currentStep.g + costMove < stepOp.g) {
  173. stepOp.g = currentStep.g + costMove;
  174. stepOp.last = currentStep
  175. // 先删除 再插入,因为插入事可以排序
  176. this._openList.splice(openIndex, 1)
  177. this.insetStepToOpen(stepOp)
  178. }
  179. }
  180. }
  181. } while (this._openList.length > 0)
  182. return [pathFound, paths, tempOpenPos, this._closeList]
  183. }
  184. findPos(pos: cc.Vec2) {
  185. // cc.log('--findPos---',pos)
  186. }
  187. private async sleep(time) {
  188. return new Promise((resolve) => {
  189. setTimeout(resolve, time);
  190. });
  191. }
  192. }