This advanced method uses velocity vectors to create more realistic following behavior with acceleration, deceleration, and damping.
// Velocity-Based Following
const maxSpeed = 0.5;
const acceleration = 0.02;
let velocity = new THREE.Vector3();
function updateFollower() {
const direction = new THREE.Vector3();
direction.subVectors(target.position, follower.position);
if (direction.length() > 0.1) {
direction.normalize();
velocity.addScaledVector(direction, acceleration);
if (velocity.length() > maxSpeed) {
velocity.normalize().multiplyScalar(maxSpeed);
}
} else {
velocity.multiplyScalar(0.9); // Damping
}
follower.position.add(velocity);
}
Combines position following with rotation tracking so the follower always faces the target.
// Following with Look-At Behavior
const followSpeed = 0.1;
function updateFollower() {
follower.position.lerp(target.position, followSpeed);
follower.lookAt(target.position);
}
A production-ready, reusable class that combines all methods into one flexible solution you can drop into any project.
class ObjectFollower {
constructor(follower, target, options = {}) {
this.follower = follower;
this.target = target;
this.followSpeed = options.followSpeed || 0.1;
this.distance = options.distance || null;
this.lookAt = options.lookAt || false;
this.velocity = new THREE.Vector3();
this.useVelocity = options.useVelocity || false;
this.maxSpeed = options.maxSpeed || 0.5;
}
update() {
if (this.useVelocity) {
this.updateWithVelocity();
} else if (this.distance) {
this.updateWithDistance();
} else {
this.updateSimple();
}
if (this.lookAt) {
this.follower.lookAt(this.target.position);
}
}
updateSimple() {
this.follower.position.lerp(
this.target.position, this.followSpeed
);
}
updateWithDistance() {
const dir = new THREE.Vector3()
.subVectors(this.follower.position, this.target.position)
.normalize();
const desired = this.target.position.clone()
.addScaledVector(dir, this.distance);
this.follower.position.lerp(desired, this.followSpeed);
}
updateWithVelocity() {
const dir = new THREE.Vector3()
.subVectors(this.target.position, this.follower.position);
if (dir.length() > 0.1) {
dir.normalize();
this.velocity.addScaledVector(dir, 0.02);
if (this.velocity.length() > this.maxSpeed) {
this.velocity.normalize().multiplyScalar(this.maxSpeed);
}
} else {
this.velocity.multiplyScalar(0.9);
}
this.follower.position.add(this.velocity);
}
}
// Usage:
const follower = new ObjectFollower(camera, player, {
followSpeed: 0.1,
distance: 5,
lookAt: true,
useVelocity: false
});
// In your animation loop:
function animate() {
follower.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}