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); }
问题原因
- 重复创建Tween动画:
animate()通过requestAnimationFrame每帧执行一次,每次都会调用animateBox(),而animateBox()每次都会给box.position绑定新的Tween动画。新动画持续干扰旧动画进程,导致首个动画永远无法完成,后续动画自然无法启动。 - 缺少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
相关产品推荐
相关产品推荐

