AStar.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. window.AStar = {};
  2. var Constants = require('Constants');
  3. var startMap =
  4. [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  5. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  6. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,],
  7. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,],
  8. [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,],
  9. [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,],
  10. [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,],
  11. [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  12. [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  13. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  14. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  15. [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,],
  16. [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,],
  17. [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,],
  18. [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,],
  19. [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,],
  20. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  21. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  22. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  23. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]];
  24. //全局变量用来调整的算法
  25. //不必要的实时使用
  26. var map, ctx, allowDiagonals, diagonalCost, dotTiebreaker, badSorting, nodesSearched, start,
  27. nextDraw = [];
  28. //初始化节点地图
  29. AStar.Init = function init() {
  30. map = new Array;
  31. for (var i = 0; i < Constants.TileMapWith; i++) {
  32. map[i] = new Array;
  33. for (var j = 0; j < Constants.TileMapWith; j++) {
  34. //第三个参数 startMap[i][j]
  35. map[i][j] = new Node(i, j, 1);
  36. }
  37. }
  38. nodesSearched = 0;
  39. // cc.log('map', map);
  40. }
  41. AStar.setMapSolid = function (x, y, isSolid) {
  42. map[x][y].solid = isSolid;
  43. // if (x!==29&&x!==30&&isSolid == 0)
  44. // console.log(x, y, isSolid);
  45. }
  46. AStar.getMap = function () {
  47. return map;
  48. }
  49. AStar.setStart = function (value) {
  50. start = value;
  51. }
  52. // 插入排序以获得更好的优先级队列性能
  53. Array.prototype.insertSorted = function (v, sortFn) {
  54. if (this.length < 1 || sortFn(v, this[this.length - 1]) >= 0) {
  55. this.push(v);
  56. return this;
  57. }
  58. for (var i = this.length - 2; i >= 0; --i) {
  59. if (sortFn(v, this[i]) >= 0) {
  60. this.splice(i + 1, 0, v);
  61. return this;
  62. }
  63. }
  64. this.splice(0, 0, v);
  65. return this;
  66. }
  67. // for comparison this insert sort uses > not >= thus inserting new nodes nearer the back
  68. // this provides much worse searching
  69. Array.prototype.insertSorted2 = function (v, sortFn) {
  70. if (this.length < 1 || sortFn(v, this[this.length - 1]) > 0) {
  71. this.push(v);
  72. return this;
  73. }
  74. for (var i = this.length - 2; i >= 0; --i) {
  75. if (sortFn(v, this[i]) > 0) {
  76. this.splice(i + 1, 0, v);
  77. return this;
  78. }
  79. }
  80. this.splice(0, 0, v);
  81. return this;
  82. }
  83. //初始化信息
  84. // allowDiagonals true 是开启八方向,false 是开启四方向
  85. // diagonalCost true 是对角线,false是关闭
  86. // dotTiebreaker
  87. // badSorting 添加新节点或重新插入旧节点
  88. AStar.setInitInfo = function setInfo(tallowDiagonals, tdiagonalCost, tdotTiebreaker, tbadSorting) {
  89. //允许对角线
  90. allowDiagonals = tallowDiagonals;
  91. //调整对角线成本
  92. diagonalCost = tdiagonalCost;
  93. //点积短路器
  94. dotTiebreaker = tdotTiebreaker;
  95. //Prefer new nodes
  96. //首选新节点?
  97. badSorting = tbadSorting;
  98. // cc.log('this.allowDiagonals=', allowDiagonals,
  99. // 'this.diagonalCost=', diagonalCost,
  100. // 'this.dotTiebreaker=', dotTiebreaker,
  101. // 'this.badSorting=', badSorting)
  102. }
  103. //算法里面的节点
  104. function Node(x, y, t) {
  105. this.x = x;
  106. this.y = y;
  107. this.solid = t;
  108. this.coord = x + ":" + y;
  109. this.neighbours = function (goal) {
  110. var n = [];
  111. var dir = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [-1, 1], [1, -1], [-1, -1]];
  112. for (var i = 0; i < (allowDiagonals ? 8 : 4); ++i) {
  113. //判断是否在边界外
  114. if (this.x + dir[i][0] < 0 || this.x + dir[i][0] > Constants.TileMapWith - 1) continue;
  115. if (this.y + dir[i][1] < 0 || this.y + dir[i][1] > Constants.TileMapWith - 1) continue;
  116. var p = map[this.x + dir[i][0]][this.y + dir[i][1]];
  117. if (p.solid && p != goal) continue;
  118. n.push(p);
  119. }
  120. // console.log('neighbours', n);
  121. return n;
  122. }
  123. }
  124. function h(a, b) {
  125. var cross = 0;
  126. if (dotTiebreaker) {
  127. var dx1 = a.x - b.x
  128. var dy1 = a.y - b.y
  129. var dx2 = start.x - b.x
  130. var dy2 = start.y - b.y
  131. var cross = Math.abs(dx1 * dy2 - dx2 * dy1)
  132. }
  133. if (allowDiagonals) {
  134. var straight = Math.abs(Math.abs(a.x - b.x) - Math.abs(a.y - b.y));
  135. var diagonal = Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) - straight;
  136. return straight + diagonalCost * diagonal + cross * 0.001;
  137. //return Math.max(Math.abs(a.x-b.x), Math.abs(a.y-b.y)); simple version
  138. }
  139. return Math.abs(a.x - b.x) + Math.abs(a.y - b.y) + cross * 0.001;
  140. }
  141. AStar.setGraphics = function (graphics) {
  142. ctx = graphics;
  143. },
  144. AStar.pathFind = function pathFind(x, y, x2, y2) {
  145. nextDraw = [];
  146. var start = map[x][y];
  147. var goal = map[x2][y2];
  148. var closed = {};
  149. var open = [start];
  150. var g_score = {}; // 从最优路径出发的距离
  151. var f_score = {}; // 通过节点估计从目标到目标的距离
  152. g_score[start.coord] = 0;
  153. f_score[start.coord] = h(start, goal);
  154. var cameFrom = {};
  155. var sortFn = function (b, a) { return f_score[a.coord] - f_score[b.coord]; };
  156. while (open.length > 0) {
  157. var node = open.pop(); //F值最低的节点
  158. // cc.log('node==',node);
  159. if (node == goal) {
  160. var path = [goal];
  161. while (cameFrom[path[path.length - 1].coord]) {
  162. path.push(cameFrom[path[path.length - 1].coord])
  163. }
  164. return path;
  165. }
  166. closed[node.coord] = true;
  167. var neighbours = node.neighbours(goal);
  168. for (var i = 0, c = neighbours.length; i < c; ++i) {
  169. var next = neighbours[i];
  170. if (closed[next.coord]) continue;
  171. var diagonal = next.x != node.x && next.y != node.y;
  172. var temp_g_score = g_score[node.coord] + (diagonal ? diagonalCost : 1);
  173. // cc.log('temp_g_score',temp_g_score);
  174. var isBetter = false;
  175. var idx = open.indexOf(next);
  176. if (idx < 0) {
  177. isBetter = true;
  178. nodesSearched++;
  179. }
  180. else if (temp_g_score < g_score[next.coord]) {
  181. open.splice(idx, 1); // remove old node
  182. isBetter = true;
  183. }
  184. if (isBetter) {
  185. cameFrom[next.coord] = node;
  186. g_score[next.coord] = temp_g_score;
  187. f_score[next.coord] = g_score[next.coord] + h(next, goal);
  188. // add the new node or reinsert the old node
  189. if (badSorting) open.insertSorted2(next, sortFn);
  190. else open.insertSorted(next, sortFn);
  191. // drawing
  192. if (ctx) {
  193. var s = Math.floor(g_score[next.coord] * 4);
  194. ctx.fillColor = new cc.Color(255 - s, 255, s, 255);
  195. ctx.rect(next.x * 10, next.y * 10, 10, 10);
  196. ctx.stroke();
  197. ctx.fill();
  198. }
  199. }
  200. }
  201. }
  202. // fail
  203. return [];
  204. }
  205. function setIndex(next) {
  206. let index = 50 * next.y + next.x;
  207. nextDraw.push(index);
  208. }
  209. function isHasIndex(next) {
  210. let index = 50 * next.y + next.x;
  211. let ishas = false;
  212. for (let i = 0; i < nextDraw.length; i++) {
  213. if (index == nextDraw[i]) {
  214. ishas = true;
  215. break;
  216. }
  217. }
  218. return ishas;
  219. }
  220. AStar.Init();