-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
3 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<link rel="stylesheet" href="../reset.css" type="text/css" /> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<script src="../p5.min.js"></script> | ||
<script src="./index.js"></script> | ||
<title>Flocking</title> | ||
</head> | ||
<body></body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters