A Noisy Walker
Table of Contents
Note To Viewers At Home: This sketch disturbs my rabbit. Viewer discretion is advised.
This is a follow-up to the Random Walker post. In that previous post I made a walker that moved randomly in any (2D) direction. In this post I'll make a walker that moves according to values given by the p5 noise function. This is a pretty straight repeat of what's in the introduction to the Nature of Code.
The Noise Walker
The NoiseWalker keeps track of its position on the canvas as well as moving itself and plotting a circle in its current location. Its constructor starts it at the center of the canvas and creates a noise-offset vector to hold the inputs to the noise function. The noise-offset vector is initially given random x and y values so they aren't the same - since noise
is a function if we passed in the same value to it for both x and y they would both get the same value out of it and we'd end up with a diagonal line instead of something that looks random-ish the way that we want.
The first call to the walk
method will clobber the initial x and y positions so setting it to the center of the canvas isn't really important.
/** a noise-based walker */
class NoiseWalker {
/** create the Noise Walker
* @param: p5 - a p5.js instance
* @param: slider - widget to get the amount of noise offset change
* @param: stroke_weight: how thick to make the circle line
* @param: diameter of the circle
* @param: fill_color: color to fill the circle
* @param: stroke_color - color for the circle's line
*/
constructor({p5,
slider,
stroke_weight=1,
diameter=24,
fill_color="cornflowerblue",
stroke_color="black"} = {}) {
let noise_upper_bound = 10**5
this.p5 = p5;
this.slider = slider;
this.stroke_weight = stroke_weight;
this.diameter = diameter;
this.fill_color = fill_color;
this.stroke_color = stroke_color;
this.position = p5.createVector(p5.width / 2, p5.height / 2);
this.noise_offset = p5.createVector(p5.random(noise_upper_bound),
p5.random(noise_upper_bound));
} // end constructor
Noise Value Offset
This property will return the current value of the slider. It's maybe overkill, but I'm trying to re-learn javascript along with p5 and follow along with The Nature of Code so I need things to be extra-obvious, sometimes.
/** getter for amount to add to the noise offset
* @returns {number}: amount to add to the noise offset on walking
*/
get noise_offset_change() {
return this.slider.value();
} // end get noise_offset_change
Walk
The walk
method moves the walker by adding some noise to its position. The noise
function outputs a value from 0 to 1 so I'll use it as a scale factor for the width and height of the canvas to get the new location of the walker. Note that we're not using the prior position of the walker when calculating the new one, just the noise.
/** update the position and noise offset */
walk() {
this.position.x = this.p5.noise(this.noise_offset.x) * this.p5.width;
this.position.y = this.p5.noise(this.noise_offset.y) * this.p5.height;
this.noise_offset.add(this.noise_offset_change,
this.noise_offset_change);
} // end walk
Show Yourself
The Noise Walker's show_yourself
method draws a circle wherever the walker happens to be at the moment. Nothing fancy.
show_yourself() {
this.p5.strokeWeight(this.stroke_weight);
this.p5.fill(this.fill_color);
this.p5.stroke(this.stroke_color);
this.p5.circle(this.position.x, this.position.y, this.diameter);
} // end show_yourself
The Sketch
I'll put the sketch in a function named "noise_walk".
NOISY_WALKER_DIV = "noisy-walker";
/** a sketch to make a circle-drawing walker that moves with noise */
function noise_walk(p5js) {
const SLIDER_WIDTH = 500;
const MEDIUM_TEAL_BLUE = p5js.color(0, 89, 179, 100);
const MEDIUM_TEAL_BLUE_OPAQUE = p5js.color(0, 89, 179);
let walker;
let slider;
Set Up
The setup
method will create the canvas, a slider which the user can use to change the size of the steps the walker takes along the noise offset, and the walker itself. The canvas and slider are placed based on the order in which you create them. In this case I wanted the slider underneath the canvas so I had to define it after the canvas (but before the walker since I pass it to the walker).
/** setup the canvas, walker, and slider */
p5js.setup = function() {
p5js.createCanvas(
document.getElementById(NOISY_WALKER_DIV).offsetWidth,
400);
// a slider to let the user change how much the noise is changing
slider = p5js.createSlider(0, 1, 0.01, 0);
slider.style("width", `${SLIDER_WIDTH}px`);
walker = new NoiseWalker({p5: p5js,
slider: slider,
fill_color:MEDIUM_TEAL_BLUE});
p5js.background("white");
} // end setup
Draw
The draw function moves and shows the walker.
/** move and draw the walker */
p5js.draw = function() {
walker.walk();
walker.show_yourself();
p5js.textSize(32);
p5js.textAlign(p5js.CENTER);
p5js.fill("white");
p5js.noStroke()
p5js.rect(p5js.width/2 + 20, p5js.height - 35 , 250, 30);
p5js.fill(MEDIUM_TEAL_BLUE_OPAQUE);
p5js.text(`Noise Change: ${slider.value().toFixed(3)}`,
p5js.width/2 , p5js.height - 10);
} // end draw
The End
And there's the code for the sketch at the top of the page.
Sources
- Nature of Code [Internet]. [cited 2023 May 11]. Available from: https://nature-of-code-2nd-edition.netlify.app/
- p5 reference | noise() [Internet]. [cited 2023 Apr 25]. Available from: https://p5js.org/reference/#/p5/noise