reduce array allocations when doing collision

This commit is contained in:
RandomityGuy 2026-03-27 17:34:32 +00:00
parent 95e75a220e
commit a6ae9259a1
7 changed files with 44 additions and 87 deletions

View file

@ -260,7 +260,8 @@ class Marble extends GameObject {
public var contacts:Array<CollisionInfo> = [];
public var bestContact:CollisionInfo;
public var contactEntities:Array<CollisionEntity> = [];
static var contactScratch:Array<CollisionEntity> = [];
var queuedContacts:Array<CollisionInfo> = [];
var appliedImpulses:Array<{impulse:Vector, contactImpulse:Bool}> = [];
@ -700,9 +701,7 @@ class Marble extends GameObject {
function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) {
this.contacts = queuedContacts;
CollisionPool.clear();
var c = collisiomWorld.sphereIntersection(this.collider, timeState);
this.contactEntities = c.foundEntities;
contacts = contacts.concat(c.contacts);
collisiomWorld.sphereIntersection(this.collider, timeState, this.contacts);
}
public function queueCollision(collisionInfo:CollisionInfo) {
@ -1274,7 +1273,10 @@ class Marble extends GameObject {
searchbox.addSpherePos(position.x, position.y, position.z, _radius);
searchbox.addSpherePos(position.x + velocity.x * deltaT, position.y + velocity.y * deltaT, position.z + velocity.z * deltaT, _radius);
var foundObjs = this.collisionWorld.boundingSearch(searchbox);
contactScratch.resize(0);
this.collisionWorld.boundingSearch(searchbox, contactScratch);
var foundObjs = contactScratch;
var finalT = deltaT;
var found = false;
@ -1904,7 +1906,7 @@ class Marble extends GameObject {
}
// }
}
this.queuedContacts = [];
this.queuedContacts.resize(0);
newPos = this.collider.transform.getPosition(); // this.getAbsPos().getPosition().clone();
@ -1983,7 +1985,9 @@ class Marble extends GameObject {
// marbleHitbox.offset(end.x, end.y, end.z);
// spherebounds.addSpherePos(gjkCapsule.p2.x, gjkCapsule.p2.y, gjkCapsule.p2.z, gjkCapsule.radius);
var contacts = this.collisionWorld.boundingSearch(box);
contactScratch.resize(0);
this.collisionWorld.boundingSearch(box, contactScratch);
var contacts = contactScratch;
// var contacts = marble.contactEntities;
var inside = [];
@ -2036,7 +2040,9 @@ class Marble extends GameObject {
var checkSphereRadius = checkBounds.getMax().sub(checkBoundsCenter).length();
var checkSphere = new Bounds();
checkSphere.addSpherePos(checkBoundsCenter.x, checkBoundsCenter.y, checkBoundsCenter.z, checkSphereRadius);
var endpadBB = this.collisionWorld.boundingSearch(checkSphere, false);
contactScratch.resize(0);
this.collisionWorld.boundingSearch(checkSphere, contactScratch, false);
var endpadBB = contactScratch;
var found = false;
for (collider in endpadBB) {
if (collider.go == @:privateAccess this.level.endPad) {
@ -2820,7 +2826,6 @@ class Marble extends GameObject {
this.megaMarbleUseTick = 0;
this.netFlags = MarbleNetFlags.DoBlast | MarbleNetFlags.DoMega | MarbleNetFlags.DoHelicopter | MarbleNetFlags.DoShockAbsorber | MarbleNetFlags.DoSuperBounce | MarbleNetFlags.PickupPowerup | MarbleNetFlags.GravityChange | MarbleNetFlags.UsePowerup;
this.lastContactNormal = new Vector(0, 0, 1);
this.contactEntities = [];
this.cloak = false;
this._firstTick = true;
this.lastRespawnTick = -100000;

View file

@ -56,7 +56,5 @@ class BoxCollisionEntity extends CollisionEntity implements IBVHObject {
return Math.POSITIVE_INFINITY;
}
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState) {
return [];
}
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {}
}

View file

@ -200,7 +200,7 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
this.priority = priority;
}
public function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState) {
public function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
var position = collisionEntity.transform.getPosition();
var radius = collisionEntity.radius + 0.001;
@ -227,8 +227,6 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
invtform.load(Matrix.I());
}
var contacts = [];
for (obj in surfaces) {
var surface:CollisionSurface = cast obj;
@ -301,7 +299,5 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
// if (surfaceBestContact != null)
// contacts.push(surfaceBestContact);
}
return contacts;
}
}

View file

@ -18,7 +18,7 @@ class CollisionHull extends CollisionEntity {
super(go);
}
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState):Array<CollisionInfo> {
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
var bbox = this.boundingBox;
var box = new Bounds();
var pos = collisionEntity.transform.getPosition();
@ -51,10 +51,9 @@ class CollisionHull extends CollisionEntity {
cinfo.friction = friction;
cinfo.force = force;
this.go.onMarbleContact(collisionEntity.marble, timeState, cinfo);
return [cinfo];
contacts.push(cinfo);
}
}
return [];
}
public override function addSurface(surface:CollisionSurface) {

View file

@ -38,11 +38,12 @@ class CollisionWorld {
this.dynamicGrid.build();
}
public function sphereIntersection(spherecollision:SphereCollisionEntity, timeState:TimeState):SphereIntersectionResult {
var contactList:Array<CollisionInfo> = [];
var intersectionList:Array<CollisionEntity> = [];
public function sphereIntersection(spherecollision:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
var position = spherecollision.transform.getPosition();
var radius = spherecollision.radius;
// var velocity = spherecollision.velocity;
// var intersections = this.octree.radiusSearch(position, searchdist);
var box = new Bounds();
box.addSpherePos(0, 0, 0, radius);
@ -50,60 +51,24 @@ class CollisionWorld {
box.transform(rotQuat.toMatrix());
box.offset(position.x, position.y, position.z);
// box.addSpherePos(position.x + velocity.x * timeState.dt, position.y + velocity.y * timeState.dt, position.z + velocity.z * timeState.dt, radius);
var intersections = this.grid.boundingSearch(box);
this.intersectionList.resize(0);
this.grid.boundingSearch(box, this.intersectionList);
dynamicGrid.boundingSearch(box, this.intersectionList);
// var intersections = this.rtree.search([box.xMin, box.yMax, box.zMin], [box.xSize, box.ySize, box.zSize]);
var contacts = [];
var foundEntities = [];
for (obj in intersections) {
var entity:CollisionEntity = cast obj;
foundEntities.push(entity);
if (entity.go.isCollideable) {
contacts = contacts.concat(entity.sphereIntersection(spherecollision, timeState));
}
}
// if (marbleEntities.length > 1) {
// marbleSap.recompute();
// var sapCollisions = marbleSap.getIntersections(spherecollision);
// for (obj in sapCollisions) {
// if (obj.go.isCollideable) {
// contacts = contacts.concat(obj.sphereIntersection(spherecollision, timeState));
// }
// }
// }
// contacts = contacts.concat(this.staticWorld.sphereIntersection(spherecollision, timeState));
var dynSearch = dynamicGrid.boundingSearch(box);
for (obj in dynSearch) {
for (obj in this.intersectionList) {
if (obj != spherecollision) {
var col = cast(obj, CollisionEntity);
if (col.boundingBox.collide(box) && col.go.isCollideable)
contacts = contacts.concat(col.sphereIntersection(spherecollision, timeState));
var entity = obj;
if (obj.boundingBox.collide(box) && entity.go.isCollideable) {
entity.sphereIntersection(spherecollision, timeState, contacts);
}
}
}
// for (marb in marbleEntities) {
// if (marb != spherecollision) {
// if (spherecollision.go.isCollideable) {
// var isecs = marb.sphereIntersection(spherecollision, timeState);
// if (isecs.length > 0)
// foundEntities.push(marb);
// contacts = contacts.concat(isecs);
// }
// }
// }
return {foundEntities: foundEntities, contacts: contacts};
}
public function boundingSearch(bounds:Bounds, useCache:Bool = true) {
var contacts = this.grid.boundingSearch(bounds).map(x -> cast(x, CollisionEntity));
contacts = contacts.concat(dynamicGrid.boundingSearch(bounds).map(x -> cast(x, CollisionEntity)));
return contacts;
public function boundingSearch(bounds:Bounds, contacts:Array<CollisionEntity>, useCache:Bool = true) {
this.grid.boundingSearch(bounds, contacts);
dynamicGrid.boundingSearch(bounds, contacts);
}
public function rayCast(rayStart:Vector, rayDirection:Vector, rayLength:Float) {
@ -116,19 +81,17 @@ class CollisionWorld {
+ rayDirection.x * rayLength, rayStart.y
+ rayDirection.y * rayLength, rayStart.z
+ rayDirection.z * rayLength);
var objs = this.grid.boundingSearch(bounds);
var dynObjs = dynamicGrid.boundingSearch(bounds);
this.intersectionList.splice(0, this.intersectionList.length);
this.grid.boundingSearch(bounds, this.intersectionList);
dynamicGrid.boundingSearch(bounds, this.intersectionList);
var results = [];
for (obj in objs) {
var oo = cast(obj, CollisionEntity);
for (obj in this.intersectionList) {
var oo = obj;
oo.rayCast(rayStart, rayDirection, results, rayLength);
}
for (obj in dynObjs) {
var oo = cast(obj, CollisionEntity);
oo.rayCast(rayStart, rayDirection, results, rayLength);
}
// results = results.concat(this.staticWorld.rayCast(rayStart, rayDirection));
return results;
}

View file

@ -221,7 +221,7 @@ class GridBroadphase {
}
// searchbox should be in LOCAL coordinates
public function boundingSearch(searchbox:Bounds) {
public function boundingSearch(searchbox:Bounds, foundSurfaces:Array<CollisionEntity>) {
var queryMinX = Math.max(searchbox.xMin, bounds.xMin);
var queryMinY = Math.max(searchbox.yMin, bounds.yMin);
var queryMaxX = Math.min(searchbox.xMax, bounds.xMax);
@ -240,8 +240,6 @@ class GridBroadphase {
if (yEnd > CELL_SIZE)
yEnd = CELL_SIZE;
var foundSurfaces = [];
searchKey++;
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map

View file

@ -75,10 +75,9 @@ class SphereCollisionEntity extends CollisionEntity {
return Math.POSITIVE_INFINITY;
}
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState) {
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
if (ignore)
return [];
var contacts = [];
return;
var thispos = transform.getPosition();
var position = collisionEntity.transform.getPosition();
var velocity = collisionEntity.velocity;
@ -113,6 +112,5 @@ class SphereCollisionEntity extends CollisionEntity {
// othercontact.penetration = this.radius - (thispos.sub(othercontact.point).dot(othercontact.normal));
// this.marble.queueCollision(othercontact);
}
return contacts;
}
}