Thursday, August 9, 2012

Gladius, Box2D.js and 2 of Newton's 3 Laws

‹prev | My Chain | next›

I ended yesterday with the ability to move and collide my minimalist avatar in Gladius under Box2D.js physics. All is not well on avatar island, however. First, the avatar demonstrates Newton's First Law nicely in that even after I have let go of movement keys, the avatar continues in motion. The second problem is that a collision demonstrates Newton's Third Law in that the obstacle moves on impact.

The most obvious way that I can think to make the avatar stop is to set the velocity to zero when I let go of the control key. For better or worse, however, the Box2D plugin in Gladius does not support the SetLinearVelocity(). Well, it supports it, but no matter how I call it, nothing happens:
b = avatarBox2d.box2dBody
// b2Body
// undefined
// undefined
Digging through the source a bit, it seems that SetLinearVelocity() needs a b2Vec object along the lines of:
box2dBody.SetLinearVelocity( new Box2D.b2Vec2( 0, 0 ) )
But as far as I can tell, the b2Vec object is not exposed by the Gladius Box2D plugin (yet).

No matter, I can make further use of Newton's First Law to solve this problem by exerting another force. In this case, I add friction (a.k.a. linear damping) to the avatar's motion:
        var avatarBodyDefinition = new box2d.BodyDefinition();
        avatarBox2d = new box2d.Body({
          bodyDefinition: avatarBodyDefinition,
          fixtureDefinition: fixtureDefinition
        av = new engine.Entity("avatar",
            new engine.core.Transform([0,0,0], [Math.PI/2, 0, 0]),
            new cubicvr.Model(resources.cone_mesh, resources.red_material),
            new input.Controller( resources.avatar_controls ),
            new engine.logic.Actor( avatarLogic )
This has the added benefit of not requiring any changes to the actor logic:
        var avatarLogic = {
          "Update": function(event) {
            if (!this.owner.hasComponent("Controller")) return;

            var impulse, force = 0.5;
            if (controller.states["moveLeft"]) {
              impulse = [-force, 0];
            // ...

            if (impulse) {
              new engine.Event("LinearImpulse", {impulse: impulse}).
Actually, I do make the force a little stronger to make the motion faster in the face of the linear damping. That aside, I keep the force in place as long as keys are being pressed to keep the avatar in the "moveLeft" state. As soon at I let go of the key, the actor is no longer in the "moveLeft" state, leaving the linear damping as the only force at play. The end result is that the avatar comes to a quick halt.

With a physics solution to my first physics engine problem out of the way, I turn to the movable obstacle that I would like to be immovable. For this, I can again thank Alan Kligman, who pointed out that I can make my obstacle static:
        var bodyDefinition = new box2d.BodyDefinition({
          type: box2d.BodyDefinition.BodyTypes.STATIC
        var fixtureDefinition = new box2d.FixtureDefinition({
          shape:new box2d.BoxShape(0.25,0.25)
        obstacleBox2d = new box2d.Body({
          bodyDefinition: bodyDefinition,
          fixtureDefinition: fixtureDefinition
With that, when my avatar (currently just a cone) impacts the sphere / obstacle, the avatar immediately halts and the obstacle does not move (event handlers do turn it yellow though):

That is a good stopping point for today. Up tomorrow, I am going to reassemble my avatar and use an immovable fence to keep the avatar confined to an island paradise. I am reasonably sure that I can do this without any problems. Which is to say: I expect at least two things to go horribly awry.

Day #473

No comments:

Post a Comment