This commit is contained in:
Anuken
2020-02-10 15:51:01 -05:00
parent 86d5842868
commit 47023af3d5
4 changed files with 6 additions and 351 deletions

View File

@ -131,6 +131,10 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
return array.size == 0;
}
public T index(int i){
return array.get(i);
}
public int size(){
return array.size;
}

View File

@ -1,349 +0,0 @@
package mindustry.entities;
import arc.struct.*;
import arc.util.pooling.*;
import arc.util.pooling.Pool.*;
/**
* Quad tree for optimized queries in 2d space
* @author Piotr-J
*/
public class QuadTree2 implements Poolable{
/**
* Max count of containers in a tree before it is split
* <p>
* Should be tweaked for best performance
*/
public static int MAX_IN_BUCKET = 16;
/**
* Max count of splits, tree start at depth = 0
* <p>
* Should be tweaked for best performance
*/
public static int MAX_DEPTH = 8;
private static Pool<QuadTree2> qtPool = Pools.get(QuadTree2.class, QuadTree2::new);
private static Pool<Container> cPool = Pools.get(Container.class, Container::new);
private static Array<Container> idToContainer = new Array<>();
public final static int OUTSIDE = -1;
public final static int SW = 0;
public final static int SE = 1;
public final static int NW = 2;
public final static int NE = 3;
protected int depth;
protected Array<Container> containers;
protected Container bounds;
protected QuadTree2[] nodes;
protected QuadTree2 parent;
/**
* Public constructor for {@link Pool} use only
*/
public QuadTree2(){
this(0, 0, 0, 0);
}
/**
* Public constructor for initial {@link QuadTree2}
* <p>
* Specify max tree bounds
*/
public QuadTree2(float x, float y, float width, float height){
bounds = new Container();
containers = new Array<>(MAX_IN_BUCKET);
nodes = new QuadTree2[4];
init(0, x, y, width, height, null);
}
protected QuadTree2 init(int depth, float x, float y, float width, float height, QuadTree2 parent){
this.depth = depth;
bounds.set(x, y, width, height);
this.parent = parent;
return this;
}
private int indexOf(float x, float y, float width, float height){
float midX = bounds.x + bounds.width / 2;
float midY = bounds.y + bounds.height / 2;
boolean top = y > midY;
boolean bottom = y < midY && y + height < midY;
if(x < midX && x + width < midX){
if(top){
return NW;
}else if(bottom){
return SW;
}
}else if(x > midX){
if(top){
return NE;
}else if(bottom){
return SE;
}
}
return OUTSIDE;
}
/**
* Inserts given entity id to tree with given bounds
*/
public void insert(int eid, float x, float y, float width, float height){
insert(cPool.obtain().set(eid, x, y, width, height));
}
protected void insert(Container c){
if(nodes[0] != null){
int index = indexOf(c.x, c.y, c.width, c.height);
if(index != OUTSIDE){
nodes[index].insert(c);
return;
}
}
c.parent = this;
idToContainer.set(c.eid, c);
containers.add(c);
if(containers.size > MAX_IN_BUCKET && depth < MAX_DEPTH){
if(nodes[0] == null){
float halfWidth = bounds.width / 2;
float halfHeight = bounds.height / 2;
nodes[SW] = qtPool.obtain().init(depth + 1, bounds.x, bounds.y, halfWidth, halfHeight, this);
nodes[SE] = qtPool.obtain().init(depth + 1, bounds.x + halfWidth, bounds.y, halfWidth, halfHeight, this);
nodes[NW] = qtPool.obtain().init(depth + 1, bounds.x, bounds.y + halfHeight, halfWidth, halfHeight, this);
nodes[NE] = qtPool.obtain().init(depth + 1, bounds.x + halfWidth, bounds.y + halfHeight, halfWidth, halfHeight, this);
}
for(int i = containers.size - 1; i >= 0; i--){
Container next = containers.get(i);
int index = indexOf(next.x, next.y, next.width, next.height);
if(index != OUTSIDE){
nodes[index].insert(next);
containers.remove(i);
}
}
}
}
/**
* Returns entity ids of entities that are inside {@link QuadTree2}s that contain given point
* <p>
* Returned entities must be filtered further as these results are not exact
*/
public IntArray get(IntArray fill, float x, float y){
if(bounds.contains(x, y)){
if(nodes[0] != null){
int index = indexOf(x, y, 0, 0);
if(index != OUTSIDE){
nodes[index].get(fill, x, y, 0, 0);
}
}
for(int i = 0; i < containers.size; i++){
fill.add(containers.get(i).eid);
}
}
return fill;
}
/**
* Returns entity ids of entities that bounds contain given point
*/
public IntArray getExact(IntArray fill, float x, float y){
if(bounds.contains(x, y)){
if(nodes[0] != null){
int index = indexOf(x, y, 0, 0);
if(index != OUTSIDE){
nodes[index].getExact(fill, x, y, 0, 0);
}
}
for(int i = 0; i < containers.size; i++){
Container c = containers.get(i);
if(c.contains(x, y)){
fill.add(c.eid);
}
}
}
return fill;
}
/**
* Returns entity ids of entities that are inside {@link QuadTree2}s that overlap given bounds
* <p>
* Returned entities must be filtered further as these results are not exact
*/
public IntArray get(IntArray fill, float x, float y, float width, float height){
if(bounds.overlaps(x, y, width, height)){
if(nodes[0] != null){
int index = indexOf(x, y, width, height);
if(index != OUTSIDE){
nodes[index].get(fill, x, y, width, height);
}else{
// if test bounds don't fully fit inside a node, we need to check them all
for(QuadTree2 node : nodes){
node.get(fill, x, y, width, height);
}
}
}
for(int i = 0; i < containers.size; i++){
Container c = containers.get(i);
fill.add(c.eid);
}
}
return fill;
}
/**
* Returns entity ids of entities that overlap given bounds
*/
public IntArray getExact(IntArray fill, float x, float y, float width, float height){
if(bounds.overlaps(x, y, width, height)){
if(nodes[0] != null){
int index = indexOf(x, y, width, height);
if(index != OUTSIDE){
nodes[index].getExact(fill, x, y, width, height);
}else{
// if test bounds don't fully fit inside a node, we need to check them all
for(QuadTree2 node : nodes){
node.getExact(fill, x, y, width, height);
}
}
}
for(int i = 0; i < containers.size; i++){
Container c = containers.get(i);
if(c.overlaps(x, y, width, height)){
fill.add(c.eid);
}
}
}
return fill;
}
/**
* Update position for this id with new one
*/
public void update(int id, float x, float y, float width, float height){
Container c = idToContainer.get(id);
c.set(id, x, y, width, height);
QuadTree2 qTree = c.parent;
qTree.containers.remove(c);
while(qTree.parent != null && !qTree.bounds.contains(c)){
qTree = qTree.parent;
}
qTree.insert(c);
}
/**
* Remove this id from the tree
*/
public void remove(int id){
Container c = idToContainer.get(id);
if(c == null)
return;
if(c.parent != null){
c.parent.containers.remove(c);
}
cPool.free(c);
}
/**
* Reset the QuadTree by removing all nodes and stored ids
*/
@Override
public void reset(){
for(int i = containers.size - 1; i >= 0; i--){
cPool.free(containers.remove(i));
}
for(int i = 0; i < nodes.length; i++){
if(nodes[i] != null){
qtPool.free(nodes[i]);
nodes[i] = null;
}
}
}
/**
* Dispose of the QuadTree by removing all nodes and stored ids
*/
public void dispose(){
reset();
}
/**
* @return {@link QuadTree2[]} with nodes of these tree, nodes may be null
*/
public QuadTree2[] getNodes(){
return nodes;
}
/**
* @return {@link Container} that represents bounds of this tree
*/
public Container getBounds(){
return bounds;
}
@Override
public String toString(){
return "QuadTree{" +
"depth=" + depth + "}";
}
/** Simple container for entity ids and their bounds*/
static class Container implements Poolable{
private int eid;
private float x;
private float y;
private float width;
private float height;
private QuadTree2 parent;
public Container(){
}
public Container set(int eid, float x, float y, float width, float height){
this.eid = eid;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
return this;
}
public Container set(float x, float y, float width, float height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
return this;
}
public boolean contains(float x, float y){
return this.x <= x && this.x + this.width >= x && this.y <= y && this.y + this.height >= y;
}
public boolean overlaps(float x, float y, float width, float height){
return this.x < x + width && this.x + this.width > x && this.y < y + height && this.y + this.height > y;
}
public boolean contains(float ox, float oy, float owidth, float oheight){
float xmax = ox + owidth;
float ymax = oy + oheight;
return ((ox > x && ox < x + width) && (xmax > x && xmax < x + width)) && ((oy > y && oy < y + height) && (ymax > y && ymax < y + height));
}
public boolean contains(Container c){
return contains(c.x, c.y, c.width, c.height);
}
@Override
public void reset(){
eid = -1;
x = 0;
y = 0;
width = 0;
height = 0;
parent = null;
}
}
}

View File

@ -159,7 +159,7 @@ public class DesktopInput extends InputHandler{
if(unit != null){
unit.hitbox(Tmp.r1);
if(Tmp.r1.contains(Core.input.mouseWorld())){
player.unit(unit);
//player.unit(unit);
}
}
}

View File

@ -1,3 +1,3 @@
org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=68b2451bd0f8c6252ccf2c065a1c4b4896605183
archash=292d60e7d6c2013334b0f4f30659e1d885f73cfe