在 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
的关系来判断动画是否播放结束。结合这两种方法,可以灵活地实现动画结束检测,并执行相应的逻辑。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2018-03-04 vi 使用小结