Dan Quinn

Code Sketch - Wobbler


Nannou source code:

use nannou::prelude::*;

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

struct Model {
    cols: u32,
    rows: u32,
    grid_size: u32,
    padding: u32,
    wobble_timer: i32,
    wobbler: [i32; 2],
}

fn model(app: &App) -> Model {
    // Create a new window! Store the ID so we can refer to it later.
    let width = 200;
    let height = 200;
    let grid_size = 40;
    let padding = 5;
    let cols = width / grid_size;
    let rows = height / grid_size;

    app.new_window()
        .size(width, height)
        .view(view)
        .build()
        .unwrap();

    Model {
        cols,
        rows,
        grid_size,
        padding,
        wobble_timer: 0,
        wobbler: [0, 0],
    }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    model.wobble_timer += 1;
    if model.wobble_timer > 10 {
        model.wobbler[0] = map_range(random_f32(), 0.0, 1.0, 1.0, (model.cols - 1) as f32).floor() as i32;
        model.wobbler[1] = map_range(random_f32(), 0.0, 1.0, 1.0, (model.rows - 1) as f32).floor() as i32;
        model.wobble_timer = 0;
    }
}

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

    if frame.nth() == 0 {
        draw.background().color(BLACK);
    }
    
    draw.rect()
        .w_h(win_r.w(), win_r.h())
        .color(rgba(0.0, 0.0, 0.0, 0.01));

    let t1 = app.time * 2.0;
    let t2 = app.time * 3.0;
    
    for i in 1..model.rows - 1 {
        for j in 1..model.cols - 1 {

            if model.wobbler[0] == i as i32 && model.wobbler[1] == j as i32 {
                let mut x = map_range(i as f32, 0.0, model.rows as f32, win_r.left(), win_r.right()) + model.grid_size as f32 / 2.0;
                let mut y = map_range(j as f32, 0.0, model.rows as f32, win_r.left(), win_r.right()) + model.grid_size as f32 / 2.0;
                y += t1.sin() * (t2.sin() * 10.0);
                x += t1.cos() * (t2.cos() * 10.0);

                draw.rect()
                    .x_y(x, y)
                    .w_h(model.grid_size as f32 - model.padding as f32 / 2.0, model.grid_size as f32 - model.padding as f32 / 2.0)
                    .stroke_weight(2.0)
                    .color(BLACK)
                    .stroke(hsl(clamp(t1.sin(), 0.6, 0.7), 1.0, 0.5));
            }
        }
    }

    // Write the result of our drawing to the window's frame.
    draw.to_frame(app, &frame).unwrap();
    
    if frame.nth() < 300 {
        let file_path = captured_frame_path(app, &frame);
        app.main_window().capture_frame(file_path);
    }
}

fn captured_frame_path(app: &App, frame: &Frame) -> std::path::PathBuf {
    app.project_path()
        .expect("failed to locate `project_path`")
        .join("frames")
        .join(format!("{:04}", frame.nth()))
        .with_extension("png")
}