Monday, August 6, 2012

Box2D (emphasis 2D) Collisions in Gladius

‹prev | My Chain | next›

For the last day or two, I've been struggling with Box2D.js collision detection in Gladius. I was able to get the plugin sourced and running. I was even able to get some collisions detected. But I was thwarted when trying to detect collisions along the z-axis. Everything was registering as a collision.

Luckily, Gladius has some very helpful authors. Late last night, Alan Kligman pointed out what I was not seeing: that Box2D.js is only a 2D library. By default, Box2D is detecting collisions in the XY plane. Anything along the z-axis is projected down onto the XY plane, meaning that I will see collisions if the XY coordinates of colliding objects align—even if they are separated by 1,000,000 pixels in along the z-axis.

In my avatar simulation, the x-axis runs from left to right:


That is perfectly OK, but the y-axis (the other axis on which collision coordinates matter), is up-and-down. Since the avatar is constrained to walking on the island, the y-axis coordinate is always zero. In other words, I am trying to detect collisions in a useless dimension.

My first inclination is to rotate the Box2D entities into the XZ plane. Rotating 90° about the y-axis ought to shift the collision planes from XY to XZ:
        var obstacle = new engine.Entity( "obstacle-box2d",
          [
            new engine.core.Transform([0, 0, 10], [Math.PI/2, 0, 0]),
            obstacleBox2d,
            new cubicvr.Model( resources.sphere_mesh, resources.yellow_material )
          ]
        );
        space.add( obstacle );

        space.add(new engine.Entity("avatar-box2d",
          [
            new engine.core.Transform([0, 0, 0], [Math.PI/2, 0, 0]),
            avatarBox2d
          ],
          [],
          space.findNamed("avatar")
        ));
Only this has no effect. Immediately after page load, I still see a collision event from the callback:
        var bodyDefinition = new box2d.BodyDefinition();
        var fixtureDefinition = new box2d.FixtureDefinition({
          shape:new box2d.BoxShape(0.25,0.25)
        });
        var obstacleBox2d = new box2d.Body({
          bodyDefinition: bodyDefinition,
          fixtureDefinition: fixtureDefinition
        });

        obstacleBox2d.onContactBegin = function(event){
          console.log("Obstable contact begin");
         this.owner.findComponent( "Model").setMaterialDefinition(resources.grey_material);
        };
So it seems that everything really needs to be in the XY plane. This is a bit of a pain, but I re-position the camera along the y-axis (instead of the usual z-axis) and rotate back to the origin:
        space.add(new engine.Entity("camera",
          [
            new engine.core.Transform([0, -25, 5], [Math.PI/2, 0, 0]),
            new cubicvr.Camera()
          ]
        ));
After removing the previous rotation attempts, I now see no collision as I place the obstacle anywhere in the XY plane (the obstacle remains yellow unless there is a collision):





But if there is an actual collision, the obstacle detects it:



At this point, I have broken my avatar down to the most basic pieces in order to understand the problem. Tomorrow, I am going to put it back together to make sure that it all still works.

Day #470

No comments:

Post a Comment