๐ŸŽ‡ Dandelion

BamgasiJMยท2026๋…„ 3์›” 14์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
64/65
post-thumbnail

๐Ÿ“ p5.js

// * Dandelion Generative Art

// ===============================================
// [1. GLOBAL CONFIGURATION] 
// ===============================================
const MAX_GEN = 7; // ์ตœ๋Œ€ ์„ฑ์žฅ ๋‹จ๊ณ„ (์„ธ๋Œ€)
const START_BRANCH_COUNT = 6; // ์ดˆ๊ธฐ ์ค‘์‹ฌ์—์„œ ๋ป—์–ด ๋‚˜๊ฐ€๋Š” ๊ฐ€์ง€ ์ˆ˜
const SUB_BRANCH_COUNT = 4; // ์ดํ›„ ๊ฐ ๋งˆ๋””์—์„œ ๋ถ„๊ธฐ๋˜๋Š” ๊ฐ€์ง€ ์ˆ˜

const MIN_LINE_LEN = 80; // ์ตœ์†Œ ๊ฐ€์ง€ ๊ธธ์ด (px)
const MAX_LINE_LEN = 90; // ์ตœ๋Œ€ ๊ฐ€์ง€ ๊ธธ์ด (px)

const MIN_DOT_SIZE = 2; // ์ค‘์‹ฌ๋ถ€ ๋…ธ๋“œ ์ตœ์†Œ ํฌ๊ธฐ
const MAX_DOT_SIZE = 5; // ๋ง๋‹จ ์”จ์•— ์ตœ๋Œ€ ํฌ๊ธฐ

const BG_COLOR = "#432f2f"; // ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ HEX
const LINE_COLOR = [255, 180]; // ์„  ์ƒ‰์ƒ ๋ฐ ํˆฌ๋ช…๋„ [R, G, B, Alpha] ๋˜๋Š” [Gray, Alpha]
const DOT_COLOR = [255, 220]; // ์  ์ƒ‰์ƒ ๋ฐ ํˆฌ๋ช…๋„

// ===============================================
// [2. STATE VARIABLES]
// ===============================================
let nodes = []; // ์ „์ฒด ๋…ธ๋“œ ์ €์žฅ ๋ฐฐ์—ด (๋ Œ๋”๋ง์šฉ)
let activeNodes = []; // ํ˜„์žฌ ๋ถ„๊ธฐ ์ค‘์ธ ๋ง๋‹จ ๋…ธ๋“œ ๋ฐฐ์—ด (์—ฐ์‚ฐ์šฉ)
let lastBranchTime = 0; // ๋งˆ์ง€๋ง‰ ๋ถ„๊ธฐ ์‹œ์  ๊ธฐ๋ก
const BRANCH_INTERVAL = 500; // ๋ถ„๊ธฐ ๊ฐ„๊ฒฉ (๋ฐ€๋ฆฌ์„ธ์ปจ๋“œ)

// ===============================================
// [3. P5.JS CORE]
// ===============================================
function setup() {
  createCanvas(1200, 1200);
  background(BG_COLOR);

  // ์ดˆ๊ธฐ ๋ฃจํŠธ ๋…ธ๋“œ ์„ค์ • (์บ”๋ฒ„์Šค ์ •์ค‘์•™)
  const root = {
    x: width / 2,
    y: height / 2,
    parent: null,
    generation: 0,
    angle: 0,
  };

  nodes.push(root);
  activeNodes.push(root);
  lastBranchTime = millis();
}

function draw() {
  background(BG_COLOR);

  // ์ „์ฒด ๋…ธ๋“œ ์ˆœํšŒ ๋ฐ ๋ Œ๋”๋ง
  for (let i = 0; i < nodes.length; i++) {
    const n = nodes[i];

    // 1. ๋ผ์ธ ๋ Œ๋”๋ง
    if (n.parent) {
      // ์„ธ๋Œ€๊ฐ€ ์ง„ํ–‰๋ ์ˆ˜๋ก ์„ ์ด ๊ฐ€๋Š˜์–ด์ง€๋„๋ก ์„ค์ •
      const sw = map(n.generation, 1, MAX_GEN, 1.2, 0.2);
      stroke(LINE_COLOR);
      strokeWeight(sw);
      line(n.x, n.y, n.parent.x, n.parent.y);
    }

    // 2. ๋…ธ๋“œ(์ ) ๋ Œ๋”๋ง
    noStroke();
    fill(DOT_COLOR);
    // ์„ธ๋Œ€์— ๋”ฐ๋ผ ์  ํฌ๊ธฐ ๊ฒฐ์ • (๋ง๋‹จ์ผ์ˆ˜๋ก MAX_DOT_SIZE์— ์ˆ˜๋ ด)
    const dotSize = map(n.generation, 0, MAX_GEN, MIN_DOT_SIZE, MAX_DOT_SIZE);
    circle(n.x, n.y, dotSize);
  }

  // 3. ๋ถ„๊ธฐ ํƒ€์ด๋ฐ ์ฒดํฌ ๋ฐ ์‹คํ–‰
  if (millis() - lastBranchTime > BRANCH_INTERVAL) {
    if (activeNodes.length > 0 && activeNodes[0].generation < MAX_GEN) {
      branchOut();
      lastBranchTime = millis();
    } else if (
      activeNodes.length > 0 &&
      activeNodes[0].generation === MAX_GEN
    ) {
      // ๋ชจ๋“  ์„ฑ์žฅ์ด ๋๋‚ฌ์„ ๋•Œ ๋ถˆํ•„์š”ํ•œ ๋ฃจํ”„ ์ •์ง€ (์„ฑ๋Šฅ ์ตœ์ ํ™”)
      console.log("Growth Complete. Loop stopped.");
      noLoop();
    }
  }
}

// ===============================================
// [4. LOGIC FUNCTIONS]
// ===============================================
function branchOut() {
  const nextActiveNodes = [];

  for (let i = 0; i < activeNodes.length; i++) {
    const p = activeNodes[i];

    // ์บ”๋ฒ„์Šค ๊ฒฝ๊ณ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์ž์‹ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์Œ (๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ)
    if (p.x < 0 || p.x > width || p.y < 0 || p.y > height) continue;

    const currentGen = p.generation;
    const isRoot = currentGen === 0;
    const count = isRoot ? START_BRANCH_COUNT : SUB_BRANCH_COUNT;

    // ๋ถ„์‚ฐ ๊ฐ๋„ ์„ค์ • (์ฒซ ๋ถ„๊ธฐ๋Š” 360๋„, ์ดํ›„๋Š” 72๋„ ๋ฒ”์œ„ ๋‚ด ๋ถ„์‚ฌ)
    const spreadAngle = isRoot ? TWO_PI : PI * 0.4;

    for (let j = 0; j < count; j++) {
      let angle;
      if (isRoot) {
        angle = (TWO_PI / START_BRANCH_COUNT) * j;
      } else {
        // ๋ถ€๋ชจ์˜ ๊ฐ๋„๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ์ขŒ์šฐ spreadAngle ๋งŒํผ ๋ถ„์‚ฐ
        angle =
          p.angle + map(j, 0, count - 1, -spreadAngle / 2, spreadAngle / 2);
      }

      const len = random(MIN_LINE_LEN, MAX_LINE_LEN);
      const newNode = {
        x: p.x + cos(angle) * len,
        y: p.y + sin(angle) * len,
        parent: p,
        generation: currentGen + 1,
        angle: angle,
      };

      nodes.push(newNode);
      nextActiveNodes.push(newNode);
    }
  }

  // ๋‹ค์Œ ์—ฐ์‚ฐ์„ ์œ„ํ•ด ๋ง๋‹จ ๋…ธ๋“œ ๊ฐฑ์‹ 
  activeNodes = nextActiveNodes;
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€