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.
 
 
 

460 lines
8.4 KiB

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