Files
basket_utils/src/playerAvatar.js
T

41 lines
2.5 KiB
JavaScript

import * as THREE from 'three';
// Lightweight articulated fallback until an authored, rigged player asset is supplied.
export function createPlayerAvatar(color) {
const avatar = new THREE.Group(); avatar.name = 'avatar'; avatar.position.y = -0.35;
const uniform = new THREE.MeshStandardMaterial({ color, roughness: 0.9 });
const skin = new THREE.MeshStandardMaterial({ color: 0xb77d58, roughness: 0.9 });
const dark = new THREE.MeshStandardMaterial({ color: 0x182536, roughness: 1 });
function mesh(geometry, material, parent, x, y, z) {
const object = new THREE.Mesh(geometry, material); object.position.set(x, y, z); parent.add(object); return object;
}
mesh(new THREE.CylinderGeometry(0.23, 0.19, 0.55, 10), uniform, avatar, 0, 1.23, 0);
mesh(new THREE.BoxGeometry(0.39, 0.25, 0.25), dark, avatar, 0, 0.87, 0);
const head = new THREE.Group(); head.name = 'head'; head.position.y = 1.65; avatar.add(head);
mesh(new THREE.SphereGeometry(0.17, 12, 10), skin, head, 0, 0, 0);
mesh(new THREE.BoxGeometry(0.065, 0.055, 0.09), skin, head, 0, -0.015, 0.16);
for (const side of [-1, 1]) {
const arm = new THREE.Group(); arm.name = side < 0 ? 'leftArm' : 'rightArm'; arm.position.set(side * 0.29, 1.43, 0); avatar.add(arm);
mesh(new THREE.CapsuleGeometry(0.075, 0.42, 3, 8), skin, arm, 0, -0.25, 0);
const leg = new THREE.Group(); leg.name = side < 0 ? 'leftLeg' : 'rightLeg'; leg.position.set(side * 0.12, 0.83, 0); avatar.add(leg);
mesh(new THREE.CapsuleGeometry(0.085, 0.5, 3, 8), skin, leg, 0, -0.36, 0);
mesh(new THREE.BoxGeometry(0.18, 0.12, 0.31), dark, leg, 0, -0.74, 0.055);
}
return avatar;
}
export function posePlayerAvatar(avatar, sample, location, time, shooting) {
const stride = sample?.phase === 'move' ? Math.sin(time * 11) * 0.4 : 0;
avatar.getObjectByName('leftLeg').rotation.x = stride;
avatar.getObjectByName('rightLeg').rotation.x = -stride;
const passing = sample?.phase === 'pass';
avatar.getObjectByName('leftArm').rotation.x = shooting ? -2.6 : passing ? -1.35 : -stride * 0.65;
avatar.getObjectByName('rightArm').rotation.x = shooting ? -2.6 : passing ? -1.35 : stride * 0.65;
const target = sample?.lookAtLocation; const head = avatar.getObjectByName('head');
if (target) {
const desired = Math.atan2(target.x - location.x, target.z - location.z) - (sample.facing || 0);
const angle = Math.atan2(Math.sin(desired), Math.cos(desired));
head.rotation.y = THREE.MathUtils.clamp(angle, -Math.PI * 0.42, Math.PI * 0.42);
} else head.rotation.y = 0;
}