You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Three.js中requestAnimationFrame驱动的动画随消息发送次数增多而加速?

如何避免Three.js中requestAnimationFrame驱动的动画随消息发送次数增多而加速?

嘿,我看了你的代码,问题其实挺典型的——动画加速的根源是每次发消息调用animateProcessingEffect时,你以为取消了之前的动画循环,但实际上根本没取消掉,导致多个动画帧请求同时在跑,叠加起来自然越来越快。

咱们一步步来解决:

问题核心:动画帧ID的作用域问题

你代码里的animationFrameId看起来没有在全局作用域声明,如果它是animateProcessingEffect内部的局部变量,那每次调用这个函数时,你用cancelAnimationFrame(animationFrameId)取消的都是当前函数里的新变量(初始值是undefined),上一次启动的动画循环完全没被终止,还在后台跑着。新的动画又启动,多个循环同时修改currentProcessing并调用update,速度自然就翻倍、翻几倍了。

修复方案

1. 全局声明动画帧ID

在你的全局变量区域(比如和boostedSpeed、currentProcessing一起)加上:

let animationFrameId = null; // 全局存储动画帧ID,确保每次都能拿到上一次的请求ID

2. 完善动画取消与重置逻辑

修改animateProcessingEffect函数,确保启动新动画前彻底终止旧动画,并且在动画结束后重置ID,避免后续误判:

function animateProcessingEffect(targetProcessing = 1.8) {
    // 先终止之前的动画,不管有没有在运行
    if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null; // 重置ID,防止后续误操作
    }

    const steps = 0.005;
    const revertSteps = 0.001;
    const revertDelay = 100;
    let isReverting = false;

    function animateStep() {
        if (!isReverting) {
            if (currentProcessing < targetProcessing) {
                currentProcessing = Math.min(currentProcessing + steps, targetProcessing);
            } else {
                isReverting = true;
                setTimeout(() => {
                    animationFrameId = requestAnimationFrame(animateStep);
                }, revertDelay);
                return;
            }
        } else {
            if (currentProcessing > 1) {
                currentProcessing = Math.max(currentProcessing - revertSteps, 1);
            } else {
                animationFrameId = null; // 动画完全结束后,重置ID
                return;
            }
        }
        update();
        animationFrameId = requestAnimationFrame(animateStep);
    }

    animationFrameId = requestAnimationFrame(animateStep);
}

3. 额外优化:避免重复触发(可选)

如果担心用户快速发送消息导致频繁启停动画,还可以加一个“动画锁”,比如全局声明isAnimating,在animateProcessingEffect开头判断:

let isAnimating = false;

function animateProcessingEffect(targetProcessing = 1.8) {
    if (isAnimating) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
    }
    isAnimating = true;

    // ... 原有逻辑 ...

    // 在动画结束的else分支里加上:
    isAnimating = false;
}

这样就能确保同一时间只有一个动画循环在运行,彻底解决叠加加速的问题。

验证一下

修改后,你再发送消息试试——每次启动新的动画效果前,旧的循环都会被终止,只有当前这一个动画在跑,currentProcessing的修改和update的调用都会保持在正常频率,动画速度自然就稳定了。

备注:内容来源于stack exchange,提问作者EbDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 13:54:28