Friday, January 25, 2013

One Way Platforms in Physijs

‹prev | My Chain | next›

I have a slight problem with my Three.js / Physijs platform game:


Currently the player (the circle) bounces when it hits the platforms, which is what I want. But I want the player to bounce only when it hits the top of a platform—that is, when the player is falling down and hits the top of a platform it should bounce. When the player then bounces up into the bottom of another platform, I want the player to pass right through and continue moving up. The real world does not work that way and neither does Physijs. Instead the player bounces off the bottom of the platform and quickly shoots down.

I cannot think of an obvious way that Physijs might facilitate that—making objects ghost-like sometimes and completely solid at other times. I do know that Physijs supports collision events that can fire before the physics engine starts to affect things, but I cannot see how that helps in this case.

Instead, what I'd like to try is to move the player "out" of the screen when it is moving up, and place it back at z=0 when it is going down. This should give it a miss when moving up, but allow collisions to kick in when going down.

My first pass will assume that all collisions are down collisions. That is, when I see a collision, I move the player out of the screen 25:
  player.addEventListener('collision', function(object) {
    console.log('Collision!');
    player.__dirtyPosition = true;
    player.position.z = 25;
  }); 
Physijs does not normally allow instantaneous transport—that kind of defeats the laws of physics that it is working so hard to reproduce—hence the __dirtyPosition. That flag is how developers tell Physijs that yes, I know that I am asking something horrible of you, but I want to do it any way. It lasts only until the next physics update, which is typically done along with animation.

And this works, I am now allowed one collision and then my player is stuck at z=25:


To reset the player's Z position, I add a check to the animation() function:
  function animate() {
    requestAnimationFrame(animate);
    scene.simulate(); // run physics

    resetPlayerFallingZ();
    renderer.render(scene, camera);
  }
  animate();  
I define that function to reset the player's z back to zero, but only if it makes it through the guard clauses:
  function resetPlayerFallingZ() {
    if (player.position.z === 0) return;
    if (player.getLinearVelocity().y > 0) return;
    
    player.__dirtyPosition = true;
    player.position.z = 0;        
  }
The first guard clause ensure that the function only applies if the player's Z position has already been pushed out. The second ensures that the player is falling.

With that, I again see lots of collisions falling down, but am still free to move up without hindrance:


That seems like a good stopping point for tonight. Up tomorrow, I would like to see if I can get screen wrapping to work. This seems prohibitively hard—especially in a world in which physics prevails. Still, I need to give it a shot.


Day #641

No comments:

Post a Comment