🔮 :: Bounce Party

BamgasiJM·2025년 9월 30일

Nannou <Generative Art>

목록 보기
35/55
post-thumbnail

📝 Rust Code

use nannou::prelude::*;

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

struct Ball {
    position: Vec2,
    velocity: Vec2,
}

struct Model {
    balls: Vec<Ball>,
    gravity: f32,
}

fn model(app: &App) -> Model {
    app.new_window().size(800, 800).view(view).build().unwrap();

    let balls = (0..5000)
        .map(|_| Ball {
            position: vec2(random_range(-400.0, 400.0), random_range(0.0, 800.0)),
            velocity: vec2(0.0, random_range(-5.0, 5.0)),
        })
        .collect();

    Model { balls, gravity: -0.1 }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    for ball in &mut model.balls {
        // 중력 적용
        ball.velocity.y += model.gravity;
        ball.position += ball.velocity;

        // 바닥 충돌 처리
        if ball.position.y < -390.0 {
            ball.position.y = -390.0;
            ball.velocity.y *= -0.9; // 반사 & 감쇠
        }

        // 좌우 화면 벽 충돌
        if ball.position.x > 390.0 {
            ball.position.x = 390.0;
            ball.velocity.x *= -0.4;
        }
        if ball.position.x < -390.0 {
            ball.position.x = -390.0;
            ball.velocity.x *= -0.8;
        }
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();
    draw.rect().w_h(800.0, 800.0).color(hsla(0.0, 0.0, 0.01, 0.1));

    for ball in &model.balls {
        draw.ellipse().xy(ball.position).radius(1.5).color(rgba(0.0, 1.0, 0.8, 0.8));
    }

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

📝 Rust Code + Refactoring

use nannou::prelude::*;

const NUM_BALLS: usize = 5000;
const WINDOW_SIZE: f32 = 800.0;
const BALL_RADIUS: f32 = 1.5;
const GRAVITY: f32 = -0.1;
const FLOOR_Y: f32 = -390.0;
const WALL_X: f32 = 390.0;
const BOUNCE_LOSS_Y: f32 = -0.9;
const BOUNCE_LOSS_X_RIGHT: f32 = -0.4;
const BOUNCE_LOSS_X_LEFT: f32 = -0.8;

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

struct Ball {
    position: Vec2,
    velocity: Vec2,
}

struct Model {
    balls: Vec<Ball>,
}

fn model(app: &App) -> Model {
    app.new_window()
        .size(WINDOW_SIZE as u32, WINDOW_SIZE as u32)
        .view(view)
        .build()
        .unwrap();

    let mut balls = Vec::with_capacity(NUM_BALLS);
    for _ in 0..NUM_BALLS {
        balls.push(Ball {
            position: vec2(
                random_range(-WINDOW_SIZE / 2.0, WINDOW_SIZE / 2.0),
                random_range(0.0, WINDOW_SIZE),
            ),
            velocity: vec2(0.0, random_range(-5.0, 5.0)),
        });
    }
    Model { balls }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    for ball in &mut model.balls {
        ball.velocity.y += GRAVITY;
        ball.position += ball.velocity;
        handle_collision(ball);
    }
}

fn handle_collision(ball: &mut Ball) {
    if ball.position.y < FLOOR_Y {
        ball.position.y = FLOOR_Y;
        ball.velocity.y *= BOUNCE_LOSS_Y;
    }
    if ball.position.x > WALL_X {
        ball.position.x = WALL_X;
        ball.velocity.x *= BOUNCE_LOSS_X_RIGHT;
    }
    if ball.position.x < -WALL_X {
        ball.position.x = -WALL_X;
        ball.velocity.x *= BOUNCE_LOSS_X_LEFT;
    }
}

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

    draw.rect()
        .w_h(WINDOW_SIZE, WINDOW_SIZE)
        .color(hsla(0.0, 0.0, 0.01, 0.1));

    for ball in &model.balls {
        draw.ellipse()
            .xy(ball.position)
            .radius(BALL_RADIUS)
            .color(rgba(0.0, 1.0, 0.8, 0.8));
    }

    draw.to_frame(app, &frame).unwrap();
}
profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0개의 댓글