Monday, March 25, 2013

Jumping in Three.js without Physics

‹prev | My Chain | next›

I think that I am done with the game for the last chapter of 3D Game Programming for Kids. I still need to rework the first draft, but I am happy with the direction in which last night's Clean Code thought experiment pointed me. There is still much work to be done in the book—the last 10% will likely take the better part of two months to complete.

With that in mind, I return to an old friend—my favorite Three.js avatar:



I have long promised a game featuring this player and, thanks to some great suggestions, I think I have a pretty good idea what I want to do in that chapter. It involves jumping and shaking.

The problem is that, at this point in the book, I have not introduced a physics engine that would help with that. So the challenge tonight is to make this kind of motion look OK without the benefit of physics.

Luckily, I have introduced Tween.js at this point and I am already using it to animate turning the avatar. I start by adding a key event handler for the space bar, which should initiate a jump:
  document.addEventListener('keydown', function(event) {
    switch (event.keyCode) {
      // ...
      case 32: // space
        jump();
        break;
    }
  });
Sadly there is no good way to avoid keyCode, but you live by JavaScript, you die by JavaScript. Anyhow, I make a Tween in the jump() function that moves from 0 to 180°, adjusting the height of the player's frame of reference by the sine of the angle:
  function jump() {
    new TWEEN
      .Tween({jump: 0})
      .to({jump: Math.PI}, 500)
      .onUpdate(function () {
        marker.position.y = 200* Math.sin(this.jump);
      })
      .start();
  }
The result is actually fairly pleasing:



Sure, it's hard to imagine the actual motion from a snapshot, but the player does jump. This involved minimal code, but I am a bit worried about that sine. There is no way of avoiding some trigonometry in 3D programming and I do not avoid it in the book. But I cannot recall if I have introduced it at this point.

Unfortunately, the non-trigonometry alternative is usually something like:
  function jump() {
    new TWEEN
      .Tween({jump: 0})
      .to({jump: 400}, 500)
      .onUpdate(function () {
        var height = 200;
        marker.position.y = height - Math.abs(this.jump % (2*height) - height);
      })
      .start();
  }
That works, but I have to think that kids would much more readily accept Math.sin()-is-awesome rather than that beastly code. I suppose that I could reduce that to the simpler, single loop form of:
  function jump() {
    new TWEEN
      .Tween({jump: -1})
      .to({jump: 1}, 500)
      .onUpdate(function () {
        marker.position.y = 200 * (1 - Math.abs(this.jump))
      })
      .start();
  }
That is not too bad. I still rather favor the sine version—whether or not I have introduced them at this point in the book. Then again, I could take this as an opportunity to introduce absolute values. Either could work, but it is good to have choices.


Day #701

No comments:

Post a Comment