import { Component, type ReactNode } from "react"; import type { CharacterRigState, MotionClip } from "../schema/directorProject"; import { PrimitiveMannequin } from "./PrimitiveMannequin"; import { UE4MannequinModel } from "./UE4MannequinModel"; import { GltfCharacterModel } from "./GltfCharacterModel"; import type { CharacterBodyType } from "./mannequin/bodyTypes"; import { getActiveMotionClipAtTime, resolveMotionClipEnd } from "./mannequin/motion"; interface CharacterModelProps { bodyType?: CharacterBodyType; color?: string; onLabelAnchorYChange?: (anchorY: number) => void; rigState?: CharacterRigState; motionTime?: number; characterId?: string; /** 动作片段起点(秒):基础动作只在该时间区间内驱动角色,缺省视为时间轴开头 */ motionStartTime?: number; /** 动作片段终点(秒):缺省视为时间轴末尾 */ motionEndTime?: number; /** 时间轴上的动作片段序列(多段动作)。存在时按播放时间取当前片段覆盖上面的单一 motion。 */ motionClips?: MotionClip[]; /** 时间轴总时长(秒),用于解析到末尾的动作片段。 */ duration: number; /** 当 rigState.modelAssetId 指向一个导入的 GLB/GLTF 资产时,其可访问的 url(用于渲染该角色几何)。 */ modelAssetUrl?: string; } class CharacterModelBoundary extends Component< { fallback: ReactNode; children: ReactNode; }, { hasError: boolean; } > { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { return this.state.hasError ? this.props.fallback : this.props.children; } } export function CharacterModel({ bodyType, color, onLabelAnchorYChange, rigState, motionTime, characterId, motionStartTime, motionEndTime, modelAssetUrl, motionClips, duration }: CharacterModelProps) { // 动作序列:按当前播放时间取出应生效的片段(后段覆盖前段),用它覆盖单一 motion 字段。 // 无片段 / 时间不在任何片段内 → 回退到旧的单一段落(rigState.motion + motionStartTime/EndTime)。 const activeClip = getActiveMotionClipAtTime(motionClips, motionTime ?? 0, duration); const resolvedRigState: CharacterRigState | undefined = activeClip && rigState ? { ...rigState, motion: activeClip } : rigState; const resolvedStart = activeClip ? activeClip.start : motionStartTime; const resolvedEnd = activeClip ? resolveMotionClipEnd(activeClip, duration) : motionEndTime; const fallback = ; // 导入的 GLB/GLTF 人形角色:几何来自资产,用通用人形骨骼映射驱动程序化动作。 if (rigState?.modelAssetId && modelAssetUrl) { return ( ); } if (rigState?.rigType !== "ue4-mannequin") { return fallback; } return ( ); }