如何用p5.js实现仅P0运动点留轨迹且可重置轨迹?
解决p5.js中仅指定点保留运动轨迹的问题
嘿,我来帮你搞定这个需求!你想要的是仅让P0留下运动轨迹,其他点只显示当前位置,同时支持按钮控制启停、点击清除旧轨迹重新开始对吧?直接去掉draw()开头的背景确实会让所有点都留痕迹,咱们换个精准控制的思路:
核心思路
- 单独保存P0的轨迹:用一个数组记录P0每一帧的位置,这样咱们只对这个数组里的点绘制轨迹
- 每次绘制先清画布:在
draw()开头正常清除背景,然后先画出P0的历史轨迹,再绘制所有点的当前位置——这样其他点只会显示当前帧的位置,不会留下痕迹 - 按钮控制重置逻辑:点击按钮时,清空轨迹数组、重置所有点的位置和运动状态、重启计时器,实现重新开始的效果
完整代码示例
// 定义点的类,包含位置、速度和更新方法 class Point { constructor(x, y) { this.pos = createVector(x, y); // 随机初始速度 this.vel = p5.Vector.random2D().mult(random(2, 5)); } update() { this.pos.add(this.vel); // 碰到画布边缘反弹 if (this.pos.x < 0 || this.pos.x > width) this.vel.x *= -1; if (this.pos.y < 0 || this.pos.y > height) this.vel.y *= -1; } draw() { fill(255); stroke(0); strokeWeight(2); ellipse(this.pos.x, this.pos.y, 10, 10); } } let points = []; let p0Trajectory = []; // 专门保存P0的轨迹 let isRunning = false; let timer = 0; let controlBtn; function setup() { createCanvas(600, 400); // 创建5个初始点 for (let i = 0; i < 5; i++) { points.push(new Point(random(width), random(height))); } // 创建控制按钮 controlBtn = createButton('启动/重置运动'); controlBtn.position(10, height + 10); controlBtn.mousePressed(resetAndStart); } function draw() { background(200); // 每次绘制都清背景,避免所有点留痕迹 if (isRunning) { timer += deltaTime / 1000; // 转换为秒 // 运动未结束时,更新所有点并记录P0的轨迹 if (timer < 5) { points.forEach(point => point.update()); // 把P0的当前位置添加到轨迹数组(用copy避免后续更新影响历史值) p0Trajectory.push(points[0].pos.copy()); } else { isRunning = false; // 5秒后停止运动 } } // 绘制P0的轨迹 if (p0Trajectory.length > 1) { noFill(); stroke(255, 0, 0); // 用红色区分P0的轨迹 strokeWeight(2); beginShape(); p0Trajectory.forEach(pos => vertex(pos.x, pos.y)); endShape(); } // 绘制所有点的当前位置 points.forEach(point => point.draw()); // 显示剩余时间 fill(0); noStroke(); textSize(16); text(`剩余时间: ${max(0, 5 - floor(timer))}秒`, width - 150, height - 10); } // 按钮点击事件:重置所有状态并启动运动 function resetAndStart() { timer = 0; isRunning = true; p0Trajectory = []; // 清空旧轨迹 // 重置每个点的位置和速度 points.forEach(point => { point.pos = createVector(random(width), random(height)); point.vel = p5.Vector.random2D().mult(random(2, 5)); }); }
关键细节解释
- 轨迹数组
p0Trajectory:每次更新P0位置时,用copy()复制位置向量,避免后续位置更新影响数组里的历史值 - 绘制顺序:先画轨迹,再画当前点——这样P0的当前位置会覆盖轨迹的最后一个点,视觉上更自然
- 反弹逻辑:给点加了边缘反弹,避免点跑出画布,你可以根据需求去掉
- 计时器用
deltaTime:比frameCount更精准,因为deltaTime是两帧之间的实际时间间隔,不会受帧率波动影响
这样操作下来,你点击按钮后,只有P0会留下红色的运动轨迹,其他点只会显示当前位置;再次点击按钮时,旧轨迹会被清空,所有点重新开始运动~
内容的提问来源于stack exchange,提问作者Erik Norberg
相关产品推荐
相关产品推荐

