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

如何用p5.js实现仅P0运动点留轨迹且可重置轨迹?

解决p5.js中仅指定点保留运动轨迹的问题

嘿,我来帮你搞定这个需求!你想要的是仅让P0留下运动轨迹,其他点只显示当前位置,同时支持按钮控制启停、点击清除旧轨迹重新开始对吧?直接去掉draw()开头的背景确实会让所有点都留痕迹,咱们换个精准控制的思路:

核心思路

  1. 单独保存P0的轨迹:用一个数组记录P0每一帧的位置,这样咱们只对这个数组里的点绘制轨迹
  2. 每次绘制先清画布:在draw()开头正常清除背景,然后先画出P0的历史轨迹,再绘制所有点的当前位置——这样其他点只会显示当前帧的位置,不会留下痕迹
  3. 按钮控制重置逻辑:点击按钮时,清空轨迹数组、重置所有点的位置和运动状态、重启计时器,实现重新开始的效果

完整代码示例

// 定义点的类,包含位置、速度和更新方法
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:42:30