joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

在 Three.js 中,动画的播放通常通过 THREE.AnimationMixerTHREE.AnimationAction 来管理。如果你想检测动画是否播放结束,可以通过监听 AnimationAction 的事件或检查其状态来实现。


结论

可以通过 AnimationActionstopped 事件或检查 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.timeclip.duration,可以更精确地控制动画结束的逻辑。

(3) 循环模式

AnimationActionloop 属性决定了动画的播放模式:

  • THREE.LoopOnce:只播放一次。
  • THREE.LoopRepeat:无限循环播放。
  • THREE.LoopPingPong:来回播放。

如果你希望动画只播放一次,建议设置 action.setLoop(THREE.LoopOnce)


5. 注意事项

(1) 性能优化

在复杂场景中,频繁检查动画状态可能会增加计算开销。建议结合 stopped 事件和时间检查,选择最适合的方式。

(2) 动画嵌套

如果模型中有多个动画剪辑同时播放,需要分别监听每个 AnimationAction 的结束事件。

(3) 跨帧问题

由于动画更新是基于帧的,可能存在微小的时间偏差。因此,在检测动画结束时,可以稍微放宽条件(如 action.time >= clip.duration - 0.01)。


总结

在 Three.js 中,可以通过监听 AnimationActionstopped 事件或检查 action.timeclip.duration 的关系来判断动画是否播放结束。结合这两种方法,可以灵活地实现动画结束检测,并执行相应的逻辑。

posted on   joken1310  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2018-03-04 vi 使用小结
点击右上角即可分享
微信分享提示