在 Three.js 中,动画的播放通常通过 THREE.AnimationMixer 和 THREE.AnimationAction 来管理。如果你想检测动画是否播放结束,可以通过监听 AnimationAction 的事件或检查其状态来实现。
结论
可以通过 AnimationAction 的 stopped 事件或检查 time 属性与 clip.duration 的关系来判断动画是否播放结束。
详细展开
1. 核心概念
AnimationMixer:用于管理动画的播放。AnimationAction:表示一个具体的动画动作,可以通过它控制动画的播放、暂停、停止等操作。AnimationClip:定义了动画的关键帧数据。
2. 检测动画结束的方法
(1) 监听 stopped 事件
AnimationAction 提供了一个 stopped 事件,当动画停止时会触发该事件。你可以通过绑定回调函数来检测动画结束。
// 创建 AnimationMixer
const mixer = new THREE.AnimationMixer(model);
// 加载动画剪辑并创建 AnimationAction
const clip = model.animations[0]; // 假设模型中有一个动画剪辑
const action = mixer.clipAction(clip);
// 监听 stopped 事件
action.addEventListener('stopped', () => {
console.log('动画播放结束了');
});
// 播放动画
action.play();
(2) 检查时间与持续时间的关系
你可以通过比较动画当前时间 (action.time) 和动画总时长 (clip.duration) 来判断动画是否结束。
function checkAnimationEnd() {
if (action.time >= clip.duration) {
console.log('动画播放结束了');
return true;
}
return false;
}
// 在渲染循环中调用
function animate() {
requestAnimationFrame(animate);
// 更新动画混合器
mixer.update(clock.getDelta());
// 检查动画是否结束
if (checkAnimationEnd()) {
// 动画结束后的逻辑
}
renderer.render(scene, camera);
}
animate();
(3) 设置重复次数
如果动画只播放一次(默认行为),你也可以通过设置 loop 属性为 THREE.LoopOnce 并结合上述方法来检测动画结束。
action.setLoop(THREE.LoopOnce); // 设置动画只播放一次
action.play();
// 结合 stopped 事件或时间检查
3. 完整示例代码
以下是一个完整的示例,展示如何检测动画播放结束:
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer);
// 添加时钟
const clock = new THREE.Clock();
// 加载模型
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
const model = gltf.scene;
scene.add(model);
// 创建 AnimationMixer
const mixer = new THREE.AnimationMixer(model);
// 获取动画剪辑并创建 AnimationAction
const clip = gltf.animations[0]; // 假设模型中有一个动画剪辑
const action = mixer.clipAction(clip);
// 监听 stopped 事件
action.addEventListener('stopped', () => {
console.log('动画播放结束了');
});
// 播放动画
action.play();
// 渲染循环
function animate() {
requestAnimationFrame(animate);
// 更新动画混合器
const deltaTime = clock.getDelta();
mixer.update(deltaTime);
// 检查动画是否结束
if (action.time >= clip.duration) {
console.log('动画播放结束了');
}
renderer.render(scene, camera);
}
animate();
});
4. 关键点解析
(1) stopped 事件
stopped 事件会在动画完全停止时触发,适合用于简单的结束检测。
(2) 时间检查
通过比较 action.time 和 clip.duration,可以更精确地控制动画结束的逻辑。
(3) 循环模式
AnimationAction 的 loop 属性决定了动画的播放模式:
THREE.LoopOnce:只播放一次。THREE.LoopRepeat:无限循环播放。THREE.LoopPingPong:来回播放。
如果你希望动画只播放一次,建议设置 action.setLoop(THREE.LoopOnce)。
5. 注意事项
(1) 性能优化
在复杂场景中,频繁检查动画状态可能会增加计算开销。建议结合 stopped 事件和时间检查,选择最适合的方式。
(2) 动画嵌套
如果模型中有多个动画剪辑同时播放,需要分别监听每个 AnimationAction 的结束事件。
(3) 跨帧问题
由于动画更新是基于帧的,可能存在微小的时间偏差。因此,在检测动画结束时,可以稍微放宽条件(如 action.time >= clip.duration - 0.01)。
总结
在 Three.js 中,可以通过监听 AnimationAction 的 stopped 事件或检查 action.time 和 clip.duration 的关系来判断动画是否播放结束。结合这两种方法,可以灵活地实现动画结束检测,并执行相应的逻辑。

浙公网安备 33010602011771号