From 4e4b349f83fcf69eb1bba1eb760638de0c927c72 Mon Sep 17 00:00:00 2001 From: Alberto Morabito Date: Sun, 28 Jan 2024 14:47:24 +0000 Subject: [PATCH] Day 19: "Flocking" Summary: I have another generative art project. Some time ago there was a flocking algorithm article trending on HN. I then created a piece for the other project, and now look! Genuary has the same prompt. I've reused that code, but made some changes: - Birds colour based on their angle - Added some interactivity - Changed birds shape to circle --- 19/index.html | 12 +++++ 19/index.js | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 1 + 3 files changed, 141 insertions(+) create mode 100644 19/index.html create mode 100644 19/index.js diff --git a/19/index.html b/19/index.html new file mode 100644 index 0000000..b7cbdcc --- /dev/null +++ b/19/index.html @@ -0,0 +1,12 @@ + + + + + + + + + Flocking + + + diff --git a/19/index.js b/19/index.js new file mode 100644 index 0000000..acce856 --- /dev/null +++ b/19/index.js @@ -0,0 +1,128 @@ +// I already created a generative art piece called flocking +// for my old GenArt project, so I've tweaked that. + +const DEFAULT_SPEED = 5; +const DEFAULT_SIZE = 50; +const DEFAULT_PROXIMITY_RADIUS = DEFAULT_SIZE * 2; +const NOISE = 5; + +const birds = []; +const MAX_BIRDS = 150; +const numOfBirds = Math.min((innerWidth * innerHeight) / 6000, MAX_BIRDS); + +let hasClicked = false; +function setup() { + const canvas = createCanvas(innerWidth, innerHeight); + angleMode(DEGREES); + colorMode(HSB); + background("#B5E2FA"); + + canvas.mouseClicked(() => { + hasClicked = !hasClicked; + }); + + for (let i = 0; i < numOfBirds; i++) { + birds.push(new Bird()); + } +} + +function draw() { + if (!hasClicked) { + clear(); + background("#B5E2FA"); + } + for (const bird of birds) { + // Change behaviour based on nearby birds + bird.lookAround(birds); + bird.move(); + } +} + +/** + * Not the smartest of the birds.. Just roughly follows the direction + * of the nearby birds, with some added noise for more interesting + * patterns. + */ +class Bird { + x; + y; + colour; + angle; + speed; + size = DEFAULT_SIZE; + // Only birds within this radius influence this bird's behaviour. + proximityRadius = DEFAULT_PROXIMITY_RADIUS; + otherBirds = []; + + constructor( + { angle, speed } = { angle: Math.random() * 360, speed: DEFAULT_SPEED } + ) { + this.x = Math.random() * width; + this.y = Math.random() * height; + this.angle = angle; + this.speed = speed; + } + + lookAround(birds) { + this.otherBirds = this.getBirdsInProximityRange(birds); + } + + move() { + if (this.otherBirds.length > 0) { + const averageAngle = this.getAverageAngle(); + const movingInTheSameDirection = (this.angle - averageAngle) % 360 < 90; + if (movingInTheSameDirection) { + this.angle += NOISE; + } else { + this.angle = averageAngle; + } + } + + const newX = this.x + this.speed * sin(this.angle); + const newY = this.y + this.speed * cos(this.angle); + if (newX < 0 || newX > width || newY < 0 || newY > height) { + this.speed *= -1; + this.angle += NOISE; + this.y += this.speed * sin(this.angle); + this.x += this.speed * cos(this.angle); + } else { + this.y = newY; + this.x = newX; + } + + this.colour = [this.angle % 360, 100, 100]; + fill(...this.colour); + circle(this.x, this.y, this.size); + } + + getBirdsInProximityRange(birds) { + const closeBirds = []; + for (const otherBird of birds) { + const { x, y } = otherBird; + if (this === otherBird) { + continue; + } + + if (dist(this.x, this.y, x, y) <= this.proximityRadius) { + closeBirds.push(otherBird); + } + } + + return closeBirds; + } + + getAverageAngle() { + if (!this.otherBirds.length) { + return this.angle; + } + + return ( + this.otherBirds.reduce((acc, b) => acc + b.angle, 0) / + this.otherBirds.length + ); + } +} + +function windowResized() { + resizeCanvas(innerWidth, innerHeight); +} diff --git a/index.html b/index.html index 4c7aa0e..82a7551 100644 --- a/index.html +++ b/index.html @@ -94,6 +94,7 @@ Day 16: "Draw 10 000 of something" Day 17: "Inspired by Islamic art" Day 18: "Bauhaus" + Day 19: "Flocking"