๐Ÿ”ฎ :: Colorful Rain

BamgasiJMยท2025๋…„ 11์›” 2์ผ

Nannou <Generative Art>

๋ชฉ๋ก ๋ณด๊ธฐ
50/55
post-thumbnail

๐Ÿ“ Rust Code

use nannou::prelude::*;

// ๐ŸŒ ์ „์—ญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์ˆ˜
const CANVAS_SIZE: u32 = 1000;
const GRAVITY_ACCEL_PIXELS: f32 = 30.0;
const INITIAL_RADIUS: f32 = 1.5;
const SPAWN_INTERVAL: f32 = 0.0;
const MAX_CIRCLES: usize = 1000;

// ๐Ÿ’ง ๋‚™ํ•˜ํ•˜๋Š” ์› ๊ตฌ์กฐ์ฒด
struct Drop {
    position: Point2,
    velocity: f32,
    radius: f32,
    color: Hsla,
    is_active: bool,
}

impl Drop {
    fn activate(canvas_w: f32) -> Self {
        let x = random_range(-canvas_w / 2.0, canvas_w / 2.0);
        let y = canvas_w / 2.0;

        Drop {
            position: pt2(x, y),
            velocity: 0.0,
            radius: INITIAL_RADIUS,
            color: hsla(random(), 0.8, 0.5, 1.0),
            is_active: true,
        }
    }

    fn update(&mut self, dt: f32, canvas_h: f32) {
        if !self.is_active {
            return;
        }

        self.velocity += GRAVITY_ACCEL_PIXELS * dt;
        self.position.y -= self.velocity * dt;

        if self.position.y < -canvas_h / 2.0 - self.radius {
            self.is_active = false;
        }
    }

    fn draw(&self, draw: &Draw) {
        if !self.is_active {
            return;
        }

        draw.ellipse().xy(self.position).radius(self.radius).color(self.color);
    }
}

// ๐Ÿ“ฆ ๋ชจ๋ธ ๊ตฌ์กฐ์ฒด
struct Model {
    drops: Vec<Drop>,
    last_spawn_time: f32,
    canvas_w: f32,
    canvas_h: f32,
}

impl Model {
    fn find_inactive_drop(&mut self) -> Option<&mut Drop> {
        self.drops.iter_mut().find(|d| !d.is_active)
    }

    fn spawn_drop(&mut self, time: f32) {
        if time - self.last_spawn_time >= SPAWN_INTERVAL {
            let canvas_width = self.canvas_w;

            if let Some(drop) = self.find_inactive_drop() {
                // ์žฌํ™œ์šฉ
                *drop = Drop::activate(canvas_width);
            } else if self.drops.len() < MAX_CIRCLES {
                // ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ
                self.drops.push(Drop::activate(canvas_width));
            }

            self.last_spawn_time = time;
        }
    }
}

fn model(app: &App) -> Model {
    app.new_window()
        .size(CANVAS_SIZE, CANVAS_SIZE)
        .title("Rain in Hue")
        .view(view)
        .build()
        .unwrap();

    let rect = app.window_rect();

    let drops = Vec::with_capacity(MAX_CIRCLES);

    Model {
        drops,
        last_spawn_time: 0.0,
        canvas_w: rect.w(),
        canvas_h: rect.h(),
    }
}

fn update(app: &App, model: &mut Model, update: Update) {
    let time = app.time;
    let dt = update.since_last.as_secs_f32();

    model.spawn_drop(time);

    for drop in &mut model.drops {
        drop.update(dt, model.canvas_h);
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();

    if frame.nth() == 0 {
        draw.background().color(hsla(0.0, 0.0, 0.01, 1.0));
    } else {
        draw.rect().wh(app.window_rect().wh()).color(hsla(0.0, 0.0, 0.01, 0.01));
    }

    for drop in model.drops.iter().filter(|d| d.is_active) {
        drop.draw(&draw);
    }

    draw.to_frame(app, &frame).unwrap();
}

fn main() {
    nannou::app(model).update(update).run();
}

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

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