Willing to extend moveWithCollisions method

Hi there!

Currently, in the collisionCoordinator we loop through all meshes in the scene - Babylon.js/collisionCoordinator.ts at master · BabylonJS/Babylon.js · GitHub.

I have an intention to extend moveWithCollisions method to be able to pass manually an array of meshes against which collision detection should be tested.

My rationale for this I that this way I can drastically improve performance in the multiplayer game I’m developing. The world in my game is tile-based. So for example, the ground is not a single mesh but it rather consists of a large number of instanced tile meshes, which can be destructed during gameplay.

Thus, I have an efficient way to get an array of all meshes that surround a player. Then these meshes could be passed to the moveWithCollisions method, which would pass those down to the _collideWithWorld method and finally, that method would iterate only over that array of meshes that were passed in rather than all meshes in the scene.

If there are no concerns about such an extension of the moveWithCollisions method I’m happy to work on a PR.

In case if there are any concerns, maybe a good alternative for me would be a way to be able to extend or override DefaultCollisionCoordinator class.

Thanks for proposing to contribute !!!

Just thinking out loud :

  1. Would collision masks and groups not be enough ?
  2. Else maybe a predicate would fill more align with the rest of the APIs ? (just wondering)

And yes we would totally accept this as a PR !!!

Hi @jsdream,

Perhaps the CollisionCoordinator can be adjusted (upgraded/extended) in such a way that it is initialized with a cache of the meshes that are selected within the loop:

It would need to have a dirty flag that would update the cached set of meshes to check the collision with collider with.

This may be a more generic solution. If i remember correctly, these kind of dirty-cache-like optimizations are done for mesh rendering as well to speed up the rendering of (visible & in-view) meshes and the computation of mesh position/orientations (world matrices).

Another approach for your case specific may be to create a 2nd scene (e.g. a map) that is not rendered but is solely used for collisions. It would only contain simplified (collision) meshes of the real meshes from the rendering scene that are close to the player position. Then sync the position of the real player mesh with the collider copy mesh. Think of it as using a 2D-map to navigate a 3D-world.

Q

Thanks for a quick response @sebavan!

  1. From what I read here New properties; collisionGroup & collisionMask added to babylon collisions. - Announcements - HTML5 Game Devs Forum and saw in the code about collision masks I am not sure how I can use them to satisfy my needs.

  2. A predicate is also doesn’t sound good to me, as that would still mean I have to loop through all meshes in the scene to filter out only needed ones, especially in the situation when I already have an array of meshes surrounding player, which were efficiently retrieved from a Map.


Hi @QuintusHegie and thanks for your input.

As for approach with separate scenes it’s not going to work in my use case as it would mean I have to create a new scene for every player as well as every other mesh moving with collisions.

Regarding CollisionCoordinator I’m also not sure how your idea is going to work. The reason why I think it’s not going to work is that CollisionCoordinator is initialized per scene, but not per mesh (which would be needed in my case).

Although, your idea might work if the array of surrounding meshes will be attached to the moving mesh itself and then CollisionCoordinator could get that array from the mesh object.

All this would look something like this:

mesh.surroundingMeshes = arrayOfMeshes;
mesh.moveWithCollisions(vector);

And then in CollisionCoordinator:

var meshes = (excludedMesh && excludedMesh.surroundingMeshes) || this._scene.meshes;

for (var index = 0; index < meshes; index++) {
    var mesh = meshes[index];
    if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh && ((collisionMask & mesh.collisionGroup) !== 0)) {
        mesh._checkCollision(collider);
    }
}

This way at least methods parameters are not touched.

I guess collision groups will do in your case.

Basically collision will happen if A.collisionGroup & b.collisionMask !== 0

So if you set a collisionMask at 2 on the mesh and the surrounding meshes group at 2 only those would interact together.

Ok, so on approximation image below this is how I can see it would work with collision groups. All grid tile meshes are divided onto collision groups and then we assign collision mask to player’s mesh equal to the group the player currently in.

That means I won’t be able to achieve the following selection with collision groups, while it is possible with my approach. Which is quite important in the context of my game.

So in the context of my game, my approach gives me more significant performance boost.

I appreciate that this can be something too specific for my use case and maybe not needed in the framework itself. That’s why I’m thinking maybe it would be good if it would be possible to override default CollisionCoordinator with my own implementation?

Or maybe there is something else possible with collision groups I’m missing?

I was thinking you juste dynamically assign the collision group to all surrounding meshes and when the list changes, you assign this group to new entries and remove it from removed entries :slight_smile:

If this is not possible, do not hesitate to create the PR for it so we could reference this thread as an explanation of when to use it.

Yeah, I was also thinking about dynamic collision group assign approach, but it also has a few disadvantages for me:

  1. Every time before a mesh moves or a new moving mesh added it would be necessary to iterate over all meshes to update their collisionGroup. And this loop should be repeated for every moving mesh then. Since I’m developing a multiplayer game and running this code on the server-side every additional loop is a big pain for me (I have quite a large amount of meshes that would be necessary to iterate).
  2. Also, using collisionGroup would mean that inside CollisionCoordinator a loop over all meshes will be preserved and meshes will be filtered within the loop. So the if condition below would still have to be run for every mesh in the scene.
for (var index = 0; index < this._scene.meshes.length; index++) {
    var mesh = this._scene.meshes[index];
    if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh && ((collisionMask & mesh.collisionGroup) !== 0)) {

In my scenario, running even an empty loop through all meshes in the scene is something I need to avoid as much as possible.

Perfect, understood and it is a great case, feel free to create a PR.

Thanks for understanding!

Let me create a PR and we can then discuss implementation details there.

1 Like