<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.js"></script>
<!--     <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/addons/p5.sound.min.js"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/p5.capture@1.1.0/dist/p5.capture.umd.min.js"></script> -->
class Mass {
  constructor(opts) {
    Object.assign(this, opts);
  }

  update() {
    // this.acc.add(this.gravity);
    this.acc.add(this.acc);
    const accel = p5.Vector.add(this.acc, this.gravity);

    this.vel.add(accel);
    // this.vel.limit(this.topspeed);
    this.loc.add(this.vel);

    if (this.isReachEdgeW()) {
      this.acc.mult(this.e);
      this.vel.mult(this.e, 1);
      this.loc.x = this.loc.x < this.edgeW[0] ? this.edgeW[0] : this.edgeW[1];
    }
    if (this.isReachEdgeH()) {
      this.acc.mult(this.e);
      this.vel.mult(1, this.e);
      this.loc.y = this.loc.y < this.edgeH[0] ? this.edgeH[0] : this.edgeH[1];
    }
  }

  isReachEdgeW() {
    return this.loc.x <= this.edgeW[0] || this.loc.x >= this.edgeW[1];
  }

  isReachEdgeH() {
    return this.loc.y <= this.edgeH[0] || this.loc.y >= this.edgeH[1];
  }

  display() {
    push();
    strokeWeight(1);
    // text(
    //   `(${this.loc.x.toFixed(1)}, ${this.loc.y.toFixed(1)})`,
    //   this.loc.x + 5,
    //   this.loc.y + 5
    // );
    const relVel = p5.Vector.add(this.loc, p5.Vector.mult(this.vel, -4));
    stroke(this.massColor);
    line(this.loc.x, this.loc.y, relVel.x, relVel.y);
    pop();

    push();
    fill(this.massColor);
    ellipse(this.loc.x, this.loc.y, 10, 10);
    pop();

    push();
    const relA = p5.Vector.add(this.loc, this.acc);
    const relV = p5.Vector.add(this.loc, this.vel);

    strokeWeight(1);
    line(this.loc.x, this.loc.y, relA.x, relA.y);
    pop();
  }
}

let W, H;

let masses = [];
let MASS_N = 100;

function generateRandomMass() {
  const edgeW = [0 + 30, width - 30];
  const edgeH = [0 + 30, height - 30];
  const massColor = color(random(255));
  const vel = createVector(
    random(-0.01,0.01)*width,
    random(-0.01,0.01)*height
  )
  return new Mass({
    massColor: massColor,
    edgeW: edgeW,
    edgeH: edgeH,
    acc: createVector(0, 0),
    vel: vel,
    loc: createVector(random(edgeW[1]), random(edgeH[1])),
    gravity: createVector(0, 0.6),
    e: -random(0.8),
  });
}
function setup() {
  createCanvas((W = windowWidth), (H = windowHeight));

  // for (let i = 0; i < MASS_N; i++) {
  //   let m = generateRandomMass();
  //   masses.push(m);
  // }
}

// P5Capture.setDefaultOptions({
//   format: "gif",
//   framerate: 60,
//   quality: 0.5,
//   width: 320,
// });

function draw() {
  // if (frameCount === 1) {
  //   const capture = P5Capture.getInstance();
  //   capture.start({
  //     duration: 150,
  //   });
  // }
  background(220);
  // translate(width / 2, height / 2);

  text(
    [`frameCount = ${frameCount}`,
     `n = ${masses.length}`
    ].join("\n"),
    20,
    20
  );

  push();
  for (let i = 0; i < masses.length; i++) {
    masses[i].update();
    masses[i].display();
  }
  
  frameCount % 1 || masses.push(generateRandomMass())
  masses.length > MASS_N && masses.shift();
  pop();
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.