Why does the result of the physics change on less performing devices?

This is a project of a traditional roulette, the idea is to apply an impulse to the ball with physics and it lands on a number.

But I’m having a problem that when I apply the impulse on the ball, depending on the performance of each device, the ball falls and stops in a different place.

The project is this => PlayCanvas 3D HTML5 Game Engine

The application on a Mac mini (Apple Silicon M1):

The application on a Iphone 6:

Link do build used on both devices new Roleta - PLAYCANVAS

Script rotateNumbers => PlayCanvas | HTML5 Game Engine
Script that applies the momentum of the ball => PlayCanvas | HTML5 Game Engine

It can be noticed that the result changes where the ball stops, and the difference is great. How could I solve that? take into consideration the processing or something? Thanks…

It is not about a less powerful device. I suppose you are using Ammo physics? If so, Ammo is not deterministic, which means you will have different results on different devices.

The workaround is not simple, and there is no example, but this is what I’ve done in the past that worked for me:

  • Host:

    • Calculate the impulse for the ball
    • Calculate the impulse for the roulette (if the roulette rotation is different every time)
    • Send both impulses to the network for other clients
    • Destroy the old physics world (not default one in PlayCanvas, it is not used in this case)
    • Create a new physics world
    • Add roulette rigidbody
    • Add ball rigidbody
    • Apply impulse on roulette
    • Apply impulse on ball
    • Create a loop with enough iterations to get the result (ball falling into a slot, maybe 300 steps?)
    • On each iteration of the loop, read and save into array a position and rotation of the ball and roulette
    • Once the loop ended, you get ball/roulette positions and rotations at fixed timesteps (60 times a second). You might need to normalize recorded quaternions.
    • You then “playback” the ball/roulette position, in PlayCanvas. Since refresh rates will be different on each device (some will match at 1/60, some will have 1/144, etc), you should playback considering the delta time step size. There are 2 ways to do it:
      • Create a curve for each component of the position vector (x, y, z) from the recorded values. Then normalize the total duration of the simulation, and sample the curve set for the position. For example, total duration is 3 seconds, you want to know the ball position at 1.5 second, after normalization, you grab the curve value at 0.5.
      • Another option is to do interpolation of position and rotations. You record simulation at some low fixed step, say 1/30. Then you know that at 0.3 second you will be at that position, but only 0.15 passed (or whatever the actual dt is), so you do a vector lerp on position and spherical interpolation on quaternion difference.
    • If you stopped simulation recording when the result is available (ball falling into a slot), then you would need to continue roulette rotation at the current speed, slowing it down (if it slows down). There can be a difference at slow down speed on different devices, but it is not important, as it will not affect the roulette result any more.
  • Client:

    • Receive the impulses
    • Destroy the old physics world.
    • Do the same stuff you did on host (adding bodies, applying impulses). It is important you do everything in the exact same order as you did on host.
    • Once you have simulation results, you start the playback.

This will guarantee the same visual outcome on every device.