:: BASIC_19_gravity_bouncing_balls

BamgasiJM·2025년 9월 30일

Nannou <BASIC>

목록 보기
30/41
post-thumbnail

📝 Rust Code

use nannou::prelude::*;

const NUM_BALLS: usize = 20;
const WINDOW_SIZE: f32 = 800.0;
const BALL_RADIUS: f32 = 10.0;
const GRAVITY: f32 = -0.1;
const FLOOR_Y: f32 = -390.0;
const WALL_X: f32 = 390.0;
const RESTITUTION: f32 = 0.7; // 바닥 반사 감쇠

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

struct Model {
    balls: Vec<Ball>,
}

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

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

    let balls = (0..NUM_BALLS)
        .map(|_| Ball {
            position: vec2(
                random_range(-WINDOW_SIZE / 2.0, WINDOW_SIZE / 2.0),
                random_range(200.0, 400.0)
            ),
            velocity: vec2(
                random_range(-2.0, 2.0),
                random_range(-2.0, 2.0)
            ),
        })
        .collect();
    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;

        // 바닥 충돌
        if ball.position.y < FLOOR_Y {
            ball.position.y = FLOOR_Y;
            ball.velocity.y *= -RESTITUTION;
        }
        // 오른쪽 벽
        if ball.position.x > WALL_X {
            ball.position.x = WALL_X;
            ball.velocity.x *= -1.0;
        }
        // 왼쪽 벽
        if ball.position.x < -WALL_X {
            ball.position.x = -WALL_X;
            ball.velocity.x *= -1.0;
        }
    }
}

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

    // 첫 프레임은 완전히 불투명(하얀색)
    let frame_nth = frame.nth(); // 0부터 시작 
    if frame_nth == 0 {
        draw.rect()
            .w_h(800.0, 800.0)
            .color(hsla(0.0, 0.0, 0.01, 1.0)); // 불투명
    } else {
        draw.rect()
            .w_h(800.0, 800.0)
            .color(hsla(0.0, 0.0, 0.01, 0.08)); // 잔상을 위한 투명도
    }

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

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

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

0개의 댓글