Three.js 中重置物体位置后,如何让动画继续循环移动?
动画循环还在运行。物体停在原地,是因为每一帧都会用持续增长的 time 重新计算位置,随后又被 if 分支重置为 0。可以用相对时间和取模运算,让位置在指定区间内循环,不必反复删除和创建网格。
为什么重置位置后就不动了?
原来的位置计算和重置逻辑如下:
Wall.position.y = -15 + time / 200;
if (Wall.position.y > 5) {
Wall.position.y = 0;
}
setAnimationLoop 回调收到的 time 是以毫秒为单位的时间戳。修改 Wall.position.y 不会重置这个时间戳。
当 time > 4000 时,第一行计算出的 y 坐标会大于 5。之后每一帧都会先算出一个大于 5 的位置,再将其重置为 0,最后才渲染。因此,画面中的网格一直停在 y = 0,但渲染循环并没有停止。
用取模运算实现循环移动
如果希望网格从 y = -15 向上移动,在 y = 5 处循环回到起点,可以将原来的 animate 函数和 setAnimationLoop 调用替换为:
const minY = -15;
const maxY = 5;
const distance = maxY - minY;
const speed = 5; // 每秒移动 5 个场景单位
let startTime;
function animate(time) {
if (startTime === undefined) {
startTime = time;
}
const elapsedSeconds = (time - startTime) / 1000;
const offset = (elapsedSeconds * speed) % distance;
Wall.position.y = minY + offset;
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
代码先记录第一帧的时间,再计算动画运行了多少秒。elapsedSeconds * speed 得到累计移动距离,取模运算将偏移量限制在 [0, 20) 内,因此最终的 y 坐标会在 [-15, 5) 内循环。
speed = 5 对应原代码中 time / 200 的移动速度,循环一次需要 4 秒。即使某一帧越过边界,取模也会保留超出的距离,避免直接重置位置时丢失这部分位移。
是否需要删除并创建新的墙体?
如果墙体的形状和材质没有变化,复用现有对象并更新位置即可。创建新对象也无法解决当前问题:只要继续使用原来的位置公式,新对象仍会遇到相同的重置逻辑。
如果希望画面中始终有多段墙体连续经过,可以预先创建多个对象,按间距排列,再让各自的位置循环。间距和循环范围需要根据墙体尺寸及相机视野确定;单个对象的位置循环本身不能保证画面无缝衔接。
边界和旋转需要注意什么?
maxY = 5 只是代码中的循环边界,并不自动表示墙体已经完全离开相机视野。实际的回收位置需要结合相机参数、墙体尺寸和朝向确定,避免对象仍在画面内时突然跳回起点。
另外,Three.js 的旋转角度使用弧度。原代码中的 Wall.rotation.x = 180 表示 180 弧度。如果想旋转 180°,应写成:
Wall.rotation.x = Math.PI;
GridHelper 默认位于 XZ 平面;如果想将它立起来作为位于 XY 平面的墙体,可以使用:
Wall.rotation.x = Math.PI / 2;
旋转角度会影响网格朝向,但当前位置无法继续变化的直接原因,仍是每一帧重复触发的位置重置。
备注:内容仅供参考。
