freeblox/packages/engine/src/utils/character.ts

96 lines
2.6 KiB
TypeScript

import { AnimationClip, Bone, Object3D, SkinnedMesh, Vector3 } from 'three';
import { assetManager } from '../assets';
import { Group } from '../gameobjects/group.object';
import { MeshPart } from '../gameobjects/mesh.object';
import { Humanoid } from '../gameobjects/humanoid.object';
import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js';
const cachedMeta: {
faceTexture: string;
root: Object3D | null;
clips: AnimationClip[];
} = {
faceTexture: '',
root: null,
clips: [],
};
export const loadBaseCharacter = async () => {
if (cachedMeta.root) return cachedMeta;
// TODO: temporary loading method
const loadMesh = await assetManager.loadMeshData(
'https://lunasqu.ee/freeblox/character-base.glb'
);
const loadFace = await assetManager.createAsset(
'https://lunasqu.ee/freeblox/face-1.png',
'CharacterFace1',
'Texture'
);
loadFace.texture!.flipY = false;
loadFace.texture!.needsUpdate = true;
cachedMeta.faceTexture = loadFace.path!;
cachedMeta.root = loadMesh.scene;
cachedMeta.clips = loadMesh.animations;
return cachedMeta;
};
export const instanceCharacterObject = async (
name: string,
pos = new Vector3(0, 1, 0),
uuid?: string
) => {
const base = await loadBaseCharacter();
const cloned = SkeletonUtils.clone(base.root!);
const baseObject = new Group();
const armature = cloned.getObjectByName('Armature');
const bone = armature!.getObjectByName('BRoot');
const bodyParts = [
armature!.getObjectByName('Head'),
armature!.getObjectByName('Torso'),
armature!.getObjectByName('ArmL'),
armature!.getObjectByName('ArmR'),
armature!.getObjectByName('LegR'),
armature!.getObjectByName('LegL'),
] as SkinnedMesh[];
const convertedBodyParts = bodyParts.map(MeshPart.fromLoaded);
const [head, torso, armL, armR, legR, legL] = convertedBodyParts;
head.name = 'Head';
torso.name = 'Torso';
armL.name = 'ArmLeft';
armR.name = 'ArmRight';
legR.name = 'LegRight';
legL.name = 'LegLeft';
baseObject.animations = base.clips;
baseObject.add(bone as Bone);
baseObject.archivable = false;
baseObject.name = name;
convertedBodyParts.forEach((object) => {
baseObject.add(object);
object.archivable = false;
});
head.texture = base.faceTexture;
const controller = new Humanoid();
controller.position.set(0, 4.75, 0);
controller.archivable = false;
if (uuid) controller.uuid = uuid;
baseObject.add(controller);
baseObject.position.copy(pos);
return baseObject;
};
export const getCharacterController = (object: Object3D) => {
return object.getObjectByName('Humanoid') as Humanoid;
};