a performance disaster, part 2
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
package mindustry.async;
|
package mindustry.async;
|
||||||
|
|
||||||
import arc.*;
|
|
||||||
import arc.box2d.*;
|
import arc.box2d.*;
|
||||||
import arc.box2d.BodyDef.*;
|
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
@@ -11,6 +9,8 @@ import arc.util.pooling.Pool.*;
|
|||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
|
||||||
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes collisions.
|
* Processes collisions.
|
||||||
*
|
*
|
||||||
@@ -21,89 +21,81 @@ import mindustry.gen.*;
|
|||||||
* Collisions are resolved and stored in a list, then processed synchronously.
|
* Collisions are resolved and stored in a list, then processed synchronously.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CollisionProcess implements AsyncProcess, ContactListener, ContactFilter{
|
public class CollisionProcess implements AsyncProcess{
|
||||||
private Pool<CollisionRef> pool = Pools.get(CollisionRef.class, CollisionRef::new);
|
private Pool<CollisionRef> pool = Pools.get(CollisionRef.class, CollisionRef::new);
|
||||||
|
|
||||||
private Physics physics;
|
//private Physics physics;
|
||||||
private Array<CollisionRef> refs = new Array<>(false);
|
private QuadTree<Collisionc> tree;
|
||||||
private BodyDef def;
|
private Array<Collisionc> insertEntities = new Array<>();
|
||||||
private FixtureDef fdef;
|
private Array<Collisionc> checkEntities = new Array<>();
|
||||||
|
|
||||||
private EntityGroup<? extends Collisionc> group = Groups.collision;
|
private Array<Collisionc> arrOut = new Array<>();
|
||||||
|
|
||||||
|
private Vec2 l1 = new Vec2();
|
||||||
|
private Rect r1 = new Rect();
|
||||||
|
private Rect r2 = new Rect();
|
||||||
|
//private Array<CollisionRef> refs = new Array<>(false);
|
||||||
|
//private BodyDef def;
|
||||||
|
//private FixtureDef fdef;
|
||||||
|
|
||||||
|
private EntityGroup<? extends Collisionc> inserted = Groups.unit;
|
||||||
|
private EntityGroup<? extends Collisionc> checked = Groups.bullet;
|
||||||
private Array<Collisionc> collisions = new Array<>(Collisionc.class);
|
private Array<Collisionc> collisions = new Array<>(Collisionc.class);
|
||||||
|
|
||||||
public CollisionProcess(){
|
|
||||||
def = new BodyDef();
|
|
||||||
def.type = BodyType.DynamicBody;
|
|
||||||
|
|
||||||
fdef = new FixtureDef();
|
|
||||||
fdef.density = 1;
|
|
||||||
fdef.isSensor = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void begin(){
|
public void begin(){
|
||||||
if(physics == null) return;
|
if(tree == null) return;
|
||||||
|
|
||||||
//remove stale entities
|
|
||||||
refs.removeAll(ref -> {
|
|
||||||
if(!ref.entity.isAdded()){
|
|
||||||
physics.destroyBody(ref.body);
|
|
||||||
pool.free(ref);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
collisions.clear();
|
collisions.clear();
|
||||||
|
|
||||||
//find entities without bodies and assign them
|
insertEntities.size = 0;
|
||||||
for(Collisionc entity : group){
|
checkEntities.size = 0;
|
||||||
if(entity.colref() == null){
|
|
||||||
//add bodies to entities that have none
|
|
||||||
fdef.shape = new CircleShape(entity.hitSize() / 2f);
|
|
||||||
|
|
||||||
def.position.set(entity);
|
inserted.copy(insertEntities);
|
||||||
|
checked.copy(checkEntities);
|
||||||
Body body = physics.createBody(def);
|
|
||||||
body.createFixture(fdef);
|
|
||||||
|
|
||||||
CollisionRef ref = pool.obtain().set(entity, body);
|
|
||||||
refs.add(ref);
|
|
||||||
|
|
||||||
body.setUserData(ref);
|
|
||||||
entity.colref(ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
//save last position
|
|
||||||
CollisionRef ref = entity.colref();
|
|
||||||
ref.position.set(entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(){
|
public void process(){
|
||||||
if(physics == null) return;
|
if(tree == null) return;
|
||||||
|
|
||||||
collisions.clear();
|
collisions.clear();
|
||||||
|
|
||||||
Time.mark();
|
Time.mark();
|
||||||
|
|
||||||
//get last position vectors before step
|
tree.clear();
|
||||||
for(CollisionRef ref : refs){
|
//insert targets
|
||||||
//force set target position
|
for(Collisionc ins : insertEntities){
|
||||||
ref.body.setPosition(ref.position.x, ref.position.y);
|
tree.insert(ins);
|
||||||
|
|
||||||
//write velocity
|
|
||||||
ref.body.setLinearVelocity(ref.velocity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
physics.step(Core.graphics.getDeltaTime(), 2, 2);
|
for(Collisionc solid : checked){
|
||||||
|
solid.hitbox(r1);
|
||||||
|
r1.x += (solid.lastX() - solid.getX());
|
||||||
|
r1.y += (solid.lastY() - solid.getY());
|
||||||
|
|
||||||
|
solid.hitbox(r2);
|
||||||
|
r2.merge(r1);
|
||||||
|
|
||||||
|
arrOut.clear();
|
||||||
|
tree.getIntersect(arrOut, r2);
|
||||||
|
|
||||||
|
for(Collisionc sc : arrOut){
|
||||||
|
sc.hitbox(r1);
|
||||||
|
if(r2.overlaps(r1)){
|
||||||
|
checkCollide(solid, sc);
|
||||||
|
//break out of loop when this object hits something
|
||||||
|
if(!solid.isAdded()) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info(Time.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void end(){
|
public void end(){
|
||||||
if(physics == null) return;
|
if(tree == null) return;
|
||||||
|
|
||||||
//processes anything that happened
|
//processes anything that happened
|
||||||
for(int i = 0; i < collisions.size; i += 2){
|
for(int i = 0; i < collisions.size; i += 2){
|
||||||
@@ -116,63 +108,98 @@ public class CollisionProcess implements AsyncProcess, ContactListener, ContactF
|
|||||||
a.collision(b, cx, cy);
|
a.collision(b, cx, cy);
|
||||||
b.collision(a, cx, cy);
|
b.collision(a, cx, cy);
|
||||||
}
|
}
|
||||||
|
|
||||||
//update velocity state based on frame movement
|
|
||||||
for(CollisionRef ref : refs){
|
|
||||||
ref.velocity.set(ref.entity).sub(ref.position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset(){
|
public void reset(){
|
||||||
if(physics != null){
|
tree = null;
|
||||||
pool.freeAll(refs);
|
insertEntities.clear();
|
||||||
refs.clear();
|
checkEntities.clear();
|
||||||
physics.dispose();
|
|
||||||
physics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void init(){
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
physics = new Physics(new Vec2(), true);
|
tree = new QuadTree<>(new Rect(-finalWorldBounds, -finalWorldBounds, world.width() * tilesize + finalWorldBounds * 2, world.height() * tilesize + finalWorldBounds * 2));
|
||||||
physics.setContactListener(this);
|
|
||||||
physics.setContactFilter(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void checkCollide(Collisionc a, Collisionc b){
|
||||||
public void beginContact(Contact contact){
|
|
||||||
CollisionRef a = contact.getFixtureA().getBody().getUserData();
|
|
||||||
CollisionRef b = contact.getFixtureB().getBody().getUserData();
|
|
||||||
|
|
||||||
//save collision
|
a.hitbox(this.r1);
|
||||||
collisions.add(a.entity, b.entity);
|
b.hitbox(this.r2);
|
||||||
|
|
||||||
|
r1.x += (a.lastX() - a.getX());
|
||||||
|
r1.y += (a.lastY() - a.getY());
|
||||||
|
r2.x += (b.lastX() - b.getX());
|
||||||
|
r2.y += (b.lastY() - b.getY());
|
||||||
|
|
||||||
|
float vax = a.getX() - a.lastX();
|
||||||
|
float vay = a.getY() - a.lastY();
|
||||||
|
float vbx = b.getX() - b.lastX();
|
||||||
|
float vby = b.getY() - b.lastY();
|
||||||
|
|
||||||
|
if(a != b && a.collides(b)){
|
||||||
|
l1.set(a.getX(), a.getY());
|
||||||
|
boolean collide = r1.overlaps(r2) || collide(r1.x, r1.y, r1.width, r1.height, vax, vay,
|
||||||
|
r2.x, r2.y, r2.width, r2.height, vbx, vby, l1);
|
||||||
|
if(collide){
|
||||||
|
collisions.add(a);
|
||||||
|
collisions.add(b);
|
||||||
|
//a.collision(b, l1.x, l1.y);
|
||||||
|
//b.collision(a, l1.x, l1.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private boolean collide(float x1, float y1, float w1, float h1, float vx1, float vy1,
|
||||||
public void endContact(Contact contact){
|
float x2, float y2, float w2, float h2, float vx2, float vy2, Vec2 out){
|
||||||
|
float px = vx1, py = vy1;
|
||||||
|
|
||||||
}
|
vx1 -= vx2;
|
||||||
|
vy1 -= vy2;
|
||||||
|
|
||||||
@Override
|
float xInvEntry, yInvEntry;
|
||||||
public void preSolve(Contact contact, Manifold oldManifold){
|
float xInvExit, yInvExit;
|
||||||
|
|
||||||
}
|
if(vx1 > 0.0f){
|
||||||
|
xInvEntry = x2 - (x1 + w1);
|
||||||
|
xInvExit = (x2 + w2) - x1;
|
||||||
|
}else{
|
||||||
|
xInvEntry = (x2 + w2) - x1;
|
||||||
|
xInvExit = x2 - (x1 + w1);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
if(vy1 > 0.0f){
|
||||||
public void postSolve(Contact contact, ContactImpulse impulse){
|
yInvEntry = y2 - (y1 + h1);
|
||||||
|
yInvExit = (y2 + h2) - y1;
|
||||||
|
}else{
|
||||||
|
yInvEntry = (y2 + h2) - y1;
|
||||||
|
yInvExit = y2 - (y1 + h1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
float xEntry, yEntry;
|
||||||
|
float xExit, yExit;
|
||||||
|
|
||||||
@Override
|
xEntry = xInvEntry / vx1;
|
||||||
public boolean shouldCollide(Fixture fixtureA, Fixture fixtureB){
|
xExit = xInvExit / vx1;
|
||||||
CollisionRef a = fixtureA.getBody().getUserData();
|
|
||||||
CollisionRef b = fixtureB.getBody().getUserData();
|
|
||||||
|
|
||||||
//note that this method is called in a different thread, but for simple collision checks state doesn't matter too much
|
yEntry = yInvEntry / vy1;
|
||||||
return a != b && a.entity.collides(b.entity) && b.entity.collides(a.entity);
|
yExit = yInvExit / vy1;
|
||||||
|
|
||||||
|
float entryTime = Math.max(xEntry, yEntry);
|
||||||
|
float exitTime = Math.min(xExit, yExit);
|
||||||
|
|
||||||
|
if(entryTime > exitTime || xExit < 0.0f || yExit < 0.0f || xEntry > 1.0f || yEntry > 1.0f){
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
float dx = x1 + w1 / 2f + px * entryTime;
|
||||||
|
float dy = y1 + h1 / 2f + py * entryTime;
|
||||||
|
|
||||||
|
out.set(dx, dy);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CollisionRef implements Poolable{
|
public static class CollisionRef implements Poolable{
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ class AllDefs{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GroupDef(value = Collisionc.class)
|
|
||||||
class gcollision{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@GroupDef(value = Unitc.class, spatial = true, mapping = true)
|
@GroupDef(value = Unitc.class, spatial = true, mapping = true)
|
||||||
class gunit{
|
class gunit{
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
each(Entityc::update);
|
each(Entityc::update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void copy(Array arr){
|
||||||
|
arr.addAll(array);
|
||||||
|
}
|
||||||
|
|
||||||
public void each(Cons<T> cons){
|
public void each(Cons<T> cons){
|
||||||
for(index = 0; index < array.size; index++){
|
for(index = 0; index < array.size; index++){
|
||||||
cons.get(array.items[index]);
|
cons.get(array.items[index]);
|
||||||
|
|||||||
Reference in New Issue
Block a user