Collision callbacks occasionally not firing

In my game I have just changed from lasers (the weapon) being kinematic objects to being dynamic objects.

Now, on collision, these objects end themselves using a collision callback:

lobj.collision.on('collisionstart', this.collide);

And in the callback:

laser.prototype.collide = function(result){
     ...
     this.entity.destroy();
 }

Now some (maybe 1/50) are bouncing off the walls and not getting ended. Now I can understand some collisions being missed because they are fast-moving objects, but the collisions are happening. The lasers are bouncing. They’re just not being destroyed. This means that the collision trigger isn’t firing.

Feel free to fly around

I’ve noticed this problem before. Very occasionally, the physics engine doesn’t fire the collision callback. This affects my Pong project. I’m not even sure how to go about debugging this. It’s an issue with Ammo.js rather than PlayCanvas.

I started to notice this issue too. I observe this issue around 1 out of 20 to 30 shots.

I slightly modified engine itself in my browser and checked the behavior of manifolds and contacts. And indeed Ammo.js doesn’t return any contacts. (It seems it returns manifolds though even in case the issue occurs)

I think if it is impossible to fix (or reduce the probability of) this Ammo.js reliability issue, the issue critically impairs the reliability of PlayCanvas engine and replacement of physics engine might better be considered.

Thanks for investigating this @nakata0705. If we can find a reproducible case and it is genuinely a problem with ammo.js rather than how PlayCanvas is driving it, then we can submit a bug report against the ammo.js GitHub project. Then it is more likely to get fixed. If anyone can help with this, I’d really appreciate it! :smiley:

In some cases, it is very repeatable, ie if you move the ship to a certain location/angle and shoot at a wall, it will miss every time.

I think the way to make a test-scene would be to have a mouse/keyboard controlled ‘turret’ firing at some geometry, and use another key to save the position/orientation, so when you achieve the point where the collisions don’t fire you can save the numbers and pass the scene on.
I may have a go at doing this in a week or so.

Make sure it is not a problem when your bullet is too small and too fast that is flying through without ability to collide.
For such case it needs CCD (Continuous Collision Detection), and is generally perceived not as a “problem” of physics, but as challenge to be solved, as between two updates of bullet position, it does not calculates traveling path, but just new position, that way if object travels too fast, it will just fly though in between of physics updates.

Good suggestion @max but that is definitely not what is happening here. The bodies do collide but ammo.js never calls back to notify the engine that a contact occurred.

As Will mentioned, the bullet or ball bounces but no event is fired. Since ammo.js is converted from Bullet C++ code by using Emscripten (and it makes it extremely difficult to debug physics), this could be either Emscripten issue or an issue in Bullet itself.

I read some Bullet physics engine document. And I found a suspicious description in this page.
http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers

These pages are also infomative.
http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Stepping_The_World
http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Simulation_Tick_Callbacks

The first page says

The best way to determine if collisions happened between existing objects in the world, is to iterate over all contact manifolds. This should be done during a simulation tick (sub step) callback, because contacts might be added and removed during several substeps of a single stepSimulation call.

Current PlayCanvas Ammo.js setting is 1/60 simulation time resolution and can keep physics consistency up to 10 fps thanks to 10 maximum sub steps. (If fps becomes less than 10 fps, physics engine will “lose” time and can’t keep up with the 3D rendering)

Let’s say one PlayCanvas game’s framerate is less than 60 fps. In this case, the first page implies the contacts and manifolds information would be overwritten during any of callbacks for sub step. This matches with the symptom I observe because the “bounce without event” occurs more frequently when my game’s framerate becomes low.

OK. Then let’s call setInternalTickCallback() and add internal callback, and process manifolds and contacts… Well, things don’t go easy. Ammo.js doesn’t seem to have setInternalTickCallback() due to IDL binding restriction. This seems to be a known issue of Ammo.js.

So my guess is that if PlayCanvas build it’s own Ammo.js with setInternalTickCallback() support and modify engine to utilize the sub step callback, that would resolve this issue.

Great research @nakata0705. But I have seen this behaviour happen in apps that are running solidly at 60FPS. I haven’t noticed any frame drops when contacts are not reported. It just doesn’t feel like that is the root cause to me. But maybe I’m wrong… :smile:

Hmm… if this issue happens even if the game is running 60 fps, the cause wouldn’t be the sub step issue. I wonder what would happen if we set maxSubSteps to 1 rather than 10 for the program. That should eliminate the possibility of issue from sub steps completely.

Another thread in Ammo.js github seems to be related to the callback. Just for your information.

By the way, to avoid this callback issue, I tried to improve the performance of my program itself. I made my box static rigid bodies slightly smaller (0.98% of their original size) so that I can avoid overlapping rigid bodies. Also I changed the dynamic rigid bodies from capsule to sphere. And I reduced rendering resolution to 640x480. All of them seemed effective and the physics behavior became much more stable.

I don’t fully understand the situation. Because Ammo.js is generated JavaScript by emscripten. (I generally don’t like generated JavaScript. It’s almost impossible to debug!) But my observation so far is…

In my demo with 10,000 static box rigid bodies + some sphere dynamic rigid bodies…
1: If there are any overlapping static rigidbodies, there is a high risk that physics goes into “slow motion” mode.
2: If some frame drops happens in a row, there is a risk that physics goes into “slow motion” mode.
3: Once the game goes into “slow motion” mode, it is possible to recover from it by reducing render time extensively. If you don’t do anything, it is very likely that “slow motion” mode will not end and the game becomes unplayable.
4: If those #1 and #2 don’t happen, the game runs in solid 60 fps.

I feel Ammo.js is a black box in PlayCanvas. I can read the code of engine but I can’t really grasp what Ammo.js does. I hoped that PlayCanvas uses Oimo.js which is a physics engine written in JavaScript But I understand switching it is extremely difficult. (Potentially Oimo.js doesn’t provide features that PlayCanvas needs)