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

CreateJS链式动画无法抵达目标位置,后续动画无法启动

Three.js + CreateJS 动画序列异常问题:首个动画无法完成,后续动画无法启动

开发基于Three.js和CreateJS的项目时,对同一对象执行多次移动动画出现异常:首个动画永远无法抵达目标位置,导致后续动画完全无法触发。控制台输出显示目标位置从未达成。

问题代码

import * as THREE from './libs/three.module.js'

let box, canvas, renderer, scene, camera;

function init(){
    setUpCamera();
    setUpScene();
    animate();
}
window.addEventListener('load', init);

function setUpCamera() {
    canvas = document.querySelector('.webgl')
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100)
    camera.position.set(0, 10, 15) // 0, 10, 5
    camera.rotation.x = (-40)*  Math.PI / 180

    renderer = new THREE.WebGLRenderer({
        canvas: canvas
    })

}

function setUpScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xbfe3dd);
    scene.add(camera);
    loadBox();
}

function loadBox(){
    let boxGeometry = new THREE.BoxGeometry(5, 5, 5);
    let boxMaterial = new THREE.MeshStandardMaterial( { color: 0x96f2af} );
    box = new THREE.Mesh( boxGeometry, boxMaterial);
    scene.add(box);
}

// 异常的动画函数
function animateBox(){
    console.log("box x position = " + box.position.x);
    createjs.Tween.get(box.position)
        .to({ x: 10 }, 300, createjs.Ease.linear) // 首个动画永远无法结束
        .to({ x: -10 }, 300, createjs.Ease.linear); // 后续动画永远无法启动
}

function animate(){
    animateBox();
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}

问题原因

  1. 重复创建Tween动画:animate()通过requestAnimationFrame每帧执行一次,每次都会调用animateBox(),而animateBox()每次都会给box.position绑定新的Tween动画。新动画持续干扰旧动画进程,导致首个动画永远无法完成,后续动画自然无法启动。
  2. 缺少CreateJS Ticker驱动:CreateJS的Tween依赖自身的tick机制推进,若不在Three.js渲染循环中手动调用createjs.Ticker.update(),动画根本不会正常更新。

解决方案

1. 仅初始化一次动画序列

将animateBox()从渲染循环中移出,仅在场景初始化完成后调用一次:

function init(){
    setUpCamera();
    setUpScene();
    animateBox(); // 仅初始化一次动画
    animate();
}

2. 添加CreateJS Ticker更新

在Three.js渲染循环中加入createjs.Ticker.update(),确保CreateJS动画能正常推进:

function animate(){
    createjs.Ticker.update(); // 驱动CreateJS动画更新
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}

3. 重复触发动画时清除旧Tween

如果需要后续重复触发该动画序列,先清除目标对象上的旧动画,避免冲突:

function animateBox(){
    console.log("box x position = " + box.position.x);
    createjs.Tween.removeTweens(box.position); // 清除旧动画
    createjs.Tween.get(box.position)
        .to({ x: 10 }, 300, createjs.Ease.linear)
        .to({ x: -10 }, 300, createjs.Ease.linear);
}

注意:此时animateBox()仍不能放在animate()循环中,仅在需要触发动画的时机调用即可。

内容的提问来源于stack exchange,提问作者parwal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:18:24