跳到主要内容

<pc-anim>

<pc-anim> 在实体层级上播放动画,例如角色行走、机械连续动作或开门。

用法

片段来源​

组件自动选择以下两种方式:

显式片段。 各 <pc-anim-clip> 提供一个命名动作,适合自定义名称、逐片段速度/循环,或混合多个文件:

<pc-model name="robot" asset="arm">
<pc-anim clip="idle" transition-time="0.35">
<pc-anim-clip name="idle"></pc-anim-clip>
<pc-anim-clip name="pick"></pc-anim-clip>
<pc-anim-clip name="stow" loop="false"></pc-anim-clip>
</pc-anim>
</pc-model>

模型全部动画。 无片段子项且直接位于 <pc-model> 内时,按容器顺序添加全部动画,以轨道命名。空标签即可播放 GLB 自带内容:

<pc-model name="t-rex" asset="t-rex">
<pc-anim></pc-anim>
</pc-model>

显式片段优先,添加任一子片段会切换为声明集合。默认自动播放第一段,可用 activate=false 关闭。

名称包含点号或与更早轨道重复时会跳过并逐项警告,点号保留给混合树路径。

直接位于模型内时,组件附加到模型宿主,不需要也不应额外包装实体。模型内容在同宿主下,动画可以访问。修改 asset 保留宿主及组件,并重新针对新容器解析片段。

属性​

属性类型默认值说明
activateBoolean(布尔)"true"分配片段后自动播放,不会停止已在播放的动作
clipString(字符串)第一个分配片段活动片段名称,修改后按 transition-time 淡变。无匹配时警告并保留选择
enabledBoolean(布尔)"true"组件启用状态
speedNumber(数字)"1"全部片段的速度倍率,0 冻结
transition-timeNumber(数字)"0"通过 clip 切换时的淡变秒数,0 为硬切

此处 speed 与逐片段速度相乘,例如片段 1.4、组件 0.5,最终 0.7。

切换片段​

clip 实时指定播放项,可从标记、开发者工具或 JavaScript 修改。transition-time 大于 0 时交叉淡变,避免角色姿态突变:

<pc-anim id="hero" clip="idle" transition-time="0.3">
<pc-anim-clip name="idle"></pc-anim-clip>
<pc-anim-clip name="run"></pc-anim-clip>
</pc-anim>
document.getElementById('hero').setAttribute('clip', 'run'); // cross-fades over 0.3s

元素方法补充属性无法表达的操作,例如默认淡变时临时硬切、指定一次性时长和暂停:

const anim = document.getElementById('hero');

anim.play('run'); // hard cut, ignoring transition-time
anim.transition('idle', 1); // one-second fade, just this once
anim.pause(); // freeze, keeping the playhead
anim.play(); // resume from where it stopped

未知名称保留原播放。clip 会在控制台警告,play() 与 transition() 则静默忽略。

轨道如何绑定​

轨道按节点名称绑定到组件实体下的整个层级。骨架是常见情况,但普通刚性层级也适用。机械臂示例无需蒙皮即可驱动十个部件。

引擎只解析曲线一次,不重试。元素会在下方模型就绪时重新绑定,并在来源模型重新实例化后刷新动作库,因此运行时修改模型 asset也能自动工作。

还会将 rootBone 指向所属模型宿主,使根节点曲线正确绑定。每轮重新推导,无法确定单一模型时清空;通过引擎 API 手动设置的 rootBone 则会被识别并保留。

注意,引擎不报告片段完成。非循环动作停在末姿态但无 end 事件。需要检测时,比较底层层的活动时间与轨道时长:

const { baseLayer } = anim.component;
const done = baseLayer.activeStateCurrentTime >= baseLayer.activeStateDuration;

这适合正放。负 speed 从零向下计时,不会到达正的 duration。

示例​

单轨行走 GLB 声明为正常 walk 和三分之一速度 stalk,通过 transition-time=0.4 淡变。可修改逐片段 speed、关闭 activate,或移除子片段和 clip="walk",恢复自动播放模型自带动画:

实时示例
<pc-app>
<pc-asset src="https://cdn.jsdelivr.net/npm/[email protected]/scripts/esm/camera-controls.mjs"></pc-asset>
<pc-asset src="https://developer.playcanvas.com/assets/t-rex.glb" id="t-rex"></pc-asset>
<pc-material id="floor" diffuse="#3a3f4b"></pc-material>
<pc-scene>
<pc-entity name="camera" position="2.5 1.5 3.5">
<pc-camera clear-color="#2a2d36"></pc-camera>
<pc-script>
<pc-script-instance name="cameraControls" focus-point="0 1.2 0" pitch-range="-90 0" zoom-range="1.5 10"></pc-script-instance>
</pc-script>
</pc-entity>
<pc-entity name="light" rotation="45 30 0">
<pc-light cast-shadows normal-offset-bias="0.05" shadow-bias="0.2" shadow-distance="20" intensity="1.5"></pc-light>
</pc-entity>
<pc-entity name="ground" scale="30 30 30">
<pc-render type="plane" material="floor"></pc-render>
</pc-entity>
<pc-model name="t-rex" asset="t-rex" scale="1.5 1.5 1.5">
<pc-anim id="anim" clip="walk" transition-time="0.4">
<pc-anim-clip name="walk"></pc-anim-clip>
<pc-anim-clip name="stalk" speed="0.33"></pc-anim-clip>
</pc-anim>
</pc-model>
</pc-scene>
</pc-app>
<div class="controls">
<button id="walk">Walk</button>
<button id="stalk">Stalk</button>
<button id="transport">Pause</button>
</div>
<style>
.controls {
position: absolute;
top: 12px;
left: 12px;
display: flex;
gap: 8px;
}
</style>
<script type="module">
const anim = document.getElementById('anim');
const transport = document.getElementById('transport');

// The clips are what guarantee the layer exists, so wait for them rather than the app
await Promise.all([...anim.querySelectorAll('pc-anim-clip')].map(clip => clip.ready()));

let playing = true;

document.getElementById('walk').onclick = () => anim.setAttribute('clip', 'walk');
document.getElementById('stalk').onclick = () => anim.setAttribute('clip', 'stalk');

transport.onclick = () => {
playing = !playing;
playing ? anim.play() : anim.pause();
transport.textContent = playing ? 'Pause' : 'Play';
};
</script>

机械臂示例还展示六段动作、可拖动播放头和混合开关。

JavaScript 接口​

可以通过 AnimComponentElement API创建和操作元素。

成员说明
play(name?)恢复播放,可先硬切指定片段,忽略 transition-time
pause()暂停并保留播放头
transition(name, time?)淡变到指定片段并确保播放,time 默认 transition-time
clips按分配顺序列出的名称
component底层 AnimComponent

activate、clip、speed、transitionTime 也有对应 property。

只等元素不足以保证片段可播:宿主就绪即创建组件,而各轨道独立加载。需要层中已有轨道时,应等待片段:

import { whenReady } from '@playcanvas/web-components';

const anim = await whenReady('pc-anim');
await Promise.all([...anim.querySelectorAll('pc-anim-clip')].map(clip => clip.ready()));

console.log(anim.clips); // ['walk', 'stalk']

更多功能可通过底层 AnimComponent访问,包括活动时间 baseLayer.activeStateCurrentTime,循环时持续累加、片段时长,以及状态图和混合树。

另请参阅​

示例:GLB 动画、机械臂和第三人称控制器。