Thursday, August 23, 2012

Rotation Motion Controls in Three.js

‹prev | My Chain | next›

I enjoyed a huge breakthrough last night. It's one of those breakthroughs that makes a developer's pain and struggles all seem worthwhile. Where you finally have a brilliant stroke of genius to solve a problem in a new or unexpected way. Or, you actually read the documentation. Anyhow...

With my Three.js Physijs rafting simulation in better shape, I am ready to add motion controls to the raft.

First I add a "rudder" to the raft to indicate the direction in which the raft is pointing. I do not have to mess with Physijs for this, since it is just an indicator. I do have to mess around with manual veritices in Three.js in order to create a line:
  var geometry = new THREE.Geometry();
  geometry.vertices.push(new THREE.Vector3(0, 0, 0));
  geometry.vertices.push(new THREE.Vector3(10, 0, 0));
  var rudder = new THREE.Line(
    geometry,
    new THREE.LineBasicMaterial({color: 0xff0000})
  );
  rudder.position.z = 0;
  rudder.position.x = 35;
  raft.add(rudder);

  raft.position.y = 20;
  raft.rotation.x = Math.PI/2;
I suspect that it might be easier to create a cylinder, but I am glad for a way to create lines. With that, I have my direction indicated:


To add motion controls, first I use the space bar to add a force in the current direction. A simple document listener ought to suffice:
document.addEventListener("keydown", function(event) {
  var code = event.which || event.keyCode;
  if (code == 0x20) { // space
    pushRaft();
  }
  else {
    console.log(code);
  }
});

function pushRaft() {
  var angle = raft.rotation.z
    , cos = Math.cos(angle)
    , sin = Math.sin(angle);

  raft.applyCentralForce(new THREE.Vector3(1e8 * cos, 0, 1e8 * sin));
}
And indeed that does work. I am able to move forward in whatever direction I happen to be pointing.

I need a little more than that in my game, however. I need to be able to steer clear of trouble. For that, I add two more keys to listen for: J/K. When one of those is pressed, I rotate the raft accordingly:
document.addEventListener("keydown", function(event) {
  var code = event.which || event.keyCode;
  if (code == 0x20) { // space
    pushRaft();
  }
  else if (code == 0x4a) { // J
    rotateRaft(-1);
  }
  else if (code == 0x4b) { // K
    rotateRaft(1);
  }
  else {
    console.log(code);
  }
});

function rotateRaft(direction) {
  raft.__dirtyRotation = true;
  raft.rotation.z = raft.rotation.z + direction * Math.PI / 100;
}
And that actually works I am now able to rotate and move my raft. Two problems still remain.

First, when I collide with a river bank, the raft sometimes gets some angular velocity. I can likely solve that with some Physijs damping.

Second, when I apply enough force, I can move back upriver. The force that I applied last night from the river needs to be constant and greater than the force that my raft can exert. That seems a trickier proposition. Hopefully I will come up with something tomorrow.



Day #487

No comments:

Post a Comment