My Three.js avatar controls are working fairly well. There are a couple of problems still lingering. The first that I hope to fix tonight is that the avatar is facing the wrong direction when moving left or right. I need for it to face left or right, but instead it continues to point forward.
This is not as simple as rotating the avatar about the y-axis (up and down):
function render() { // ... if (controls.moveLeft) avatar.rotation.y = -Math.PI/2; if (controls.moveRight) avatar.rotation.y = Math.PI/2; // ... }The problem with that approach is that the avatar is added to the entire scene:
avatar = buildAvatar();
scene.add(avatar);
By adding to the entire scene, the y-axis for the avatar is at the origin. In other words, if I rotate about the y-axis, I rotate about the origin and end up on the other side of the world.To make rotation work around the center of the avatar, I need to add a frame of reference for the avatar:
avatar = buildAvatar();
var a_frame = new THREE.Object3D();
a_frame.add(avatar);
scene.add(a_frame);
Instead of tying the FirstPersonControls
to the avatar, I now need to tie them to this frame of reference: avatar = buildAvatar();
var a_frame = new THREE.Object3D();
a_frame.add(avatar);
scene.add(a_frame);
controls = new THREE.FirstPersonControls(a_frame);
controls.movementSpeed = 10000;
controls.activeLook = false;
Now, rotating the avatar about the y-axis will rotate around the new a_frame
y-axis, so this will work:function render() { // ... if (controls.moveLeft) avatar.rotation.y = -Math.PI/2; if (controls.moveRight) avatar.rotation.y = Math.PI/2; // ... }And, indeed it does work as I walk from left to right, I am facing the direction in which I am walking:
Last up tonight, I would like the transition from walking forward to walking to the side to be smoother. Currently, moving to the side immediately renders the avatar facing to the side.
For that, I am going to use Tween, which comes along with Three.js in
examples/js/Tween.js
. After copying that into my /scripts
directory, I update the HTML to source this library in addition to Three.js:<!DOCTYPE html> <html> <head> <script src="/scripts/Three.js"></script> <script src="/scripts/Tween.js"></script> <script src="/scripts/avatar.js"></script> <title>Avatar</title> </head> <body> </body> </html>Next, I update the usual Three.js
animate()
function to update any active "Tweens":function animate() { // note: three.js includes requestAnimationFrame shim requestAnimationFrame(animate); TWEEN.update(); render(); }Without a running "tween", this has no effect. So I add one. The animation that I desire is for the avatar to rotate from its current y-axis frame of reference rotation to some end-angle (e.g. +90° or -90°). In tween-ese, this means starting an object's
y
property at the avatar's current rotation, describing the end state for the y
rotation and the number of milliseconds that the animation should take. Lastly, I need an onUpdate
callback that will effect slight change on the avatar:function spinAvatar(angle) { new TWEEN.Tween( { y: avatar.rotation.y } ) .to( { y: angle }, 100 ) .onUpdate( function () { avatar.rotation.y = this.y; } ) .start(); }That is a nice, compact DSL for describing changes over time. I like it. It certainly beats trying to manually keep track of the rotation myself in the game's
animate()
function.I swap out the immediate angle changes for this
spinAvatar()
tween:function render() { // ... if (controls.moveForward || controls.moveBackward || controls.moveRight || controls.moveLeft) { // ... if (controls.moveLeft) spinAvatar(-Math.PI/2); if (controls.moveRight) spinAvatar(Math.PI/2); } else { spinAvatar(0); } // ... }And it works! I have a nice, smooth rotation immediately when the avatar starts walking, giving the whole thing a nice feel.
Day #457
Could you post a full sample code using the above..?
ReplyDeleteI believe that the full version is located at: https://github.com/eee-c/threejs-my/blob/gh-pages/scripts/avatar.js. That version may have additional tweaks and may not correspond exactly to this post, but it looks close after skimming it.
Delete