Can somebody help me understand this awesome code?

I came across a really cool sketch in Open Processing. But it’s uncommented, and I’d like to better understand what’s going on. (I am really new to p5.js, but have been using Processing for a few months).

Anyway, I was wondering if anyone would be willing to help me understand how he is creating this effect – either by explaining at a high level, or adding some more comments to the code.

Link: https://www.openprocessing.org/sketch/654366

var inc = 0.1;
var scl = 10;
var cols;
var rows;

var zoff = 0;
var fr;
var particles = [];

var flowfeild;

var img;

function preload(){
	img = loadImage("starry.jpg");
}

function setup() {
createCanvas(img.width, img.height);


	//colorMode(HSB, 255);
	cols = floor(width / scl);
	rows = floor(height / scl);

	flowfield = new Array(cols * rows);

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

function draw(){
	//background(240);

	var yoff = 0;

	for (var y = 0; y < rows; y++) {
		var xoff = 0;
		for (var x = 0; x < cols; x++) {
			var index = x + y * cols;
			var angle = noise(xoff, yoff, zoff) * TWO_PI * 4;
			var v = p5.Vector.fromAngle(angle);
			v.setMag(1);
			flowfield[index] = v;
			xoff += inc;
			stroke(0, 50);
		}
		yoff += inc;

		zoff += random(0.0001, 0.001);
	}

	for (var i = 0; i < particles.length; i++) {
		particles[i].follow(flowfield);
		particles[i].update();
		particles[i].edges();
		particles[i].draw();
	}


}

class Particle{
	constructor(){

		this.pos = createVector(random(width), random(height));
		this.vel = createVector(0, 0);
		this.acc = createVector(0, 0);

		this.maxSpeed = 2;
		this.h = 0;
		this.cc = color(200, 0, 0);

		this.prevPos = this.pos.copy();

	}

	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);
		}

		draw(){

			var newColour = color(img.get(this.pos.x, this.pos.y));
			stroke(red(newColour), green(newColour), blue(newColour), 30);
			this.h = this.h + 1;
			if (this.h > 100){
				this.h = 0;
			}

			//strokeWeight(1);
			line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos
				.y);
			this.updatePrev();
		}

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

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


}
1 Like

tried something new, hopefully the image is readable & not too small!

(you might have to right click the image and select ‘view image’, to see it in full!)


some other takeaways for exploring codebases:

1. open the codebase in a more ‘interactive’ IDE

The very first thing I did to explore this code was to copy paste the code into a modern IDE (there are many alternatives here, and I recommend vscode if you haven’t given it a try already!). IDE’s will let you click on things (variables), and see where they are used simply by scrolling a bit down & looking at where they are highlighted! They can also automatically format your document so indentations line up properly (which makes code harder to read), and even highlight the scopes you’re interested in! (so you don’t accidentally assume code is located where it isn’t)… + many more!. The web IDE’s like the one on https://editor.p5js.org/ are getting better every day, but there are still a few features that we currently miss out on, and would be foolish not to take advantage of :smiley: !

2. if you see a bunch of stuff happening at once, try to reduce the problem to just one or two things!

in this case, we have a Class definition, and many instances of the same class being created

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

here you can reduce the instance count from 800 to 1, and observe what happens with just 1 particle.

3. if something is confusing, just comment it out!

simple tip, but one of the greatest things about code is how interactive it is! (at least nowadays, you can make changes instantly, and see the results just as instantly, right in your browser). Things are often much easier to grasp when you see the ‘before and after’ of it.

4. some codebases are inherently harder to grasp than others

Don’t worry if something seems to not make sense at first, or if it takes a lot of time to parse etc… this happens all the time, and some codebases assume the reader is familiar with other pieces of code, like libraries and frameworks. In this case, p5js, and it has a pretty good & extensive documentation! Eg. I had to look up ‘preload()’ in this case, since (even though I had my suspicions) I wasn’t completely sure. It also kinda helped that the author nicely defined the ‘preload()’ function before the ‘setup()’ funcion, and I’m sure that was no accident. This is also a contributor to ‘some codebases being harder to read than others’, the author has almost limitless potential in creating a hard to understand codebase! (cough job security cough), but this codebase was imo really nice to grasp :D. (libraries also help with this, making it harder to create ‘hard to read’ code in the first place!)

3 Likes

Didn’t work for me. I had to click on the expand sign: double arrow (in the lower right corner) first or download the image.

But then I read a Great explanation!

3 Likes

oh… right! that opens the thumbnail of the image… :man_facepalming:, yeah, click & open link in new tab, or directly on the image! thanks! :smiley:

1 Like

Thanks so much for the time you put into this :slight_smile:

1 Like