Level.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. package me.hammerle.supersnuvi.gamelogic;
  2. import java.io.File;
  3. import java.util.HashMap;
  4. import java.util.LinkedList;
  5. import java.util.List;
  6. import java.util.TreeSet;
  7. import java.util.stream.Collectors;
  8. import me.hammerle.snuviengine.api.Shader;
  9. import me.hammerle.snuviengine.api.Texture;
  10. import me.hammerle.snuviengine.api.TextureRenderer;
  11. import me.hammerle.supersnuvi.Game;
  12. import me.hammerle.supersnuvi.entity.Entity;
  13. import me.hammerle.supersnuvi.entity.EntityBuilder;
  14. import me.hammerle.supersnuvi.tiles.Location;
  15. import me.hammerle.supersnuvi.tiles.StartTile;
  16. import me.hammerle.supersnuvi.tiles.Tile;
  17. import me.hammerle.supersnuvi.util.CollisionLine;
  18. import me.hammerle.supersnuvi.util.CollisionObject;
  19. import me.hammerle.supersnuvi.util.Utils;
  20. public final class Level
  21. {
  22. private final static float ERROR = 1f / 65536f;
  23. public final static Texture TILES = new Texture("resources/tiles.png");
  24. private final static Texture GUI = new Texture("resources/gui.png");
  25. private final static TextureRenderer GUI_RENDERER = new TextureRenderer(60);
  26. private final boolean worldLoaded;
  27. private final LevelData data;
  28. private final String fileName;
  29. private final String name;
  30. private final HashMap<Integer, Entity> entities = new HashMap<>();
  31. private final LinkedList<Entity> spawnQueue = new LinkedList<>();
  32. private Entity hero;
  33. private int entityCounter = 0;
  34. private boolean shouldReset = false;
  35. private boolean done = true; // this will be reseted in resetLevel()
  36. private int souls;
  37. private int maxSouls;
  38. private float time = 0.0f;
  39. private float cameraX = 0.0f;
  40. private float cameraY = 0.0f;
  41. private float oldCameraX = 0.0f;
  42. private float oldCameraY = 0.0f;
  43. private final int meshSize = 16;
  44. private final int meshLayers;
  45. private final int meshWidth;
  46. private final int meshHeight;
  47. private final TextureRenderer[][][] meshes;
  48. //private int tries = 7;
  49. private TreeSet<Point> spawns = new TreeSet<>();
  50. public Level(File f)
  51. {
  52. this.data = new LevelData(f);
  53. this.worldLoaded = data.load();
  54. if(worldLoaded)
  55. {
  56. this.name = data.getString("name", "error");
  57. meshLayers = data.getLayers() - 1;
  58. meshWidth = (int) Math.ceil((double) data.getWidth() / meshSize);
  59. meshHeight = (int) Math.ceil((double) data.getHeight() / meshSize);
  60. meshes = new TextureRenderer[meshLayers][meshWidth][meshHeight];
  61. for(int l = 0; l < meshLayers; l++)
  62. {
  63. for(int mx = 0; mx < meshWidth; mx++)
  64. {
  65. for(int my = 0; my < meshHeight; my++)
  66. {
  67. meshes[l][mx][my] = new TextureRenderer(meshSize * meshSize * 2);
  68. }
  69. }
  70. }
  71. // debug stuff
  72. if(name.equals("00-Tech Demo"))
  73. {
  74. int index = data.getBackgroundIndex();
  75. for(int i = 0; i < 5; i++)
  76. {
  77. data.setTile(index, 3 + i, 7 - i, 300);
  78. }
  79. data.setTile(index, 8, 3, 2);
  80. data.setTile(index, 9, 4, 2);
  81. /*for(int layer = 0; layer <= data.getBackgroundIndex(); layer++)
  82. {
  83. for(int x = 0; x < data.getWidth(); x++)
  84. {
  85. for(int y = 0; y < data.getHeight(); y++)
  86. {
  87. int t = data.getTile(layer, x, y);
  88. if(t < 16)
  89. {
  90. data.setTile(layer, x, y, t + 240);
  91. }
  92. else if(t < 32)
  93. {
  94. data.setTile(layer, x, y, t + 224);
  95. }
  96. }
  97. }
  98. }
  99. index--;
  100. for(int x = 0; x < data.getWidth(); x++)
  101. {
  102. for(int y = 0; y < data.getHeight(); y++)
  103. {
  104. if(data.getTile(index, x, y) == 128)
  105. {
  106. data.setTile(index, x, y, -1);
  107. }
  108. }
  109. }
  110. for(int x = 0; x < 5; x++)
  111. {
  112. for(int y = 0; y < 5; y++)
  113. {
  114. data.setTile(index, x + 6, y + 1, 256 + x + (4 - y) * 5);
  115. }
  116. }*/
  117. }
  118. // end debug stuff
  119. maxSouls = 0;
  120. data.forEachInteractTile((x, y, tile) ->
  121. {
  122. Tile t = Game.get().getTile(tile);
  123. if(t != null)
  124. {
  125. maxSouls += t.getBottleScore();
  126. }
  127. if(tile == StartTile.ID)
  128. {
  129. spawns.add(new Point(x, y - 1));
  130. }
  131. });
  132. data.forEachEntity((x, y, tile) ->
  133. {
  134. if(tile == 1)
  135. {
  136. maxSouls++;
  137. }
  138. }, 0, data.getWidth(), 0, data.getHeight());
  139. }
  140. else
  141. {
  142. this.name = f.getName();
  143. maxSouls = 0;
  144. meshLayers = 0;
  145. meshWidth = 0;
  146. meshHeight = 0;
  147. meshes = new TextureRenderer[0][0][0];
  148. }
  149. fileName = f.getName();
  150. // there must be at least one spawn
  151. if(spawns.isEmpty())
  152. {
  153. spawns.add(new Point(5, 5));
  154. }
  155. resetLevel();
  156. }
  157. // -------------------------------------------------------------------------
  158. // basic stuff
  159. // -------------------------------------------------------------------------
  160. public Entity getHero()
  161. {
  162. return hero;
  163. }
  164. public String getFileName()
  165. {
  166. return fileName;
  167. }
  168. public String getName()
  169. {
  170. return name;
  171. }
  172. public void finishLevel()
  173. {
  174. shouldReset = true;
  175. done = true;
  176. }
  177. public boolean shouldFinish()
  178. {
  179. return done;
  180. }
  181. public boolean shouldReset()
  182. {
  183. return shouldReset;
  184. }
  185. public void scheduleReset()
  186. {
  187. shouldReset = true;
  188. }
  189. public boolean resetLevel()
  190. {
  191. /*boolean dead = false;
  192. if(!done) // hero just died
  193. {
  194. tries--;
  195. if(tries <= 0)
  196. {
  197. tries = 7;
  198. dead = true;
  199. }
  200. }*/
  201. Game.get().resetTiles();
  202. data.activateEntities();
  203. souls = 0;
  204. time = 0.0f;
  205. shouldReset = false;
  206. done = false;
  207. Entity h = spawnHero(true);
  208. hero = h;
  209. entities.clear();
  210. entities.put(entityCounter++, h);
  211. for(int l = 0; l < meshLayers; l++)
  212. {
  213. for(int x = 0; x < meshWidth; x++)
  214. {
  215. for(int y = 0; y < meshHeight; y++)
  216. {
  217. meshes[l][x][y].clear();
  218. }
  219. }
  220. }
  221. return false;
  222. }
  223. public void spawnEntity(Entity ent)
  224. {
  225. spawnQueue.add(ent);
  226. }
  227. public Entity spawnHero(boolean first)
  228. {
  229. Entity h = hero;
  230. Point p;
  231. if(h == null || hero.getX() < 0 || first)
  232. {
  233. // first spawn or out of map, use first spawn
  234. p = spawns.first();
  235. }
  236. else
  237. {
  238. // hero is somewhere in the map, getting last spawn
  239. p = spawns.floor(new Point(Utils.toBlock(hero.getX()), Utils.toBlock(hero.getY())));
  240. if(p == null)
  241. {
  242. p = spawns.first();
  243. }
  244. }
  245. Entity newHero = EntityBuilder.buildHero(this, Utils.toCoord(p.getX()), Utils.toCoord(p.getY()));
  246. // reset the camera
  247. oldCameraX = -getViewX(newHero.getCenterX());
  248. oldCameraY = -getViewY(newHero.getCenterY());
  249. cameraX = oldCameraX;
  250. cameraY = oldCameraY;
  251. return newHero;
  252. }
  253. public void increaseSouls(int score)
  254. {
  255. souls += score;
  256. }
  257. public int getCurrentBottles()
  258. {
  259. return souls;
  260. }
  261. public int getMaxBottles()
  262. {
  263. return maxSouls;
  264. }
  265. public LevelData getData()
  266. {
  267. return data;
  268. }
  269. public float getTime()
  270. {
  271. return time;
  272. }
  273. public int getWidth()
  274. {
  275. return data.getWidth();
  276. }
  277. public int getHeight()
  278. {
  279. return data.getHeight();
  280. }
  281. // -------------------------------------------------------------------------
  282. // tick
  283. // -------------------------------------------------------------------------
  284. public void tick()
  285. {
  286. if(worldLoaded)
  287. {
  288. time += Game.SECS_PER_TICK;
  289. Game.get().tickTiles();
  290. // entity spawn layer
  291. /*int startX = renderer.getFirstVisibleBlockX();
  292. int startY = renderer.getFirstVisibleBlockY();
  293. int endX = Math.min(renderer.getLastVisibleBlockX() + 1, data.getWidth());
  294. int endY = Math.min(renderer.getLastVisibleBlockY() + 1, data.getHeight());
  295. data.forEachEntity((x, y, tile) ->
  296. {
  297. if(tile > 0)
  298. {
  299. data.deactivateEntity(x, y);
  300. Entity ent = EntityBuilder.fromId(tile, this, Utils.toCoord(x), Utils.toCoord(y));
  301. if(ent != null)
  302. {
  303. entities.put(entityCounter++, ent);
  304. }
  305. }
  306. }, startX, endX, startY, endY);*/
  307. // doing entity logic first
  308. entities.values().removeIf(entity ->
  309. {
  310. entity.tick();
  311. return entity.getHealth().shouldDespawn();
  312. });
  313. if(!spawnQueue.isEmpty())
  314. {
  315. spawnQueue.forEach(ent -> entities.put(entityCounter++, ent));
  316. spawnQueue.clear();
  317. }
  318. // calculate new camera position
  319. oldCameraX = cameraX;
  320. oldCameraY = cameraY;
  321. cameraX = -getViewX(hero.getCenterX());
  322. cameraY = -getViewY(hero.getCenterY());
  323. }
  324. }
  325. public String formatBottles(int bottles)
  326. {
  327. char[] c = new char[5];
  328. if(bottles <= 9)
  329. {
  330. c[0] = '0';
  331. c[1] = (char) (bottles + '0');
  332. }
  333. else if(bottles > 99)
  334. {
  335. c[0] = 'X';
  336. c[1] = 'X';
  337. }
  338. else
  339. {
  340. c[0] = (char) ((bottles / 10) + '0');
  341. c[1] = (char) ((bottles % 10) + '0');
  342. }
  343. c[2] = '/';
  344. if(maxSouls <= 9)
  345. {
  346. c[3] = '0';
  347. c[4] = (char) (maxSouls + '0');
  348. }
  349. else if(maxSouls > 99)
  350. {
  351. c[3] = 'X';
  352. c[4] = 'X';
  353. }
  354. else
  355. {
  356. c[3] = (char) ((maxSouls / 10) + '0');
  357. c[4] = (char) ((maxSouls % 10) + '0');
  358. }
  359. return new String(c);
  360. }
  361. public String formatTime(float time)
  362. {
  363. if(time == -1.0f)
  364. {
  365. return "-----";
  366. }
  367. else if(time >= 999.9f)
  368. {
  369. return "999.9";
  370. }
  371. return String.format("%05.1f", time);
  372. }
  373. private float getViewX(float x)
  374. {
  375. x -= Shader.getViewWidth() >> 1;
  376. if(x < 0)
  377. {
  378. return 0;
  379. }
  380. float max = data.getWidth() * Tile.SIZE - Shader.getViewWidth();
  381. if(x > max)
  382. {
  383. return max;
  384. }
  385. return x;
  386. }
  387. private float getViewY(float y)
  388. {
  389. y -= Shader.getViewHeight() >> 1;
  390. if(y < 0)
  391. {
  392. return 0;
  393. }
  394. float max = data.getHeight() * Tile.SIZE - Shader.getViewHeight();
  395. if(y > max)
  396. {
  397. return max;
  398. }
  399. return y;
  400. }
  401. public void updateTile(int layer, int x, int y)
  402. {
  403. if(layer > data.getBackgroundIndex())
  404. {
  405. layer--;
  406. }
  407. meshes[layer][x / meshSize][y / meshSize].clear();
  408. }
  409. public void updateTile(int x, int y)
  410. {
  411. updateTile(data.getBackgroundIndex(), x, y);
  412. }
  413. private void drawMesh(int l, int tl, int mx, int my)
  414. {
  415. TextureRenderer tr = meshes[l][mx][my];
  416. if(!tr.isBuilt())
  417. {
  418. int tsx = mx * meshSize;
  419. int tsy = my * meshSize;
  420. int tex = Math.min(tsx + meshSize, data.getWidth());
  421. int tey = Math.min(tsy + meshSize, data.getHeight());
  422. for(int x = tsx; x < tex; x++)
  423. {
  424. for(int y = tsy; y < tey; y++)
  425. {
  426. Tile t = Game.get().getTile(data.getTile(tl, x, y));
  427. if(t.shouldRender(x, y))
  428. {
  429. float minX = x * Tile.SIZE + t.getOffsetX();
  430. float minY = y * Tile.SIZE + t.getOffsetY();
  431. tr.addRectangle(minX, minY,
  432. minX + t.getWidth(), minY + t.getHeight(),
  433. t.getTextureMinX() + ERROR, t.getTextureMinY() + ERROR,
  434. t.getTextureMaxX() - ERROR, t.getTextureMaxY() - ERROR);
  435. }
  436. }
  437. }
  438. tr.build();
  439. }
  440. meshes[l][mx][my].draw();
  441. }
  442. public void renderTick(float lag)
  443. {
  444. if(worldLoaded)
  445. {
  446. float camX = Utils.interpolate(oldCameraX, cameraX, lag);
  447. float camY = Utils.interpolate(oldCameraY, cameraY, lag);
  448. Shader.translateTo(camX, camY);
  449. Shader.updateMatrix();
  450. int startX = (int) (-camX / (meshSize * Tile.SIZE));
  451. int startY = (int) (-camY / (meshSize * Tile.SIZE));
  452. int endX = (int) Math.ceil((-camX + Shader.getViewWidth()) / (meshSize * Tile.SIZE));
  453. int endY = (int) Math.ceil((-camY + Shader.getViewHeight()) / (meshSize * Tile.SIZE));
  454. startX = Math.min(Math.max(startX, 0), meshWidth);
  455. startY = Math.min(Math.max(startY, 0), meshHeight);
  456. endX = Math.min(Math.max(endX, 0), meshWidth);
  457. endY = Math.min(Math.max(endY, 0), meshHeight);
  458. // background
  459. Shader.setColorEnabled(false);
  460. Shader.setTextureEnabled(true);
  461. Shader.setBlendingEnabled(true);
  462. TILES.bind();
  463. int fromLayer = 0;
  464. int toLayer = data.getBackgroundIndex() + 1;
  465. for(int l = fromLayer; l < toLayer; l++)
  466. {
  467. for(int mx = startX; mx < endX; mx++)
  468. {
  469. for(int my = startY; my < endY; my++)
  470. {
  471. drawMesh(l, l, mx, my);
  472. }
  473. }
  474. }
  475. // entities
  476. entities.values().forEach(entity ->
  477. {
  478. entity.renderTick(lag);
  479. });
  480. // foreground
  481. Shader.setColorEnabled(false);
  482. Shader.setTextureEnabled(true);
  483. Shader.setBlendingEnabled(true);
  484. TILES.bind();
  485. fromLayer = toLayer + 1;
  486. toLayer = data.getLayers();
  487. for(int l = fromLayer; l < toLayer; l++)
  488. {
  489. for(int mx = startX; mx < endX; mx++)
  490. {
  491. for(int my = startY; my < endY; my++)
  492. {
  493. drawMesh(l - 1, l, mx, my);
  494. }
  495. }
  496. }
  497. // menu rendering
  498. Shader.translateTo(0.0f, 0.0f);
  499. Shader.updateMatrix();
  500. // grey background of clock and bottles
  501. float lineHeight = Shader.getFontRenderer().getHeight();
  502. float lineWidth = Shader.getFontRenderer().getWidth();
  503. Shader.setColorEnabled(true);
  504. Shader.setTextureEnabled(false);
  505. Shader.getColorRenderer().drawRectangle(0.0f, 0.0f, (lineWidth * 6.0f) + 10.0f, (lineHeight * 2.0f + 10.0f), 0x77000000);
  506. Shader.setTextureEnabled(true);
  507. float y = 5.0f;
  508. y = Shader.getFontRenderer().drawString(13.0f, y, formatBottles(souls));
  509. Shader.getFontRenderer().drawString(13.0f, y, formatTime(time));
  510. Shader.setColorEnabled(false);
  511. float w = Shader.getViewWidth();
  512. GUI.bind();
  513. GUI_RENDERER.clear();
  514. int scale = Shader.getViewScale();
  515. // bottles
  516. switch(scale)
  517. {
  518. case 1: GUI_RENDERER.addRectangle(6.0f, 4.0f, 12.0f, 14.0f, 0.0f, 0.046875f, 0.01171875f, 0.068359375f); break;
  519. case 2: GUI_RENDERER.addRectangle(6.0f, 4.0f, 12.0f, 14.0f, 0.01171875f, 0.046875f, 0.037109375f, 0.0859375f); break;
  520. default: GUI_RENDERER.addRectangle(6.0f, 4.0f, 12.0f, 14.0f, 0.037109375f, 0.046875f, 0.06640625f, 0.10546875f); break;
  521. }
  522. // clock
  523. switch(scale)
  524. {
  525. case 1: GUI_RENDERER.addRectangle(4.0f, y, 13.0f, y + 9.0f, 0.0f, 0.265625f, 0.017578125f, 0.283203125f); break;
  526. case 2: GUI_RENDERER.addRectangle(4.5f, y, 13.0f, y + 8.5f, 0.017578125f, 0.265625f, 0.05078125f, 0.298828125f); break;
  527. default: GUI_RENDERER.addRectangle(4.666666666f, y, 13.0f, y + 8.333333333f, 0.05078125f, 0.265625f, 0.099609375f, 0.314453125f); break;
  528. }
  529. // gui background
  530. GUI_RENDERER.addRectangle(w - 111.0f, 0.0f, w - 44.0f, 24.0f, 0.0f, 0.0f, 0.130859375f, 0.046875f);
  531. GUI_RENDERER.addRectangle(w - 44.0f, 0.0f, w - 18.0f, 16.0f, 0.130859375f, 0.0f, 0.181640625f, 0.03125f);
  532. GUI_RENDERER.addRectangle(w - 76.0f, 24.0f, w - 45.0f, 57.0f, 0.068359375f, 0.046875f, 0.12890625f, 0.111328125f);
  533. // health mirror
  534. int healthFrame = (int) (hero.getHealth().getHealthPercent() * 7);
  535. float leftMirror = (7 - healthFrame) * 0.0625f;
  536. GUI_RENDERER.addRectangle(w - 39.0f, 8.0f, w - 7.0f, 46.0f, leftMirror, 0.15625f, leftMirror + 0.0625f, 0.23046875f);
  537. // energy
  538. float energy = hero.getEnergy().getEnergyPercent();
  539. float fullEnd = w - 109.0f + 64.0f * energy;
  540. GUI_RENDERER.addRectangle(w - 109.0f, 13.0f, fullEnd, 21.0f, 0.0f, 0.140625f, 0.125f * energy, 0.15625f);
  541. GUI_RENDERER.addRectangle(fullEnd, 13.0f, w - 45.0f, 21.0f, 0.125f * energy, 0.125f, 0.125f, 0.140625f);
  542. // gui foreground
  543. GUI_RENDERER.addRectangle(w - 49.0f, 0.0f, w, 64.0f, 0.201171875f, 0.0f, 0.296875f, 0.125f);
  544. GUI_RENDERER.addRectangle(w - 109.0f, 15.0f, w - 106.0f, 18.0f, 0.15625f, 0.03125f, 0.162109375f, 0.037109375f);
  545. GUI_RENDERER.addRectangle(w - 97.0f, 15.0f, w - 92.0f, 20.0f, 0.1796875f, 0.03125f, 0.189453125f, 0.041015625f);
  546. // health number overlay
  547. GUI_RENDERER.addRectangle(w - 30.0f, 53.0f, w - 12.0f, 62.0f, leftMirror, 0.23828125f, leftMirror + 0.03515625f, 0.255859375f);
  548. GUI_RENDERER.build();
  549. GUI_RENDERER.draw();
  550. // dynamic clock hand
  551. Shader.setColorEnabled(true);
  552. Shader.setTextureEnabled(false);
  553. switch(scale)
  554. {
  555. case 1: Shader.translateTo(8.5f, y + 4.5f); break;
  556. case 2: Shader.translateTo(8.75f, y + 4.25f); break;
  557. default: Shader.translateTo(8.8333333333f, y + 4.16666667f); break;
  558. }
  559. Shader.rotate(-time * 72.0f);
  560. Shader.updateMatrix();
  561. Shader.getColorRenderer().drawRectangle(-0.5f / scale, -0.5f / scale, 0.5f / scale, 4.0f - 0.5f * scale, 0xFF000000);
  562. }
  563. }
  564. // -------------------------------------------------------------------------
  565. // collision box, interaction layer
  566. // -------------------------------------------------------------------------
  567. private Tile getInteractionTile(int x, int y)
  568. {
  569. int i = data.getInteractionTile(x, y);
  570. if(i == -1)
  571. {
  572. return Game.FALLBACK_TILE;
  573. }
  574. return Game.get().getTile(i);
  575. }
  576. private CollisionObject getMovementBox(int x, int y)
  577. {
  578. int i = data.getInteractionTile(x, y);
  579. if(i == -1)
  580. {
  581. return CollisionObject.NULL_BOX;
  582. }
  583. return Game.get().getTile(i).getMovementBox(x, y).reset().offset(Utils.toCoord(x), Utils.toCoord(y));
  584. }
  585. public List<CollisionObject> getMovementBoxesAt(CollisionObject box, Entity not)
  586. {
  587. List<CollisionObject> boxes;
  588. if(not != null)
  589. {
  590. boxes = getEntitiesCollidingWith(not, box).stream().map(ent -> ent.getBox()).collect(Collectors.toList());
  591. }
  592. else
  593. {
  594. boxes = new LinkedList<>();
  595. }
  596. int startX = Utils.toBlock(box.getMinX());
  597. int endX = Utils.toBlock(box.getMaxX());
  598. int startY = Utils.toBlock(box.getMinY());
  599. int endY = Utils.toBlock(box.getMaxY());
  600. for(int x = startX; x <= endX; x++)
  601. {
  602. for(int y = startY; y <= endY; y++)
  603. {
  604. CollisionObject cb = getMovementBox(x, y);
  605. if(cb.mayCollide(box) && cb != CollisionObject.NULL_BOX)
  606. {
  607. boxes.add(cb.copy());
  608. }
  609. }
  610. }
  611. return boxes;
  612. }
  613. private CollisionObject getCollisionBox(int x, int y)
  614. {
  615. int i = data.getInteractionTile(x, y);
  616. if(i == -1)
  617. {
  618. return CollisionObject.NULL_BOX;
  619. }
  620. Tile tile = Game.get().getTile(i);
  621. return tile.getCollisionBox(x, y).reset().offset(Utils.toCoord(x), Utils.toCoord(y));
  622. }
  623. public List<Location> getCollisionBoxesAt(CollisionObject cb)
  624. {
  625. LinkedList<Location> boxes = new LinkedList<>();
  626. int startX = Utils.toBlock(cb.getMinX());
  627. int endX = Utils.toBlock(cb.getMaxX());
  628. int startY = Utils.toBlock(cb.getMinY());
  629. int endY = Utils.toBlock(cb.getMaxY());
  630. for(int x = startX; x <= endX; x++)
  631. {
  632. for(int y = startY; y <= endY; y++)
  633. {
  634. if(getCollisionBox(x, y).isColliding(cb))
  635. {
  636. boxes.add(new Location(getInteractionTile(x, y), x, y));
  637. }
  638. }
  639. }
  640. return boxes;
  641. }
  642. public List<Entity> getEntitiesCollidingWith(Entity not, CollisionObject cb)
  643. {
  644. return entities.values().stream().filter(ent -> ent != not && ent.getBox().isColliding(cb)).collect(Collectors.toList());
  645. }
  646. }