simultaneous collisions in scenekit

trying to make a simple simulation of a Newton's Cradle in Scenekit.


if i have two balls starting in equilibrium and then give one ball an impulse, the dynamics are correct. the first ball comes back, hits the second ball. stops and all the momentum goes to the second ball. repeat. great!


now three balls are placed in the cradle. again, take one of the end balls, give it an impulse so it flies up. comes back and collides. the two other balls move and the original ball bounces back. that's not physics. the correct behavior is the first ball after colliding, stops and the ball on the other end moves up. the center ball should not move. ever. apparently collisions are handled serially.


playing w/ the timestep of the simulation doesn't appear to help (which also suggests collisions are handled serially).


physically (for identical balls), during a collisin, the velocities should simply be swapped between pairs (assuming elastic collision). so i turned off collisions and used SCNPhysicsContactDelegate to be called when any two balls contact w/ func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) and then simply swapped the velocities between the two nodes or gave each an impulse that would do the same thing. Doesn't really work since, some balls overlap and appear to be stuck for a bit.


i think what i need is a way to find *all* contacts in a timestep so i can handle simultaneous collisions correctly. alas, don't see how to do that.


any brillant ideas?


this also implies scenekit simulation of billards can't possibly work at least according to Newtonian physics. 😟

Replies

if i have a single ball in the cradle, the total mechanical energy is mostly conserved (friction = rollingFriction = angularDamping = damping = 0), though there is a slow decrease in time.


going back to just two balls, it does work for the first two or three collisions, but eventually energy is pumped into the system (restitution=1), ultimately resulting in some chaotic motion. the error initially shows itself by the colliding ball not having its velocity exactly zero. that is, isolated collisions are not handled exactly.


with more than two balls, if you introduce a slight gap between the balls in equilibrium, then the first two or three collisions behave as expected (and implies that simultaneous collisions is the main culprit). however, eventually a simultaneous collision occurs and energy can suddenly change.


it appears i need to replace/ignore Scenekit's physics simulation and implement my own. it's easy for this case, at least.

I think the easiest way to run a collision detection is by checking the distance between two balls. One after another until you checked them entirely.

This should be fast and possible to do it on all balls simultaneously: If the distance is getting smaller than twice the radius (assuming all balls have the same radius)... there you go.