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

Three.js中满足条件语句后如何继续动画并实现墙体无限上移循环

嘿,我帮你拆解下问题的根源,再给你两个能完美实现无限循环滚动的方案~

为什么你的动画会“停止”?

你代码里的位置更新逻辑是硬伤:你每次都用全局递增的time变量直接计算网格的y位置,而不是在上一帧的位置基础上逐步累加偏移量。

看这段关键代码:

Wall.position.y = -15 + time / 200;

time是从页面加载开始就一直涨的毫秒数,当你触发if条件把Wall.position.y设为0后,下一帧的time已经比之前大了几十毫秒,算出来的-15 + time/200会直接跳到一个远大于5的数值,瞬间又触发重置逻辑。这个过程快到肉眼根本看不到循环,看起来就像动画卡在高处不动了。

另外还有个小细节:Three.js里旋转用的是弧度不是角度,你写的Wall.rotation.x = 180其实是180弧度,相当于让网格转了28圈多,这也会导致初始位置不符合你的预期,应该用Math.PI(等于180度)。

正确的实现方式

下面给你两种实用的方案,按需选择:

方案1:复用单个网格,平滑循环

这种方式最简单,只要把位置更新改成基于当前位置的增量累加,移出视野后重置到初始位置即可:

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);

// 创建网格,用Math.PI代替180(弧度转角度)
const Wall = new THREE.GridHelper(10, 5);
Wall.rotation.x = Math.PI;
scene.add(Wall);

// 配置参数,方便调整
const moveSpeed = 0.1; // 每帧移动的距离
const startY = -10;    // 初始位置(视野下方)
const resetY = 10;     // 移出视野的阈值

// 初始化位置
Wall.position.y = startY;

function animate() {
    // 核心:在上一帧位置基础上累加速度,实现连续移动
    Wall.position.y += moveSpeed;

    // 完全移出视野后,重置到初始位置
    if (Wall.position.y > resetY) {
        Wall.position.y = startY;
    }

    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 gridSize = 10;
const moveSpeed = 0.1;
const gridCount = 3; // 3个网格足够覆盖视野,避免空白
const grids = [];

// 初始化多个网格,垂直排列
for (let i = 0; i < gridCount; i++) {
    const grid = new THREE.GridHelper(gridSize, 5);
    grid.rotation.x = Math.PI;
    // 每个网格间隔gridSize,从视野下方开始排列
    grid.position.y = -gridSize * 1.5 + i * gridSize;
    scene.add(grid);
    grids.push(grid);
}

function animate() {
    grids.forEach(grid => {
        grid.position.y += moveSpeed;

        // 当网格完全移出顶部视野,移到最底部
        if (grid.position.y > gridSize * 1.5) {
            // 找到当前最靠下的网格
            const lowestGrid = grids.reduce((prev, curr) => prev.position.y < curr.position.y ? prev : curr);
            // 把当前网格移到它下方一个网格的距离
            grid.position.y = lowestGrid.position.y - gridSize;
        }
    });

    renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);

关于你尝试过的“创建新网格”方案

如果之前用创建新网格、删除旧网格的方式失败,大概率是没正确清理资源:删除旧网格时,除了调用scene.remove(oldGrid),还要释放它的几何体和材质内存(oldGrid.geometry.dispose()、oldGrid.material.dispose()),不然会导致内存泄漏。不过复用现有网格的方式性能更好,优先推荐上面的两种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 06:39:02