feat(actors): build articulated dog v2
This commit is contained in:
@@ -11,9 +11,9 @@
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
buildDog,
|
||||
dogPoseStateForSpeed,
|
||||
disposeDog,
|
||||
poseDogAttention,
|
||||
poseDogWalk,
|
||||
poseDog,
|
||||
type DogRig,
|
||||
} from "../assets/actors/dog.ts";
|
||||
import {
|
||||
@@ -118,6 +118,9 @@ export function createOfficeWalker(plan: Plan, options: OfficeWalkerOptions): Of
|
||||
let enabled = options.active ?? false;
|
||||
let desired: WalkerAction = { x: 0, z: 0 };
|
||||
let gait = 0;
|
||||
let presentationSeconds = 0;
|
||||
let previousSpeed = 0;
|
||||
const previousFacing = new THREE.Vector2(0, -1);
|
||||
let faceTexture: THREE.Texture | null = null;
|
||||
let disposed = false;
|
||||
const root = new THREE.Group();
|
||||
@@ -135,16 +138,40 @@ export function createOfficeWalker(plan: Plan, options: OfficeWalkerOptions): Of
|
||||
view.position.copy(root.position);
|
||||
root.rotation.y = Math.atan2(-state.facing.x, -state.facing.z);
|
||||
|
||||
const speed = elapsedSeconds > 0 ? travelled / elapsedSeconds : 0;
|
||||
const speed = elapsedSeconds > 0 ? Math.max(0, travelled / elapsedSeconds) : 0;
|
||||
const targetGait = enabled && speed > 1e-5 ? Math.min(1, speed / (options.speed ?? 1.6)) : 0;
|
||||
gait += (targetGait - gait) * Math.min(1, elapsedSeconds / GAIT_EASE_SECONDS);
|
||||
const phase = (state.distance / STRIDE_METRES) * Math.PI * 2;
|
||||
presentationSeconds += elapsedSeconds;
|
||||
const phase = speed > 1e-5
|
||||
? (state.distance / STRIDE_METRES) * Math.PI * 2
|
||||
: presentationSeconds * 2.2;
|
||||
const facingDot = THREE.MathUtils.clamp(
|
||||
previousFacing.x * state.facing.x + previousFacing.y * state.facing.z,
|
||||
-1,
|
||||
1,
|
||||
);
|
||||
const facingCross = previousFacing.x * state.facing.z - previousFacing.y * state.facing.x;
|
||||
const turn = elapsedSeconds > 0
|
||||
? THREE.MathUtils.clamp(Math.atan2(facingCross, facingDot) / elapsedSeconds / 4, -1, 1)
|
||||
: 0;
|
||||
const acceleration = elapsedSeconds > 0
|
||||
? THREE.MathUtils.clamp((speed - previousSpeed) / elapsedSeconds / 5, -1, 1)
|
||||
: 0;
|
||||
if (actor.kind === "humanoid") {
|
||||
poseHumanoid(actor.rig, { walkPhase: phase, stride: gait * 0.62 });
|
||||
} else {
|
||||
poseDogWalk(actor.rig, phase, gait * 0.62);
|
||||
poseDogAttention(actor.rig, 0, state.distance * 5);
|
||||
const dogState = dogPoseStateForSpeed(speed * Math.max(gait, 0.2));
|
||||
poseDog(actor.rig, {
|
||||
state: dogState,
|
||||
phase,
|
||||
amount: dogState === "idle" ? 1 : THREE.MathUtils.clamp(0.38 + gait * 0.62, 0, 1),
|
||||
turn,
|
||||
acceleration,
|
||||
attentionYaw: -turn * 0.08,
|
||||
});
|
||||
}
|
||||
previousSpeed = speed;
|
||||
previousFacing.set(state.facing.x, state.facing.z);
|
||||
}
|
||||
|
||||
function snapshot(): OfficeWalkerState {
|
||||
@@ -202,6 +229,9 @@ export function createOfficeWalker(plan: Plan, options: OfficeWalkerOptions): Of
|
||||
const state = controller.reset(spawn);
|
||||
desired = { x: 0, z: 0 };
|
||||
gait = 0;
|
||||
presentationSeconds = 0;
|
||||
previousSpeed = 0;
|
||||
previousFacing.set(state.facing.x, state.facing.z);
|
||||
sync(state);
|
||||
return snapshot();
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user