BoxList.java 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package me.hammerle.snuviengine.game;
  2. import java.util.ConcurrentModificationException;
  3. import java.util.LinkedList;
  4. import java.util.List;
  5. import java.util.function.Consumer;
  6. public class BoxList<T extends IBoxListEntry>
  7. {
  8. private double maxWidth = 0;
  9. private double maxHeight = 0;
  10. private final T[] entities;
  11. private int lastFreeEntity;
  12. public boolean isIterating = false;
  13. public static class Node
  14. {
  15. private Node next = null;
  16. private Node previous = null;
  17. private int index = -1;
  18. private int x = -1;
  19. private int y = -1;
  20. }
  21. private final double boxMinX;
  22. private final double boxMinY;
  23. private final double boxMaxX;
  24. private final double boxMaxY;
  25. private final double size;
  26. private final Node[][] nodes;
  27. private final int partionX;
  28. private final int partionY;
  29. public int amount = 0;
  30. public BoxList(int maxObjects, double x1, double y1, double x2, double y2, double size)
  31. {
  32. this.size = size;
  33. boxMinX = Math.min(x1, x2);
  34. boxMinY = Math.min(y1, y2);
  35. partionX = (int) Math.ceil((Math.max(x1, x2) - boxMinX) / size);
  36. partionY = (int) Math.ceil((Math.max(y1, y2) - boxMinX) / size);
  37. boxMaxX = partionX * size;
  38. boxMaxY = partionY * size;
  39. nodes = new Node[partionX][partionY];
  40. entities = (T[]) new IBoxListEntry[maxObjects];
  41. lastFreeEntity = entities.length - 1;
  42. }
  43. public Node add(T ent)
  44. {
  45. if(isIterating)
  46. {
  47. throw new ConcurrentModificationException();
  48. }
  49. if(maxHeight < ent.getHeight() / 2)
  50. {
  51. maxHeight = ent.getHeight() / 2;
  52. }
  53. if(maxWidth < ent.getWidth() / 2)
  54. {
  55. maxWidth = ent.getWidth() / 2;
  56. }
  57. amount++;
  58. int x = Math.max(Math.min((int) ((ent.getCenterX() + boxMinX) / size), partionX - 1), 0);
  59. int y = Math.max(Math.min((int) ((ent.getCenterY() + boxMinY) / size), partionY - 1), 0);
  60. Node n = new Node();
  61. n.index = lastFreeEntity;
  62. n.x = x;
  63. n.y = y;
  64. if(nodes[x][y] == null)
  65. {
  66. nodes[x][y] = n;
  67. }
  68. else
  69. {
  70. n.next = nodes[x][y];
  71. nodes[x][y].previous = n;
  72. nodes[x][y] = n;
  73. }
  74. entities[lastFreeEntity--] = ent;
  75. return n;
  76. }
  77. public void remove(Node n)
  78. {
  79. if(isIterating)
  80. {
  81. throw new ConcurrentModificationException();
  82. }
  83. if(n.previous != null)
  84. {
  85. n.previous.next = n.next;
  86. }
  87. else
  88. {
  89. nodes[n.x][n.y] = n.next;
  90. }
  91. if(n.next != null)
  92. {
  93. n.next.previous = n.previous;
  94. }
  95. if(lastFreeEntity + 1 == entities.length)
  96. {
  97. entities[n.index] = null;
  98. }
  99. else
  100. {
  101. lastFreeEntity++;
  102. T ent = entities[lastFreeEntity];
  103. entities[n.index] = ent;
  104. ent.getNode().index = n.index;
  105. entities[lastFreeEntity] = null;
  106. }
  107. n.next = null;
  108. n.previous = null;
  109. amount--;
  110. }
  111. public void update(Entity ent)
  112. {
  113. int x = Math.max(Math.min((int) (((ent.xPos + ent.width / 2) + boxMinX) / size), partionX - 1), 0);
  114. int y = Math.max(Math.min((int) (((ent.yPos + ent.height / 2) + boxMinY) / size), partionY - 1), 0);
  115. Node n = ent.node;
  116. if(n.x == x && n.y == y)
  117. {
  118. return;
  119. }
  120. if(n.previous != null)
  121. {
  122. n.previous.next = n.next;
  123. }
  124. else
  125. {
  126. nodes[n.x][n.y] = n.next;
  127. }
  128. if(n.next != null)
  129. {
  130. n.next.previous = n.previous;
  131. }
  132. n.x = x;
  133. n.y = y;
  134. n.previous = null;
  135. if(nodes[x][y] == null)
  136. {
  137. nodes[x][y] = n;
  138. n.next = null;
  139. }
  140. else
  141. {
  142. n.next = nodes[x][y];
  143. nodes[x][y].previous = n;
  144. nodes[x][y] = n;
  145. }
  146. }
  147. public List<T> getAllEntitiesAt(T not, double minX, double minY, double maxX, double maxY)
  148. {
  149. int sx = Math.max(Math.min((int) ((minX + boxMinX - maxWidth) / size), partionX - 1), 0);
  150. int sy = Math.max(Math.min((int) ((minY + boxMinY - maxHeight) / size), partionY - 1), 0);
  151. int ex = Math.max(Math.min((int) ((maxX + boxMinX + maxWidth) / size), partionX - 1), 0);
  152. int ey = Math.max(Math.min((int) ((maxY + boxMinY + maxHeight) / size), partionY - 1), 0);
  153. List<T> list = new LinkedList<>();
  154. for(int x = sx; x <= ex; x++)
  155. {
  156. for(int y = sy; y <= ey; y++)
  157. {
  158. Node n = nodes[x][y];
  159. while(n != null)
  160. {
  161. if(not != entities[n.index] && entities[n.index].isColliding(minX, minY, maxX, maxY))
  162. {
  163. list.add(entities[n.index]);
  164. }
  165. n = n.next;
  166. }
  167. }
  168. }
  169. return list;
  170. }
  171. public void forEach(Consumer<T> c)
  172. {
  173. isIterating = true;
  174. for(int i = lastFreeEntity + 1; i < entities.length; i++)
  175. {
  176. c.accept(entities[i]);
  177. }
  178. isIterating = false;
  179. }
  180. @Override
  181. public String toString()
  182. {
  183. StringBuilder sb = new StringBuilder();
  184. for(T ent : entities)
  185. {
  186. sb.append(ent);
  187. sb.append(", ");
  188. }
  189. return sb.toString();
  190. }
  191. }