| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
use crate::field::{knot, margins, unit, Dot, Field, Orbit, ZOOM}; |
| 7 |
use crate::scene::Scene; |
| 8 |
use crate::sky::{hash, Colours}; |
| 9 |
|
| 10 |
const CLUSTER: usize = 160; |
| 11 |
|
| 12 |
const DRIFT_SPEED: f32 = 7.0; |
| 13 |
const DRIFT_S: f32 = 70.0; |
| 14 |
const FADE_S: f32 = 5.0; |
| 15 |
|
| 16 |
pub struct Adrift { |
| 17 |
field: Field, |
| 18 |
orbits: Vec<Orbit>, |
| 19 |
centre: (f32, f32), |
| 20 |
w: f32, |
| 21 |
h: f32, |
| 22 |
t: f32, |
| 23 |
} |
| 24 |
|
| 25 |
impl Adrift { |
| 26 |
pub fn new(still: bool) -> Adrift { |
| 27 |
let mut field = Field::new(still); |
| 28 |
let orbits = knot("adrift", CLUSTER); |
| 29 |
for k in 0..CLUSTER { |
| 30 |
let h = hash(&format!("adrift@{k}")); |
| 31 |
let mut d = Dot::new(0.0, 0.0, 2.0 * ZOOM, if k % 7 == 0 { 2.0 } else { 0.0 }); |
| 32 |
d.bright = 0.5 + 0.5 * unit(h, 48); |
| 33 |
d.group = 0; |
| 34 |
d.order = k as u32; |
| 35 |
field.dots.push(d); |
| 36 |
} |
| 37 |
|
| 38 |
field.dots.push(Dot::new(0.0, 0.0, 8.0, 4.0)); |
| 39 |
let mut lost = Dot::new(0.0, 0.0, 3.4 * ZOOM, 0.0); |
| 40 |
lost.bright = 1.0; |
| 41 |
field.dots.push(lost); |
| 42 |
let mut a = Adrift { field, orbits, centre: (0.0, 0.0), w: 0.0, h: 0.0, t: 12.0 }; |
| 43 |
a.place(); |
| 44 |
a |
| 45 |
} |
| 46 |
|
| 47 |
fn place(&mut self) { |
| 48 |
let (cx, cy) = self.centre; |
| 49 |
for (i, o) in self.orbits.iter().enumerate() { |
| 50 |
let (x, y) = o.at((cx, cy), self.t); |
| 51 |
self.field.dots[i].x = x; |
| 52 |
self.field.dots[i].y = y; |
| 53 |
} |
| 54 |
let core = &mut self.field.dots[CLUSTER]; |
| 55 |
core.x = cx; |
| 56 |
core.y = cy; |
| 57 |
|
| 58 |
|
| 59 |
let p = self.t % DRIFT_S; |
| 60 |
let dir: f32 = -0.35; |
| 61 |
let from = self.orbits.iter().map(|o| o.radius).fold(0.0, f32::max) + 14.0; |
| 62 |
let lost = &mut self.field.dots[CLUSTER + 1]; |
| 63 |
lost.x = cx + dir.cos() * (from + p * DRIFT_SPEED); |
| 64 |
lost.y = cy + dir.sin() * (from + p * DRIFT_SPEED); |
| 65 |
lost.bright = ((DRIFT_S - p) / FADE_S).min(p / FADE_S).clamp(0.0, 1.0); |
| 66 |
} |
| 67 |
} |
| 68 |
|
| 69 |
impl Scene for Adrift { |
| 70 |
fn resize(&mut self, w: f32, h: f32, avoid: Option<(f32, f32)>) { |
| 71 |
self.w = w; |
| 72 |
self.h = h; |
| 73 |
self.centre = match margins(w, avoid) { |
| 74 |
Some((l, _)) => (l * 0.45, h * 0.62), |
| 75 |
None => (w * 0.15, h * 0.7), |
| 76 |
}; |
| 77 |
self.place(); |
| 78 |
} |
| 79 |
fn point(&mut self, at: Option<(f32, f32)>) { |
| 80 |
self.field.point(at); |
| 81 |
} |
| 82 |
fn step(&mut self, dt: f32) { |
| 83 |
if !self.field.still { |
| 84 |
self.t += dt.clamp(0.0, 0.1); |
| 85 |
} |
| 86 |
self.place(); |
| 87 |
self.field.light(dt); |
| 88 |
} |
| 89 |
fn instances(&self, c: &Colours, out: &mut Vec<f32>) { |
| 90 |
self.field.instances(c, out) |
| 91 |
} |
| 92 |
fn links(&self, c: &Colours, out: &mut Vec<f32>) { |
| 93 |
self.field.links(c, out) |
| 94 |
} |
| 95 |
fn label(&self) -> Option<(&str, f32, f32)> { |
| 96 |
None |
| 97 |
} |
| 98 |
fn busy(&self) -> bool { |
| 99 |
!self.field.still || self.field.easing() |
| 100 |
} |
| 101 |
fn still(&self) -> bool { |
| 102 |
self.field.still |
| 103 |
} |
| 104 |
fn size(&self) -> (f32, f32) { |
| 105 |
(self.w, self.h) |
| 106 |
} |
| 107 |
} |
| 108 |
|
| 109 |
#[cfg(test)] |
| 110 |
mod tests { |
| 111 |
use super::*; |
| 112 |
|
| 113 |
#[test] |
| 114 |
fn one_mark_drifts_away_from_the_cluster_and_sets_out_again() { |
| 115 |
let mut a = Adrift::new(false); |
| 116 |
a.resize(2560.0, 1270.0, Some((707.0, 1838.0))); |
| 117 |
assert!(a.centre.0 < 707.0, "the cluster sits in the margin"); |
| 118 |
let dist = |a: &Adrift| { |
| 119 |
let l = &a.field.dots[CLUSTER + 1]; |
| 120 |
(l.x - a.centre.0).hypot(l.y - a.centre.1) |
| 121 |
}; |
| 122 |
let early = dist(&a); |
| 123 |
for _ in 0..200 { |
| 124 |
a.step(0.1); |
| 125 |
} |
| 126 |
assert!(dist(&a) > early + 100.0, "it drifts away"); |
| 127 |
for _ in 0..500 { |
| 128 |
a.step(0.1); |
| 129 |
} |
| 130 |
assert!(dist(&a) < early + 100.0, "and sets out again"); |
| 131 |
} |
| 132 |
} |