## Monday, January 28, 2013

### Constrained Motion in Physijs

‹prev | My Chain | next›

Up tonight, I switch to a new Three.js / Physijs potential game for 3D Game Programming for Kids. This will be another 2D game, so I copy bits and pieces of last night's platform game.

In this game, the player will click, drag and rotate platforms to help the player reach a goal, normally near the top of the screen. The player itself can only move forward or backward, so ramps will be needed to move up.

The player is a simple Physijs object, shaped like a disc:
``````  var player = new Physijs.ConvexMesh(
new THREE.CylinderGeometry(30, 30, 5, 16),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({color:0xbb0000}), 0.2, 0.5
)
);

player.setAngularFactor(new THREE.Vector3( 0, 0, 0 )); // don't rotate
player.setLinearFactor(new THREE.Vector3( 1, 1, 0 )); // only move on X and Y axis``````
Since this is a 2D, not three dimensional game, I constrain movement to the X-Y plane. As with the platformer game, I use simple keyboard events to move the player:
``````  document.addEventListener("keydown", function(event) {
var code = event.keyCode;
if (code == 37) left();  // left arrow
if (code == 39) right(); // right arrow
});``````
The left and right functions set a maximum velocity in the appropriate direction.

All of that is more or less a copy from the previous game. What is new is that I need four borders that constrain the player to the current screen. Since the player is restricted to the X-Y plane, all four borders are added with Z=0. What changes is the X-Y position of each and the size:
``````  function makeBorder(x, y, w, h)  {
var border = new Physijs.BoxMesh(
new THREE.CubeGeometry(w, h, 100),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({color: 0x000000}), 0.2, 1.0
),
0
);
border.position.set(x, y, 0);
return border;
}``````
I think I might do this chapter after the introduction to JavaScript objects, in which case I might fiddle with default options. For now I require all four arguments.

With that function, and the browser `width` and `height` already calculated, I have my borders with:
``````  scene.add(makeBorder(width/-2, 0,         50,    height));
As for the ramps, I define a similar generator function. In this case, the shape will be fixed, but the rotation can change:
``````  function makeRamp(x, y, rotation) {
var ramp = new Physijs.ConvexMesh(
new THREE.CubeGeometry(50, 500, 10),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({color:0x0000cc}), 0.2, 1.0
),
0
);
ramp.rotation.set(0, 0, rotation);
ramp.position.set(x, y, 0);
return ramp;
}
``````
The last thing that I do tonight is to create a goal for the game. I add a hoop to the top-left corner of the window:
``````  var goal = new Physijs.ConvexMesh(
new THREE.TorusGeometry(90, 5, 5, 16),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({color:0x00bb00}), 0.2, 0.5
),
0
);
goal.position.set(width/-2, height/2, 0);
goal.isGoal = true;
The `isGoal` property is an easy way for the collision detection to determine how (or if) to handle the event:
``````  player.addEventListener('collision', function(object) {
console.log('Collision!');
if (object.isGoal) gameOver();
});``````
With that, I have a fairly functional game:

The code so far is available if anyone cares to try their luck. Up tomorrow, I will get started trying to figure out how best to expose the ability to move those ramps around the game area.

Day #644