‹prev |
My Chain |
next›
Yesterday, I discovered the benefits of
__dirtyRotation
in
Physijs, this physics engine for
Three.js. I used it yesterday to prevent my player from spinning out of control after contact with other objects. Tonight, I plan to use it to restore the spin-to-walk ability.
I am not going to rewrite the Three.js first person controls, but I need some of that ability. I start with global variables that hold state (moving and state):
var moving = false;
var controlState = {};
Next, I need a keydown handler to set the state:
document.addEventListener("keydown", function(event) {
// Last wins (for now) because we set the velocity, not apply force
function setState(state) {
moving = true;
controlState = {};
controlState[state] = true;
}
var speed = 500;
var code = event.which || event.keyCode;
if (code == 0x57) { // w
setState("moveForward");
a_frame.setLinearVelocity({z: -speed, y: 0, x: 0 });
}
// ...
});
I feel a little bad about overwriting
controlState
and the velocity like that, but it works for now—movement is only in one direction.
I also use a corresponding keyup handler to reset
controlState
and mark the avatar as no longer moving:
document.addEventListener("keyup", function(event) {
function stopState(state) {
if (controlState[state]) {
moving = false;
controlState = {};
}
}
var code = event.which || event.keyCode;
if (code == 0x57) { // w
stopState("moveForward");
// a_frame.setLinearVelocity({z: 0, y: 0, x: 0 });
}
// ...
});
This allows me to restore the motion of the legs when
moving
is
true
. I can also spin the avatar in the proper direction depending on the controls' state:
var w = 500;
function render() {
var t_float = clock.getElapsedTime()
, t = t_float * 1000
, amplitude = (w/2 - Math.abs((t % (2*w)) - w))/w;
if (moving) {
avatar_left_leg.rotation.x = amplitude*(Math.PI/6);
// ...
if (controlState.moveLeft) spinAvatar(-Math.PI/2);
// ...
}
else {
spinAvatar(0);
}
scene.simulate(); // run physics
renderer.render(scene, camera);
}
Even the
spinAvatar()
function still works. It works because it spins the avatar inside the Physijs frame so no changes are required:
function spinAvatar(angle) {
new TWEEN.Tween( { y: avatar.rotation.y } )
.to( { y: angle }, 100 )
.onUpdate( function () {
avatar.rotation.y = this.y;
})
.start();
}
So it turns out that I did not need any additional use of
__dirtyRotation
. As long as it keeps the frame of reference steady, everything just works. Nice.
This is all going so smoothly. Something is going to go horribly wrong soon. I just know it.
But failure does not arrive when I set up invisible fences around the island:
scene = new Physijs.Scene;
var fence = new Physijs.BoxMesh(
new THREE.CubeGeometry(ISLAND_WIDTH, 1000, 10),
new THREE.Material(),
0
);
fence.position.z = -ISLAND_HALF;
fence.position.y = 500;
scene.add(fence);
The last argument of zero to the
BoxMesh
constructor specifies a mass of zero, which is interpreted as a static object in Physijs. In other words, my fence will not yield, keeping the avatar on the island:
I finally do run into a small problem with the avatar's interaction with the ball that I have left on the island for the avatar's amusement. My avatar can no longer budge it:
What fun is that?
Fortunately, it does not take too long to identify the problem. I specified a mass of 1000 for my avatar's frame of reference / Physijs box:
a_frame = new Physijs.BoxMesh(
new THREE.CubeGeometry(250, 250, 250),
new THREE.Material(),
1000
);
It seems that, in Physijs, 1000 is very light. I suppose it is measured in grams.
Anyhow, with a slightly heavier mass:
a_frame = new Physijs.BoxMesh(
new THREE.CubeGeometry(250, 250, 250),
new THREE.Material(),
1000*1000*1000
);
I can now send my ball rolling and bouncing around:
It is literally minutes of fun!
Actually, what this really means is that I seem to have gotten the hang of Physijs.
Day #481