JS基于lerp的随机游走异常:点持续向左上角偏移求解
问题根源分析与修复
核心问题:变量操作逻辑混乱 + 未使用Lerp函数
你代码里的两个致命问题导致了点持续向左上角偏移:
- 绘制目标与修改目标不匹配:实际绘制的是
pointEnd数组里的坐标,但只有向左(n=3)、向上(n=0)的操作是修改pointEnd,而向右(n=2)、向下(n=1)的操作修改的是point数组——但point从未被用来更新pointEnd,等于这两个方向的偏移完全没生效。 - Lerp函数未被调用:你定义了
lerp函数,但整个代码里没有任何地方使用它来让pointEnd向point插值移动,等于point的修改完全是无效操作。
另外还有两个次要问题:
- 计数数组初始化错误:
count = Array.from(new Array(4).keys())生成的是[0,1,2,3],不是初始为0的计数数组,会导致分布统计从一开始就不准,应该用new Array(4).fill(0)。 - 错误的动画循环:
setInterval嵌套requestAnimationFrame会导致重复触发渲染,requestAnimationFrame本身会按浏览器帧率自动执行,不需要额外包裹定时器。
修复后的代码
JavaScript部分
const canvas = document.querySelector('#myCanvas'); const ctx = canvas.getContext('2d'); const width = canvas.clientWidth; const height = canvas.clientHeight; canvas.width = width; canvas.height = height; // 点的数量 const AMOUNT = 15; // 屏幕中心坐标 const centerX = width / 2; const centerY = height / 2; // 点的大小 const SIZE = 8; // Lerp插值速度 const LERP_SPEED = 0.05; // 所有点的目标位置(随机游走的目标点) let pointsTarget = Array.from({ length: AMOUNT }, () => [centerX, centerY]); // 所有点的当前绘制位置(通过Lerp向目标点移动) let pointsCurrent = Array.from({ length: AMOUNT }, () => [centerX, centerY]); // 随机方向计数(初始化为0) let count = new Array(4).fill(0); function lerp(start, end, speed) { return start + (end - start) * speed; } function render() { // 清空画布 ctx.fillStyle = 'rgba(255, 255, 255, 1)'; ctx.fillRect(0, 0, width, height); // 遍历所有点 for (let i = 0; i < AMOUNT; i++) { const target = pointsTarget[i]; const current = pointsCurrent[i]; // 更新当前位置:通过Lerp向目标点移动 current[0] = lerp(current[0], target[0], LERP_SPEED); current[1] = lerp(current[1], target[1], LERP_SPEED); // 绘制当前点 ctx.fillStyle = 'black'; ctx.fillRect(current[0] - SIZE / 2, current[1] - SIZE / 2, SIZE, SIZE); // 生成随机方向(0:上, 1:下, 2:右, 3:左) const n = Math.floor(Math.random() * 4); count[n]++; // 更新目标点的位置 switch(n) { case 0: target[1] -= 1; break; // 上 case 1: target[1] += 1; break; // 下 case 2: target[0] += 1; break; // 右 case 3: target[0] -= 1; break; // 左 } } // 统计并打印分布(放在循环外,避免每秒打印上千次) const sum = count.reduce((a, b) => a + b); console.log(count.map((val, i) => `${i}:${Math.round((val / sum) * 100)}%`).join(' | ')); // 继续下一帧渲染 requestAnimationFrame(render); } // 启动动画 requestAnimationFrame(render);
HTML部分
<canvas id="myCanvas" style="width: 800px; height: 600px; border: 1px solid #ccc;"></canvas>
修复说明
- 统一变量职责:将原有的
points和pointsEnd改为pointsTarget(随机游走的目标点)和pointsCurrent(当前绘制的插值点),逻辑更清晰。 - 调用Lerp函数:每次渲染时用
lerp更新当前点向目标点移动,实现平滑的游走效果。 - 修正方向操作:所有随机方向的修改都作用于
pointsTarget,确保四个方向的偏移都能传递到最终绘制的点上。 - 修正计数初始化:用
fill(0)初始化计数数组,保证分布统计准确。 - 优化动画循环:直接用
requestAnimationFrame递归调用,避免冗余的定时器嵌套。
内容的提问来源于stack exchange,提问作者Lukas Laudrain
相关产品推荐
相关产品推荐

