Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A new fix for #47 #57

Merged
merged 3 commits into from
Jan 3, 2024
Merged

Conversation

Elettrotecnica
Copy link

Dear maintainers,

I was struggling with some misbehavior in my application, without realizing this may very well be related with issues #47 #52 and #54

Similar to the use cases reported originally by @smeybi, my application also may remove ammo bodies during its lifecycle, as they represent assets that are spawned/despawned on the scene.

After some long debugging I have realized there existed a problem with the way ammo bodies were deleted. If we look at

/* @param {Ammo.btCollisionObject} body */
AmmoDriver.prototype.removeBody = function(body) {
this.physicsWorld.removeRigidBody(body);
this.removeEventListener(body);
const bodyptr = Ammo.getPointer(body);
this.els.delete(bodyptr);
this.collisions.delete(bodyptr);
this.collisionKeys.splice(this.collisionKeys.indexOf(bodyptr), 1);
this.currentCollisions.delete(bodyptr);
};

At line 74 we see that when an ammo body is deleted, its supposed entry in the collisionKeys array is removed. However, this entry will be there only if the body ever participated in a collision in the role of body0

if (!this.collisions.has(body0ptr)) {
this.collisions.set(body0ptr, []);
this.collisionKeys.push(body0ptr);
}

If this never happened at the time the body is removed, the resulting index -1 will de-facto make so that splice will delete an arbitrary entry in collisionKeys. If this pattern repeats often enough, it will de-facto disable event generation for any body on the scene, as only in the collisionKeys loop we do cleanup the collisions array, which is checked before we trigger the event

if (this.collisions.get(body0ptr).indexOf(body1ptr) === -1) {
this.collisions.get(body0ptr).push(body1ptr);
if (this.eventListeners.indexOf(body0ptr) !== -1) {
this.els.get(body0ptr).emit("collidestart", { targetEl: this.els.get(body1ptr) });
}

for (let i = 0; i < this.collisionKeys.length; i++) {
const body0ptr = this.collisionKeys[i];
const body1ptrs = this.collisions.get(body0ptr);
for (let j = body1ptrs.length - 1; j >= 0; j--) {
const body1ptr = body1ptrs[j];
if (this.currentCollisions.get(body0ptr).has(body1ptr)) {
continue;
}
if (this.eventListeners.indexOf(body0ptr) !== -1) {
this.els.get(body0ptr).emit("collideend", { targetEl: this.els.get(body1ptr) });
}
if (this.eventListeners.indexOf(body1ptr) !== -1) {
this.els.get(body1ptr).emit("collideend", { targetEl: this.els.get(body0ptr) });
}
body1ptrs.splice(j, 1);

In my proposal I revert the previous fix, which came at the cost of a memory leak, and refactor the code so that we do not instantiate the data structures relevant for collisions on the fly, but at body creation. This ensures that a collisionKeys entry is there for every body and also makes the code more orderly IMO.

Please have a look if this also solves the issue reported originally.

All the best

Antonio Pisano added 3 commits December 28, 2023 11:25
… body is added, rather than on the fly

If a body is deleted before it can be the body0 of a collision, an
entry for it won't be created in the collisionKeys array. However, because
of the splice idiom used at removal, when a body that has no entry in
collisionKeys is deleted, an arbitrary entry will be deleted regardless.

Eventually, when further bodys are removed according to this pattern, there
may be no entry in collisionKeys at all, which will prevent the collisions map
from ever being emptied. This can completely prevent the firing of collisionstart
events.
…he previous commit should make them not necessary anymore
@diarmidmackenzie
Copy link
Member

Fantastic work. Thank you so much.

@diarmidmackenzie diarmidmackenzie merged commit e73bd6e into c-frame:master Jan 3, 2024
2 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants