const flowerPalette = [
"#5A9CB5", // ピンク
"#FACE68", // クリーム
"#FAAC68", // ミント
"#FA6868" // ライトブルー
];
const bgColor = "#001F3D";
const flowers = [];
const num = 1000;
const petals = [];
class Petal {
constructor(x, y, angle, size, col, depth, windSeed) {
this.x = x;
this.y = y;
this.angle = angle;
this.size = size;
this.col = col;
this.depth = depth;
this.windSeed = windSeed;
this.spin = random(-0.03, 0.03);
this.alpha = 100;
}
update() {
const t = constrain(map(this.y, height, 0, 0, 1), 0, 1);
const riseSpeed = lerp(3.0, 0.8, t);
this.y -= riseSpeed;
this.angle += this.spin * 0.5;
this.alpha = lerp(100, 0, t);
return (this.y < -80 || this.alpha < 2);
}
draw() {
push();
translate(this.x, this.y);
rotate(this.angle);
noStroke();
const c = color(this.col);
c.setAlpha(this.alpha);
fill(c);
const s = this.size * this.depth;
ellipse(0, 0, s * 0.9, s * 0.4);
pop();
}
}
class Flower {
constructor() {
this.reset();
}
reset() {
this.x = random(width);
this.y = random(height, height * 3);
this.baseX = this.x;
this.type = "round"; // 分離処理は round のみ対応(必要なら他にも実装可)
this.size = random(10, 20);
this.petals = int(random(5, 8));
this.col1 = color(random(flowerPalette));
this.col2 = color(random(flowerPalette));
this.depth = random(0.5, 1.4);
this.angle = random(TAU);
this.spin = random(-0.01, 0.01);
this.speed = random(0.3, 1.4);
this.windSeed = random(1000);
this.petalAngles = [];
for (let i = 0; i < this.petals; i++) {
this.petalAngles.push((TAU / this.petals) * i);
}
}
update() {
const t = constrain(map(this.y, height, 0, 0, 1), 0, 1);
const riseSpeed = lerp(3.2, 0.6, t);
this.y -= riseSpeed;
const windStrength = lerp(160, 30, t);
const wind = noise(frameCount * 0.002, this.windSeed) * 2 - 1;
this.x = this.baseX + wind * windStrength * this.depth;
this.angle += this.spin * lerp(1.2, 0.3, t);
this.alpha = lerp(100, 0, t);
// 花びら分離判定
if (
this.petalAngles.length > 2 &&
this.alpha > 40 &&
random() < 0.005
) {
const idx = floor(random(this.petalAngles.length));
const pa = this.petalAngles[idx];
const s = this.size * this.depth;
const px = this.x + cos(this.angle + pa) * s;
const py = this.y + sin(this.angle + pa) * s;
petals.push(
new Petal(px, py, pa, this.size, this.col1, this.depth, random(1000))
);
this.petalAngles.splice(idx, 1);
}
if (this.y < -80 || this.alpha < 2) {
this.reset();
}
}
draw() {
push();
translate(this.x, this.y);
rotate(this.angle);
const s = this.size * this.depth;
noStroke();
const fillCol1 = color(this.col1);
fillCol1.setAlpha(this.alpha);
fill(fillCol1);
for (let a of this.petalAngles) {
push();
rotate(a);
translate(s, 0);
ellipse(0, 0, s * 0.9, s * 0.4);
pop();
}
const fillCol2 = color(this.col2);
fillCol2.setAlpha(this.alpha);
fill(fillCol2);
circle(0, 0, s * 0.6);
pop();
}
}
function setup() {
createCanvas(windowWidth, windowHeight);
colorMode(HSB, 360, 100, 100, 100);
noiseDetail(4, 0.5);
for (let i = 0; i < num; i++) {
flowers.push(new Flower());
}
}
function draw() {
background(color(bgColor));
flowers.sort((a, b) => a.depth - b.depth);
for (const f of flowers) {
f.update();
f.draw();
}
for (let i = petals.length - 1; i >= 0; i--) {
const p = petals[i];
if (p.update()) {
petals.splice(i, 1);
} else {
p.draw();
}
}
}