back home

Setting Up Only What Matters And Breaking The Laws Of Physics With ClojureScript

Written by Bunkers on March 29, 2017

I introduced this Dobit logo project with a kind of scope/design post. It's now time to setup the environment and start to see if the theory can work in practise.

Initial Setup

The development environment is a combination of ClojureScript, Matter.js and Quil and the base project is up on GitHub. It's an extension of my ClojureScript version of the Coding Train's tutorials on Matter.JS.

I'm sure there are many different starting lein templates I could have used. If I continue in this vain on other projects then I think it would be worthwhile investigating the creation of my own templates. As it is, I started with the Quil ClojureScript template.

I added Figwheel, so live reloading was in place. As I can't set the state of the physics inside Matter.JS directly - I think this could be incredibly complex to implement too - Figwheel only saves me from having to refresh the page, and displays compiler error messages in the browser.

At some point it would be great to have the state of the physics engine rewindable, and truly deterministic as a product of time. How it works currently is by determining all the objects' new positions given that a certain amount of time has elapsed. Matter.JS works out whether an object has collided with another after it calculates its position. Pass a large value for elapsed time to the Engine.update method and objects will not collide with our floor object, for example. Instead their new position could effectively mean an object has passed straight through another.

I think my use of variable delta times when updating the physics engine amplifies the problem, and is the main reason for the correction parameter you can pass in to the call to update

Physics Laws Are Made To Be Broken

Time for a little side discussion with a bit of a click-bait heading! Given the way Matter.JS (and most physics engines from what I can see) is updating the world, variations in the delta time and frame rate affect the simulation. This means I can run the simulation multiple times and depending on the number of objects involved, I'll see a different result. In fact, this is what I noticed and started me down the road of investigating why.

So, it's not really breaking the laws of physics, but more calculating them at different times. In my comfy new world of Clojure immutability I'm starting to expect everything to be a pure function. Put in the same data and get out the same result. This is kind of the case here, it's just unlikely that the same data will be the inputs to the simulation on each run.

I'd love to have a physics engine that allowed me to play with time a bit. Rewind it, or just set an arbitrary state. Until then it seems that to minimise variations the advice is to have the physics update at the desired frame rate in a separate 'thread' (I know we're in a single threaded environment) independent of the rest of the program's logic. That way, as long as the CPU can handle the load, the physics should be predictable.

It's not a big problem for me at the moment. When I get some time I'll run some tests on this technique (and possibly other techniques) to see how it affects this variability.

Back to setting up the project.

Debugging

I used it in the previous project too, but in case you're hesitating, I highly recommend installing the cljs-devtools from BinaryAge in any ClojureScript project of yours. It uses Chrome's custom formatters feature to display ClojureScript data structures like standard JavaScript objects when they're logged to the console. Combine this with source maps and you've got a great debugging environment.

Base Camp Reached

So, we've now got a straightforward ClojureScipt Quil project setup with supporting plugins for debugging and live reloading in the browser. Start it up with:

lein figwheel

Head to the standard http://localhost:3449 address in your browser and you should see a starting sketch of a ground object with a small box that falls from the top and bounces to a rest.

There's a lot more to do of course, but the basic libraries and development environment are all in place.

Get yourself to base camp and you can follow along with all the other trial and error mistakes I've made to get something working!