Wednesday, March 20, 2013

Pausing Physics

‹prev | My Chain | next›

Tonight I hope to figure out how to pause Physijs physics. Pausing Three.js animation is simple enough—a guard clause before rendering does the trick:
  var paused = false;
  function animate() {
    requestAnimationFrame(animate);
    if (paused) return;
    // ...
    renderer.render(scene, camera);
  }
  animate();
Something similar seems to work for Physijs:
  // Run physics
  function gameStep() {
    if (!paused) scene.simulate();
    // Update physics 60 times a second so that motion is smooth
    setTimeout(gameStep, 1000/60);
  }
  gameStep();
The CPU's load definitely goes down in response to this, so it would seem as though this helps. The problem is that, upon “un-pause”, the game jumps ahead as if it had been simulating things all along.

I am not quite sure how this happens since the CPU load become negligible when paused. There is a web worker involved in Physijs simulation, but if it were actively working, I would expect the CPU to remain high. My best guess is that Physijs maintains an internal last-updated-physics date and, upon restart it applies physics for the interim. I'm probably completely wrong, but it is a working theory.

And unfortunately, this turns out to be a good working theory. There is a last_simulation_time stored in the worker. Sadly, try as I might, I cannot figure a way to get it to reset or slow down. So I fall back on what I know best: cheating.

I only have one thing moving in the current game, so in addition to pausing animation and not calling scene.simulate(), I also manually stop the raft by setting its mass to zero:
  var mass, velocity;
  document.addEventListener("keydown", function(event) {
    var code = event.which || event.keyCode;
    // ...
    if (code == 80)  { // P
      paused = !paused;
      if (paused) {
        mass = raft.mass;
        velocity = raft.getLinearVelocity();
        raft.mass=0;
      }
      else {
        raft.mass = mass;
        raft.setLinearVelocity(velocity);
      }
    }
  });
It may not be perfect, but it works. By setting the mass to zero, I effectively take it out of Pysijs' simulation. I squirrel the old mass and current velocity away so that, once the game is unpaused, these values can be restored and the game can proceed as desired.

This is not a great solution for a game or simulation with a ton of objects in motion, but it will suffice for my needs.

Day #696

No comments:

Post a Comment