You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

443 line
8.2 KiB

  1. define([
  2. 'js/misc/pathfinder'
  3. ], function (
  4. pathfinder
  5. ) {
  6. var sqrt = Math.sqrt.bind(Math);
  7. var ceil = Math.ceil.bind(Math);
  8. var random = Math.random.bind(Math);
  9. return {
  10. graph: null,
  11. collisionMap: null,
  12. cells: [],
  13. width: 0,
  14. height: 0,
  15. init: function (collisionMap) {
  16. this.collisionMap = collisionMap;
  17. this.width = collisionMap.length;
  18. this.height = collisionMap[0].length;
  19. this.cells = _.get2dArray(this.width, this.height, 'array');
  20. this.graph = new pathfinder.Graph(collisionMap, {
  21. diagonal: true
  22. });
  23. },
  24. addRegion: function (obj) {
  25. var lowX = obj.x;
  26. var lowY = obj.y;
  27. var highX = lowX + obj.width;
  28. var highY = lowY + obj.height;
  29. var cells = this.cells;
  30. for (var i = lowX; i <= highX; i++) {
  31. var row = cells[i];
  32. for (var j = lowY; j <= highY; j++) {
  33. row[j].push(obj);
  34. }
  35. }
  36. },
  37. addObject: function (obj, x, y, fromX, fromY) {
  38. var row = this.cells[x];
  39. if (!row)
  40. return;
  41. var cell = row[y];
  42. if (!cell)
  43. return;
  44. var cLen = cell.length;
  45. for (var i = 0; i < cLen; i++) {
  46. var c = cell[i];
  47. //If we have fromX and fromY, check if the target cell doesn't contain the same obj (like a notice area)
  48. if ((c.width) && (fromX)) {
  49. if ((fromX < c.x) || (fromY < c.y) || (fromX >= c.x + c.width) || (fromY >= c.y + c.height)) {
  50. c.collisionEnter(obj);
  51. obj.collisionEnter(c);
  52. }
  53. } else {
  54. c.collisionEnter(obj);
  55. obj.collisionEnter(c);
  56. }
  57. }
  58. cell.push(obj);
  59. return true;
  60. },
  61. removeObject: function (obj, x, y, toX, toY) {
  62. var row = this.cells[x];
  63. if (!row)
  64. return;
  65. var cell = row[y];
  66. if (!cell)
  67. return;
  68. var oId = obj.id;
  69. var cLen = cell.length;
  70. for (var i = 0; i < cLen; i++) {
  71. var c = cell[i];
  72. if (c.id != oId) {
  73. //If we have toX and toY, check if the target cell doesn't contain the same obj (like a notice area)
  74. if ((c.width) && (toX)) {
  75. if ((toX < c.x) || (toY < c.y) || (toX >= c.x + c.width) || (toY >= c.y + c.height)) {
  76. c.collisionExit(obj);
  77. obj.collisionExit(c);
  78. }
  79. } else {
  80. c.collisionExit(obj);
  81. obj.collisionExit(c);
  82. }
  83. } else {
  84. cell.splice(i, 1);
  85. i--;
  86. cLen--;
  87. }
  88. }
  89. },
  90. isValid: function (x, y) {
  91. var row = this.cells[x];
  92. if ((!row) || (row.length <= y) || (!this.graph.grid[x][y]))
  93. return false;
  94. else
  95. return true;
  96. },
  97. getCell: function (x, y) {
  98. var row = this.cells[x];
  99. if (!row)
  100. return [];
  101. var cell = row[y];
  102. if (!cell)
  103. return [];
  104. return cell;
  105. },
  106. getArea: function (x1, y1, x2, y2, filter) {
  107. var width = this.width;
  108. var height = this.height;
  109. x1 = ~~x1;
  110. y1 = ~~y1;
  111. x2 = ~~x2;
  112. y2 = ~~y2;
  113. if (x1 < 0)
  114. x1 = 0;
  115. else if (x2 >= width)
  116. x2 = width - 1;
  117. if (y1 < 0)
  118. y1 = 0;
  119. else if (y2 >= height)
  120. y2 = height - 1;
  121. var cells = this.cells;
  122. var grid = this.graph.grid;
  123. var result = [];
  124. for (var i = x1; i <= x2; i++) {
  125. var row = cells[i];
  126. var gridRow = grid[i];
  127. for (var j = y1; j <= y2; j++) {
  128. if (!gridRow[j])
  129. continue;
  130. var cell = row[j];
  131. var cLen = cell.length;
  132. for (var k = 0; k < cLen; k++) {
  133. var c = cell[k];
  134. if (filter) {
  135. if (filter(c))
  136. result.push(c);
  137. } else
  138. result.push(c);
  139. }
  140. }
  141. }
  142. return result;
  143. },
  144. getOpenCellInArea: function (x1, y1, x2, y2) {
  145. var width = this.width;
  146. var height = this.height;
  147. x1 = ~~x1;
  148. y1 = ~~y1;
  149. x2 = ~~x2;
  150. y2 = ~~y2;
  151. if (x1 < 0)
  152. x1 = 0;
  153. else if (x2 >= width)
  154. x2 = width - 1;
  155. if (y1 < 0)
  156. y1 = 0;
  157. else if (y2 >= height)
  158. y2 = height - 1;
  159. var cells = this.cells;
  160. var grid = this.graph.grid;
  161. var result = [];
  162. for (var i = x1; i <= x2; i++) {
  163. var row = cells[i];
  164. var gridRow = grid[i];
  165. for (var j = y1; j <= y2; j++) {
  166. if (!gridRow[j])
  167. continue;
  168. var cell = row[j];
  169. if (cell.length == 0) {
  170. return {
  171. x: i,
  172. y: j
  173. };
  174. }
  175. }
  176. }
  177. return result;
  178. },
  179. getPath: function (from, to) {
  180. var graph = this.graph;
  181. var grid = graph.grid;
  182. if (!to) {
  183. to = {
  184. x: ~~(random() * grid.length),
  185. y: ~~(random() * grid[0].length)
  186. };
  187. }
  188. var fromX = ~~from.x;
  189. var fromY = ~~from.y;
  190. if ((!grid[fromX]) || (grid[fromX].length <= fromY) || (fromX < 0) || (fromY < 0))
  191. return [];
  192. var toX = ~~to.x;
  193. var toY = ~~to.y;
  194. if ((!grid[toX]) || (grid[toX].length <= toY) || (toX < 0) || (toY < 0))
  195. return [];
  196. var path = pathfinder.astar.search(graph, {
  197. x: fromX,
  198. y: fromY
  199. }, {
  200. x: toX,
  201. y: toY
  202. }, {
  203. closest: true
  204. });
  205. return path;
  206. },
  207. isTileBlocking: function (x, y, mob, obj) {
  208. if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height))
  209. return true;
  210. x = ~~x;
  211. y = ~~y;
  212. var node = this.graph.grid[x][y];
  213. return ((!node) || (node.weight == 0));
  214. },
  215. isCellOpen: function (x, y) {
  216. if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height))
  217. return true;
  218. return (this.cells[x][y].length == 0);
  219. },
  220. hasLos: function (fromX, fromY, toX, toY) {
  221. if ((fromX < 0) || (fromY < 0) || (fromX >= this.width) | (fromY >= this.height) || (toX < 0) || (toY < 0) || (toX >= this.width) | (toY >= this.height))
  222. return false;
  223. var graphGrid = this.graph.grid;
  224. if ((!graphGrid[fromX][fromY]) || (!graphGrid[toX][toY]))
  225. return false;
  226. var dx = toX - fromX;
  227. var dy = toY - fromY;
  228. var distance = sqrt((dx * dx) + (dy * dy));
  229. dx /= distance;
  230. dy /= distance;
  231. fromX += 0.5;
  232. fromY += 0.5;
  233. distance = ceil(distance);
  234. var x = 0;
  235. var y = 0;
  236. for (var i = 0; i < distance; i++) {
  237. fromX += dx;
  238. fromY += dy;
  239. x = ~~fromX;
  240. y = ~~fromY;
  241. if (!graphGrid[x][y])
  242. return false;
  243. else if ((x == toX) && (y == toY))
  244. return true;
  245. }
  246. return true;
  247. },
  248. getClosestPos: function (fromX, fromY, toX, toY, target) {
  249. var tried = {};
  250. var hasLos = this.hasLos.bind(this, toX, toY);
  251. var width = this.width;
  252. var height = this.height;
  253. var collisionMap = this.collisionMap;
  254. var cells = this.cells;
  255. var reverseX = (fromX > toX);
  256. var reverseY = (fromY > toY);
  257. for (var c = 1; c <= 10; c++) {
  258. var x1 = toX - c;
  259. var y1 = toY - c;
  260. var x2 = toX + c;
  261. var y2 = toY + c;
  262. var lowX, lowY, highX, highY, incX, incY;
  263. if (reverseX) {
  264. incX = -1;
  265. lowX = x2;
  266. highX = x1 - 1;
  267. } else {
  268. incX = 1;
  269. lowX = x1;
  270. highX = x2 + 1;
  271. }
  272. if (reverseY) {
  273. incY = -1;
  274. lowY = y2;
  275. highY = y1 - 1;
  276. } else {
  277. incY = 1;
  278. lowY = y1;
  279. highY = y2 + 1;
  280. }
  281. for (var i = lowX; i != highX; i += incX) {
  282. if ((i < 0) || (i >= width))
  283. continue;
  284. var row = collisionMap[i];
  285. var cellRow = cells[i];
  286. var t = tried[i];
  287. if (!t) {
  288. t = tried[i] = {};
  289. }
  290. for (var j = lowY; j != highY; j += incY) {
  291. if (t[j])
  292. continue;
  293. t[j] = 1;
  294. if (
  295. ((i == toX) && (j == toY)) ||
  296. ((j < 0) || (j >= height)) ||
  297. (row[j])
  298. )
  299. continue;
  300. var cell = cellRow[j];
  301. var cLen = cell.length;
  302. var blocking = false;
  303. for (var k = 0; k < cLen; k++) {
  304. var aggro = cell[k].aggro;
  305. if (aggro) {
  306. blocking = aggro.list.some(a => a.obj == target);
  307. if (blocking)
  308. break;
  309. }
  310. }
  311. if (blocking)
  312. continue;
  313. else if (!hasLos(i, j))
  314. continue;
  315. return {
  316. x: i,
  317. y: j
  318. };
  319. }
  320. }
  321. }
  322. },
  323. mobsCollide: function (x, y, obj) {
  324. if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height))
  325. return true;
  326. var cell = this.cells[x][y];
  327. var cLen = cell.length;
  328. if (cLen == 1)
  329. return false;
  330. var found = false;
  331. for (var i = 0; i < cLen; i++) {
  332. var c = cell[i];
  333. if (c.aggro) {
  334. if ((!found) && (c == obj))
  335. found = true;
  336. else
  337. return true;
  338. }
  339. }
  340. return false;
  341. },
  342. setCollision: function (x, y, collides) {
  343. var node = this.graph.grid[x][y];
  344. if (!node) {
  345. var grid = this.graph.grid;
  346. node = grid[x][y] = new pathfinder.gridNode(x, y, collides ? 0 : 1);
  347. }
  348. node.weight = collides ? 0 : 1;
  349. }
  350. };
  351. });