puppet face cam when idle
This commit is contained in:
@@ -1,12 +1,21 @@
|
||||
import * as THREE from "three";
|
||||
import type { PuppetRig } from ".";
|
||||
|
||||
const MIN_IDLE_FACING_OFFSET_DEGREES = 3;
|
||||
const MAX_IDLE_FACING_OFFSET_DEGREES = 5;
|
||||
|
||||
export class PuppetAnimation {
|
||||
private readonly smoothedGroundPosition = new THREE.Vector3();
|
||||
private readonly movementDelta = new THREE.Vector3();
|
||||
private readonly idleRotationY: number;
|
||||
private idleTargetRotationY: number;
|
||||
private hasSmoothedPosition = false;
|
||||
private wasMoving = false;
|
||||
|
||||
constructor(private readonly rig: PuppetRig) {}
|
||||
constructor(private readonly rig: PuppetRig) {
|
||||
this.idleRotationY = rig.root.rotation.y;
|
||||
this.idleTargetRotationY = this.idleRotationY;
|
||||
}
|
||||
|
||||
update(
|
||||
targetGroundPosition: THREE.Vector3,
|
||||
@@ -14,6 +23,8 @@ export class PuppetAnimation {
|
||||
deltaSeconds: number,
|
||||
elapsedSeconds: number,
|
||||
) {
|
||||
this.updateIdleTarget(isMoving);
|
||||
|
||||
if (!this.hasSmoothedPosition) {
|
||||
this.smoothedGroundPosition.copy(targetGroundPosition);
|
||||
this.rig.root.position.copy(targetGroundPosition);
|
||||
@@ -27,6 +38,9 @@ export class PuppetAnimation {
|
||||
if (this.movementDelta.lengthSq() <= 0.01) {
|
||||
this.pause();
|
||||
this.rig.root.position.copy(targetGroundPosition);
|
||||
if (!isMoving) {
|
||||
this.turnTowards(this.idleTargetRotationY, deltaSeconds);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,20 +48,14 @@ export class PuppetAnimation {
|
||||
this.smoothedGroundPosition.lerp(targetGroundPosition, alpha);
|
||||
this.rig.root.position.copy(this.smoothedGroundPosition);
|
||||
|
||||
const targetRotationY = Math.atan2(
|
||||
this.movementDelta.x,
|
||||
this.movementDelta.z,
|
||||
);
|
||||
this.rig.root.rotation.y = this.dampAngle(
|
||||
this.rig.root.rotation.y,
|
||||
targetRotationY,
|
||||
14,
|
||||
deltaSeconds,
|
||||
);
|
||||
|
||||
if (isMoving) {
|
||||
this.turnTowards(
|
||||
Math.atan2(this.movementDelta.x, this.movementDelta.z),
|
||||
deltaSeconds,
|
||||
);
|
||||
this.animateWalkCycle(elapsedSeconds);
|
||||
} else {
|
||||
this.turnTowards(this.idleTargetRotationY, deltaSeconds);
|
||||
this.pause();
|
||||
}
|
||||
}
|
||||
@@ -59,6 +67,34 @@ export class PuppetAnimation {
|
||||
this.rig.rightArm.rotation.x *= 0.8;
|
||||
}
|
||||
|
||||
private updateIdleTarget(isMoving: boolean) {
|
||||
if (isMoving) {
|
||||
this.wasMoving = true;
|
||||
return;
|
||||
}
|
||||
if (!this.wasMoving) return;
|
||||
|
||||
const magnitudeDegrees = THREE.MathUtils.lerp(
|
||||
MIN_IDLE_FACING_OFFSET_DEGREES,
|
||||
MAX_IDLE_FACING_OFFSET_DEGREES,
|
||||
Math.random(),
|
||||
);
|
||||
const direction = Math.random() < 0.5 ? -1 : 1;
|
||||
this.idleTargetRotationY =
|
||||
this.idleRotationY +
|
||||
THREE.MathUtils.degToRad(magnitudeDegrees * direction);
|
||||
this.wasMoving = false;
|
||||
}
|
||||
|
||||
private turnTowards(targetRotationY: number, deltaSeconds: number) {
|
||||
this.rig.root.rotation.y = this.dampAngle(
|
||||
this.rig.root.rotation.y,
|
||||
targetRotationY,
|
||||
14,
|
||||
deltaSeconds,
|
||||
);
|
||||
}
|
||||
|
||||
private dampAngle(
|
||||
currentRadians: number,
|
||||
targetRadians: number,
|
||||
|
||||
@@ -4,6 +4,8 @@ import type { World } from "../world";
|
||||
import { PuppetAnimation } from "./animation";
|
||||
import { PuppetSkin } from "./skin";
|
||||
|
||||
const CAMERA_FACING_ROTATION_Y = Math.PI / 4;
|
||||
|
||||
export type PuppetRig = {
|
||||
root: THREE.Group;
|
||||
body: THREE.Mesh<THREE.BoxGeometry, THREE.Material | THREE.Material[]>;
|
||||
@@ -89,6 +91,7 @@ export class Puppet {
|
||||
|
||||
private createRig(): PuppetRig {
|
||||
const root = new THREE.Group();
|
||||
root.rotation.y = CAMERA_FACING_ROTATION_Y;
|
||||
const material = new THREE.MeshStandardMaterial();
|
||||
|
||||
const body = new THREE.Mesh(
|
||||
|
||||
Reference in New Issue
Block a user