But... I guess this won't be the first time someone posts bad physics code on the internet and poses it as a good example.
But... I guess this won't be the first time someone posts bad physics code on the internet and poses it as a good example.
The OPs code is fine. And was written by a she, not a he.
Your suggestion is what is sometimes called 'continuous' collision detection. It is needed in some cases, particular when the OP approach might miss collisions (less often for when knock-on-collisions are missed, since those are rarer). But that approach is not 'better' - it is far more time consuming (vastly more for 3d rigid bodies with angular velocity), and has a visual benefit in some cases (not in the OPs case - or at least you wouldn't see the difference).
But, of course, both approaches are very approximate and only intended to give the right feel. If you wanted to be even more accurate you would process your collisions by subdividing updates around the collision (a good pool-ball simulation does this, to model proper breaks). And you'd have to use different integrators than the 1st degree Newton update.
This process can keep going as far as you like. For physics systems I've worked on for modelling the behavior of rigid components in MotoGP bikes, the kinds of approximations you allow are very different to the physics engines I've built for commercial games. Neither are 'better' or 'worse' - a good programmer understands the requirements of their domain . To that extent, the OP's approach is fine, and powers the vast majority of the physics in current generation video games (most engines do support continuous collision detection, but it will be switched off for most rigid bodies in a scene, for performance).
while (trig.isLineIntersectingCircle(circle, line)) {
physics.moveCircle(circle);
}You bring up a slightly different issue now, which I'm not sure if you are suggesting the problem is with the unbounded loop or with the serial strategy for resolution.
On the former, I agree with in the narrow (interpenetration resolution isn't usually guaranteed to converge), but taking
while (has_interpenetration()) {
resolve_interpenetration();
}
and adding a limit for (int i = relaxation_steps; i > 0 && has_interpenetration(); --i) {
resolve_interpenetration();
}
gives you code that is in most game physics engines, in some form.On the latter, modern game engines do some steps globally, rather than just running through each rigid body (often collision detection, interpenetration resolution, resting contact resolution, but not normally collision resolution or integration). But the OP approach of running everything in series wasn't unusual 15 years ago when game physics systems started to become ubiquitous. Before companies like Mathengine and Havok perfected LCP approaches, folks like Ipion and FastCar were doing impulse-based calculations that were heavily serial. So for a very simple JS experiment, it didn't strike me as a problem. I'd have written it that way too, if it were me.
Of course, this is what physics engines do, and why you should probably use one instead of reinventing the wheel.
In terms of showing how a game loop and really basic game physics works, however, this is a pretty clean and understandable example.