xxxxxxxxxx
187
const PI = Math.PI;
const MAX_ACTIVE_PARTICLES = 100;
const MAX_RADIUS = 45;
const LIFESPAN_DECREASE = 0.98;
const PARTICLE_SIZE_RANGE = [1, 3]; // Minimum and maximum size of particles
const SPLIT_ANGLE_RANGE = [-PI / 6, PI / 6]; // Range for angle variation when splitting
const BRANCHING_FACTOR = 5; // Controls the probability of branching
const COLOR = "#ECFDFE992"; // Particle color
const BACKGROUND_COLOR = "#A7C7E7"; // Background color
const SNOWFLAKE_ARMS_RANGE = [5,6,7,8,9,10,11, 12]; // Range for number of arms of a snowflake
const PARTICLE_SIZE_VARIABILITY = 0.2;
const ICE_PARTICLE_SIZE = 1;
const MAX_PARTICLES_PER_SNOWFLAKE = 200; // Limit the number of particles
const ROUND_NESS = 0.8;
class IceParticle {
constructor(x, y, angle, size, snowflake_center) {
this.pos = createVector(x, y);
this.snowflake_center = snowflake_center
this.dir = p5.Vector.fromAngle(angle).mult(random() * 2);
this.lifespan = 255;
this.size = size || random(PARTICLE_SIZE_RANGE[0], PARTICLE_SIZE_RANGE[1]);
}
update() {
if (this.pos.dist(this.snowflake_center) > MAX_RADIUS ) {
this.lifespan = 0; // Deactivate the particle if it exceeds MAX_RADIUS
} else {
this.pos.add(this.dir);
this.lifespan *= LIFESPAN_DECREASE;
}
}
display() {
stroke(225,255,255, this.lifespan);
ellipse(this.pos.x, this.pos.y, this.size, this.size);
}
split() {
let newAngle = this.dir.heading() + random(SPLIT_ANGLE_RANGE[0], SPLIT_ANGLE_RANGE[1]);
let newSize = this.size * PARTICLE_SIZE_VARIABILITY;
return new IceParticle(this.pos.x, this.pos.y, newAngle, newSize, this.snowflake_center);
}
}
class Snowflake {
constructor(x, y, arms) {
this.particles = [];
let mycenter = createVector(x, y);
this.center = mycenter;
for (let i = 0; i < arms; i++) {
this.particles.push(new IceParticle(x, y, (TWO_PI / arms) * i, ICE_PARTICLE_SIZE , mycenter));
}
this.activeParticles = new Set(this.particles);
}
doneness() {
return this.particles[0].pos.dist(this.center) / MAX_RADIUS;
}
update() {
this.particles = this.particles.filter(p => p.lifespan > 0);
if (this.activeParticles.size < MAX_ACTIVE_PARTICLES) {
var branch = random(1) < this.doneness() / BRANCHING_FACTOR;
this.particles.forEach(p => {
if (branch && p.pos.dist(this.center) < MAX_RADIUS) {
let newParticle = p.split();
this.particles.push(newParticle);
this.activeParticles.add(newParticle);
}
});
}
this.activeParticles.forEach(p => p.update());
}
display() {
stroke(COLOR);
this.particles.forEach(p => p.display());
}
}
class BrownianParticle {
constructor(x, y) {
this.pos = createVector(x, y);
this.prevPos = this.pos.copy();
}
update() {
if (this.finished()) return; // Stop updating if finished
this.prevPos = this.pos.copy();
let step = p5.Vector.random2D();
this.pos.add(step);
}
display() {
if (this.finished()) return; // Don't display if finished
line(this.prevPos.x, this.prevPos.y, this.pos.x, this.pos.y);
}
finished() {
return this.pos.mag() > MAX_RADIUS;
}
intersects(snowflake) {
return snowflake.some(p => p.pos.dist(this.pos) < this.size);
}
}
class RotatingSnowflake {
constructor(x, y, arms) {
this.center = createVector(x, y);
this.arms = arms;
this.particles = [];
this.current = new BrownianParticle(0, 0);
this.particleCount = 0;
}
update() {
if (this.particleCount >= MAX_PARTICLES_PER_SNOWFLAKE) return; // Limit the number of particles
if (!this.current.finished() && !this.current.intersects(this.particles)) {
this.current.update();
} else {
this.particles.push(this.current);
this.current = new BrownianParticle(0, 0);
this.particleCount++;
}
}
display() {
push(); // Save the current drawing state
translate(this.center.x, this.center.y);
strokeWeight(0.5)
stroke(225,225,255,25)
for (let i = 0; i < this.arms; i++) {
rotate(TWO_PI / this.arms);
this.current.display();
this.particles.forEach(p => p.display());
push();
scale(1, -1);
this.current.display();
this.particles.forEach(p => p.display());
pop();
}
pop(); // Restore the original drawing state
}
}
let snowflakes = [];
function setup() {
createCanvas(windowWidth, windowHeight);
background(BACKGROUND_COLOR);
spawnSnowFlake(width/2, height/2);
}
function spawnSnowFlake(x, y) {
let n_arms = random(SNOWFLAKE_ARMS_RANGE);
// let snowflakeType = random([Snowflake, RotatingSnowflake]);
// snowflakes.push(new snowflakeType(x, y, n_arms));
// snowflakes.push(new Snowflake(x, y, n_arms));
snowflakes.push(new RotatingSnowflake(x, y, n_arms));
}
function mousePressed(){
spawnSnowFlake(mouseX, mouseY)
}
function draw() {
snowflakes.forEach(snowflake => {
snowflake.update();
snowflake.display();
});
}