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