subtitled #13: goop eating ants
parent
45fbe5a37f
commit
d333c9c9d6
|
@ -2390,6 +2390,14 @@ dependencies = [
|
|||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled13"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nannou",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtitled2"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "subtitled13"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nannou = "0.17"
|
||||
utils = { path = "../utils" }
|
|
@ -0,0 +1,89 @@
|
|||
use nannou::prelude::*;
|
||||
use nannou::rand::seq::SliceRandom;
|
||||
use utils::*;
|
||||
|
||||
fn main() {
|
||||
nannou::app(model).update(update).simple_window(view).run();
|
||||
}
|
||||
|
||||
struct Model {
|
||||
walkers: Vec<Vec2>,
|
||||
clustered: Vec<Vec2>,
|
||||
}
|
||||
|
||||
fn model(_app: &App) -> Model {
|
||||
Model {
|
||||
walkers: (0..5000).map(|_| vec2_range(-1.0, 1.0) * 300.0).collect(),
|
||||
clustered: vec![Vec2::ZERO],
|
||||
}
|
||||
}
|
||||
|
||||
fn update(app: &App, model: &mut Model, _update: Update) {
|
||||
let _t = app.elapsed_frames() as f32 / 60.0;
|
||||
|
||||
let mut clusters = model.clustered.clone();
|
||||
clusters.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
|
||||
|
||||
let mut to_remove = vec![];
|
||||
for (i, p) in &mut model.walkers.iter_mut().enumerate() {
|
||||
*p += vec2_range(-1.0, 1.0) * 3.5;
|
||||
|
||||
const RAD: f32 = 6.0;
|
||||
for &c in &clusters {
|
||||
if c.x > p.x + RAD {
|
||||
break;
|
||||
}
|
||||
if c.x < p.x - RAD {
|
||||
continue;
|
||||
}
|
||||
if p.distance_squared(c) < RAD * RAD {
|
||||
model.clustered.push(*p);
|
||||
to_remove.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i in to_remove.into_iter().rev() {
|
||||
model.walkers.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
fn view(app: &App, model: &Model, frame: Frame) {
|
||||
let t = frame.nth() as f32 / 60.0;
|
||||
|
||||
let draw = app.draw();
|
||||
|
||||
drawing::draw_soft_bg(&draw, app, SNOW, 0.03);
|
||||
|
||||
for &p in &model.walkers {
|
||||
draw.ellipse().xy(p).radius(1.0).color(BLACK);
|
||||
}
|
||||
for &p in &model.clustered {
|
||||
let v = map_sin(t + (p.x.powi(2) + p.y.powi(2) + t) * 0.00003, -20.0, 20.0);
|
||||
let h = (100.0 + v) / 360.0;
|
||||
draw.ellipse()
|
||||
.xy(p)
|
||||
.radius(4.0)
|
||||
.color(hsla(h, 0.5, 0.5, 0.3));
|
||||
}
|
||||
|
||||
let mut rng = nannou::rand::thread_rng();
|
||||
let n = (frame.nth() as f32 * 0.7) as usize;
|
||||
for _ in 0..n {
|
||||
let a = model.clustered.choose(&mut rng);
|
||||
let b = model.clustered.choose(&mut rng);
|
||||
if let (Some(&a), Some(&b)) = (a, b) {
|
||||
let v = map_sin(t * 2.0 + a.x * a.y, -20.0, 20.0);
|
||||
let h = (100.0 + v) / 360.0;
|
||||
|
||||
draw.line()
|
||||
.stroke_weight(3.0)
|
||||
.points(a, b)
|
||||
.color(hsla(h, 0.5, 0.5, 0.04));
|
||||
}
|
||||
}
|
||||
|
||||
draw.to_frame(app, &frame).unwrap();
|
||||
utils::record::record(app, &frame);
|
||||
}
|
|
@ -1,5 +1,17 @@
|
|||
use nannou::{color::IntoLinSrgba, draw::properties::ColorScalar, prelude::*};
|
||||
|
||||
pub fn draw_soft_bg(draw: &Draw, app: &App, color: impl IntoLinSrgba<ColorScalar>, alpha: f32) {
|
||||
if app.elapsed_frames() <= 1 {
|
||||
draw.background().color(color);
|
||||
} else {
|
||||
let mut color = color.into_lin_srgba();
|
||||
color.alpha = alpha;
|
||||
|
||||
let win = app.window_rect();
|
||||
draw.rect().wh(win.wh()).color(color);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws the opposite of a box
|
||||
pub fn draw_exterior(draw: &Draw, size: f32, color: impl IntoLinSrgba<ColorScalar> + Clone) {
|
||||
draw.quad()
|
||||
|
|
|
@ -42,3 +42,7 @@ impl Tup2Extension for (f32, f32) {
|
|||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vec2_range(min: f32, max: f32) -> Vec2 {
|
||||
vec2(random_range(min, max), random_range(min, max))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue