Three.js中满足条件语句后如何继续动画——实现网格墙体无限垂直上移动画
如何实现Three.js中墙体/网格的垂直无限循环移动效果?
Hey there! Let's break down why your current code isn't working and walk through the right ways to get that infinite vertical loop going.
问题出在哪?
你的动画逻辑有个关键漏洞:你用time(一个持续递增的全局时间值)直接计算墙体的绝对位置Wall.position.y = -15 + time / 200;。当墙体的y值超过5时,你把它设为0,但下一次执行animate时,time已经变得更大了,计算出来的-15 + time/200肯定还是远大于5,于是立刻又被重置为0——这就导致墙体卡在y=0的位置,看起来完全不动了。
另外还有个小细节:Three.js的旋转用弧度而非角度,你写的Wall.rotation.x = 180;会让网格旋转180弧度(相当于转了近29圈),这可能也不是你想要的效果,正确的180度旋转应该用Math.PI。
正确实现方式(两种方案)
方案1:复用现有网格(性能更优)
不需要删除重建,只需要在网格移出视野时,把它重置到视野下方的起始位置,让它继续向上移动。核心是用相对位移更新位置,而不是依赖全局time的绝对计算。
修改后的代码:
import * as THREE from 'three'; const renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set(0, 0, 10); // 创建墙体(这里用GridHelper,你也可以换成Mesh) const wall = new THREE.GridHelper( 10, 5 ); wall.rotation.x = Math.PI; // 180度对应的弧度值 scene.add( wall ); // 移动速度(可根据需求调整) const moveSpeed = 0.1; // 墙体移出视野后的重置位置(设为视野下方足够远的地方) const resetYPosition = -15; // 墙体需要重置的阈值(比如摄像机视野上方5个单位) const resetThreshold = 5; function animate() { // 每次动画帧让墙体向上移动固定步长 wall.position.y += moveSpeed; // 当墙体超出视野上方时,重置到下方起始位置 if (wall.position.y > resetThreshold) { wall.position.y = resetYPosition; } renderer.render( scene, camera ); } renderer.setAnimationLoop( animate );
方案2:动态创建/删除网格(适合多墙体流场景)
如果需要多个墙体连续循环出现,你可以维护一个墙体数组,在动画中检查每个墙体的位置,移出视野的就销毁,同时创建新的墙体补充到下方。
示例代码:
import * as THREE from 'three'; const renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set(0, 0, 10); // 墙体数组,用于跟踪所有活跃的墙体 const walls = []; const moveSpeed = 0.1; const resetThreshold = 5; const spawnYPosition = -15; const wallCount = 2; // 同时存在的墙体数量 // 创建单个墙体的函数 function spawnWall() { const wall = new THREE.GridHelper( 10, 5 ); wall.rotation.x = Math.PI; wall.position.y = spawnYPosition; scene.add( wall ); walls.push( wall ); } // 初始化创建指定数量的墙体,错开位置避免重叠 for (let i = 0; i < wallCount; i++) { spawnWall(); walls[i].position.y = spawnYPosition + (i * 10); } function animate() { // 倒序遍历数组,避免删除元素时索引混乱 for (let i = walls.length - 1; i >= 0; i--) { const wall = walls[i]; wall.position.y += moveSpeed; // 如果墙体超出视野上方,移除并销毁,同时补充新墙体 if (wall.position.y > resetThreshold) { scene.remove( wall ); walls.splice( i, 1 ); spawnWall(); } } renderer.render( scene, camera ); } renderer.setAnimationLoop( animate );
内容的提问来源于stack exchange,提问作者Seelum
相关产品推荐
相关产品推荐

