Friday, August 10, 2012

Gladius Invisible Fences with Box2D

‹prev | My Chain | next›

I had me a small breakthrough with Box2D.js and Gladius last night. At this point, I have a stripped down avatar able to move (and stop) with input controls, plus I can stop that when it runs into a static obstacle. I believe that this is sufficient to re-implement my Three.js avatar island in Gladius.

Famous last words...

One problem that I do not face is ensuring that my avatar and obstacle are in the same Z plane (up and down in my current orientation). The reason is that Box2D is a two dimensional engine. Anything along the z-axis is projected onto the XY plane. Thus, even if I place my obstacle way up high:
        var obstacle = new engine.Entity("obstacle",
          [
            new engine.core.Transform([-10, 0, 10], [Math.PI, 0, 0]),
            obstacleBox2d,
            new cubicvr.Model(resources.sphere_mesh, resources.grey_material)
          ]
        );
        space.add(obstacle);
Then I still see a collision as I near the x-y coordinates. Before the x-y coordinates are colliding, the obstacle is grey:


Once I move far enough, the obstacle signals collision by turning yellow and, since the obstacle is static, I am prevented from moving further:


With my accumulated Box2D knowledge, I proceed by defining a generic (rectangular) obstacle maker:
        function makeObstacle(x_length, y_length) {
          var STATIC = box2d.BodyDefinition.BodyTypes.STATIC
            , bodyDef = new box2d.BodyDefinition({type: STATIC})
            , fixtureDef = new box2d.FixtureDefinition({
                shape:new box2d.BoxShape(x_length, y_length)
              });

          var body = new box2d.Body({
            bodyDefinition: bodyDef,
            fixtureDefinition: fixtureDef
          });

          body.onContactBegin = function() {
            console.log("Obstable "+ this.owner.name +" contact begin");
          };
          body.onContactEnd = function() {
            console.log("Obstable "+ this.owner.name +" contact end");
          };

          return body;
        }
With that, I can define, my invisible avatar fence:
space.add(new engine.Entity("obstacle-left",
          [
            new engine.core.Transform([-10, 0, 0], [Math.PI, 0, 0]),
            makeObstacle(0.25, 100)
          ]
        ));
        space.add(new engine.Entity("obstacle-right",
          [
            new engine.core.Transform([10, 0, 0], [Math.PI, 0, 0]),
            makeObstacle(0.25, 100)
          ]
        ));
        space.add(new engine.Entity("obstacle-back",
          [
            new engine.core.Transform([0, 10, 0], [Math.PI, 0, 0]),
            makeObstacle(100, 0.25)
          ]
        ));
        space.add(new engine.Entity("obstacle-front",
          [
            new engine.core.Transform([0, -10, 0], [Math.PI, 0, 0]),
            makeObstacle(100, 0.25)
          ]
        ));
After reinstating the island and sea objects, my minimalist avatar is constrained to the island:


Restoring the remainder of the avatar ends up being as simple as uncommenting code. All of the pieces (moving and otherwise) were defined relative to the avatar's frame of reference. Since the frame of reference is already working with the Box2D fence, it all just works:


The fully restored avatar is able to swing its arms and legs as it moves about its tiny island, but it cannot leave the island.

In the end, I am unsure what I like better about Box2D collisions: the event-based collision callback handlers or the fact that I do not have to use them for static objects like my fence. Either way, Box2D is a win, even in this early version of Gladius.


Day #474

No comments:

Post a Comment