Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

458
Views
p5.js particles behavior under the influence of a 2D vector field showing poor response

I got half-way through what I wanted in the representation of physics vector fields in 2D with p5js here. The other half is to get random particles to dynamically follow the forces of the vector field, and I am having a lot of problems with it. I have tried multiple things to take into account the wrap-around of the particles, as well as the fact that I am translating the origin of the plot to the center of the canvas. However, the particles seem minimally affected by the individual vectors in the field, and ultimately march along the x axis with slight bumpiness.

enter image description here

The fact that I am completely new at JS doesn't help splice all these elements from several presentations available online, and I would appreciate any advise as to what may be going wrong, and where I should focus on.

Here is what I have so far: a file sketch.js corresponding to my own answer quoted above:

scl = 35;
var cols,rows;
var fr;
var particles = [];
var flowfield;

function setup() {
  createCanvas(windowWidth, windowHeight);
  cols = floor(width/scl);
  rows = floor(height/scl);
  fr = createP("");
   
  flowfield = new Array(cols * rows);

  for (var i = 0; i < 1000; i++) {
    particles[i] = new Particle();
  }
  background(51);
}



function draw() {
  translate(height/2, height/2);  //moves the origin to bottom left
  scale(1, -1);  //flips the y values so y increases "up"
  background(255);
  loadPixels();
  for (var y = -rows; y < rows; y++) {
    for (var x = - cols; x < cols; x++) {
      var index = x + y * cols;
      //var v = createVector(sin(x)+cos(y),sin(x)*cos(y));
      var v = createVector(y,-x);
      flowfield[index] = v;
      fill('blue');
      stroke('blue');
      push();
      translate(x*scl,y*scl);
      rotate(v.heading());
      line(0,0,0.5*scl,0);
      let arrowSize = 7;
      translate(0.5*scl - arrowSize, 0);
      triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
      pop();
    }
  }
    for (var i = 0; i < particles.length; i++) {
    particles[i].follow(flowfield);
    particles[i].update();
    particles[i].edges();
    particles[i].show();
  }
}

and a second file called particle.js:

class Particle {
  constructor() {
    this.pos = createVector(random(-width,width), 
                            random(-height,height));
    this.vel = createVector(0, 0);
    this.acc = createVector(0, 0);
    this.maxspeed = 4;
    this.prevPos = this.pos.copy();
    this.size = 8;
  }

  update() {
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }

  follow(vectors) {
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y * cols;
    var force = vectors[index];
    this.applyForce(force);
  }

  applyForce(force) {
    this.acc.add(force);
  }

  show() {
    noStroke();
    fill('rgba(100,0,255,.5)');
    circle(-(this.pos.x+width/2), -(this.pos.y-height/2), this.size);
    this.updatePrev();
  }

  updatePrev() {
    this.prevPos.x = this.pos.x;
    this.prevPos.y = this.pos.y;
  }

  edges() {
    if (this.pos.x > width) {
      this.pos.x = -width;
      this.updatePrev();
    }
    if (this.pos.x < -width) {
      this.pos.x = width;
      this.updatePrev();
    }
    if (this.pos.y > height) {
      this.pos.y = -height;
      this.updatePrev();
    }
    if (this.pos.y == -height) {
      this.pos.y = height;
      this.updatePrev();
    }

  }

}

The beginning of the simulation with the updated code on this edit is not bad:

enter image description here

but soon enough all particles align with the last row along the x axis. So I guess I need some help understanding flow fields or scaling down the effect of the vectors at the bottom.


Ethan Hermsey did solve this plotting problem for me perfectly. At this point, and undoubtfully due to either some glitch in the code, or some miscommunication, the code in the accepted answer happens to actually result in a different output to that desired in asking the question, and the code that Ethan himself solved for me. So just for reference, this is the effect intended:

enter image description here

Generated as follows:

const scl = 35;
var cols, rows;
var particles = [];
var flowfield;

function setup() {

    createCanvas(750, 750);
    cols = ceil( width / scl );
    rows = ceil( height / scl );


    flowfield = new Array( cols * rows );

    for (var i = 0; i < 1000; i ++ ) {
        particles[i] = new Particle();
    }
}

function draw() {

    translate(height / 2, height / 2); //moves the origin to center
    scale( 1, - 1 ); //flips the y values so y increases "up"
    background( 255 );

    for ( var y = 0; y < rows; y ++ ) { 
        for ( var x = 0; x < cols; x ++ ) { 
      
      var index = x + y * cols;

      let vX = x * 2 - cols;
      let vY = y * 2 - rows;
                
     
      var v = createVector( vY, -vX );
      v.normalize();
          
      flowfield[index] = v;
      
      // The following push() / pull() affects only the arrows     
      push();
      fill( 'red' );
      stroke( 'red' );
      translate(x*scl-width/2,y*scl-height/2);
      rotate(v.heading());
      line(0,0,0.5*scl,0);
      let arrowSize = 7;
      translate(0.5*scl - arrowSize, 0);
      triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
      pop();
// The preceding push() / pull() affects only the arrows     
    }// Closes inner loop
  }// Closes outer loop to create vectors and index.
  
//This next loop actually creates the desired particles:
    for (var i = 0; i < particles.length; i++) {
    particles[i].follow(flowfield);
    particles[i].update();
    particles[i].edges();
    particles[i].show();
  }
} // End of the function draw

class Particle {

    constructor() {

        // changed startpostion. Since the origin is in the center of the canvas,
        // the x goes from -width/2 to width/2
        // the y goes from -height/2 to height/2
        // i also changed this in this.edges().

        this.pos = createVector( random( - width / 2, width / 2 ),
            random( - height / 2, height / 2 ) );
        this.vel = createVector( 0, 0 );
        this.acc = createVector( 0, 0 );
        this.maxspeed = 4;
        this.steerStrength = 15;
        this.prevPos = this.pos.copy();
        this.size = 8;

    }

    update() {

        this.vel.add( this.acc );
        this.vel.limit( this.maxspeed );
        this.pos.add( this.vel );
        this.acc.mult( 0 );

    }

    follow( vectors ) {

        var x = floor( map( this.pos.x, - width / 2, width / 2, 0, cols - 1, true ) );
        var y = floor( map( this.pos.y, - height / 2, height / 2, 0, rows - 1, true ) );
        var index = ( y * cols ) + x;

        var force = vectors[ index ].copy();
        force.mult( this.steerStrength );
        this.applyForce( force );

    }

    applyForce( force ) {

        this.acc.add( force );

    }

    show() {

        noStroke();
        fill( 'rgba(100,0,255,.5)' );

        // you can just draw on the position.
        circle( this.pos.x, this.pos.y, this.size );

        this.updatePrev();

    }

    updatePrev() {

        this.prevPos.x = this.pos.x;
        this.prevPos.y = this.pos.y;

    }

    edges() {

        //clamp between -width/2 and width/2. -height/2 and height/2
        if ( this.pos.x > width / 2 ) {

            this.pos.x = - width / 2;
            this.updatePrev();

        }
        if ( this.pos.x < - width / 2 ) {

            this.pos.x = width / 2;
            this.updatePrev();

        }
        if ( this.pos.y > height / 2 ) {

            this.pos.y = - height / 2;
            this.updatePrev();

        }
        if ( this.pos.y < - height / 2 ) {

            this.pos.y = height / 2;
            this.updatePrev();

        }

    }

}
over 4 years ago · Santiago Trujillo
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!