use std::collections::VecDeque;
use std::sync::atomic::{AtomicUsize, Ordering};
static SMOKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone, Copy)]
pub struct Particle {
pub x: i32,
pub y: i32,
pub pattern: usize,
pub kind: usize,
}
pub struct Smoke {
particles: VecDeque<Particle>,
should_generate: bool,
}
thread_local! {
static SMOKE: std::cell::RefCell<Smoke> = const {
std::cell::RefCell::new(Smoke {
particles: VecDeque::new(),
should_generate: false,
})
};
}
pub fn set_generation_gate(should_gen: bool) {
SMOKE.with(|s| {
let mut smoke = s.borrow_mut();
smoke.should_generate = should_gen;
});
}
pub fn add_smoke(x: i32, y: i32) {
SMOKE.with(|s| {
let mut smoke = s.borrow_mut();
if smoke.should_generate && smoke.particles.len() < 1000 {
let counter = SMOKE_COUNTER.fetch_add(1, Ordering::SeqCst);
let kind = counter % 2;
smoke.particles.push_back(Particle {
x,
y,
pattern: 0,
kind,
});
}
});
}
pub fn update_smoke() {
SMOKE.with(|s| {
let mut smoke = s.borrow_mut();
if !smoke.should_generate {
return;
}
for particle in &mut smoke.particles {
use crate::train::ascii::{SMOKE_DX, SMOKE_DY};
let dy = SMOKE_DY[particle.pattern];
let dx = SMOKE_DX[particle.pattern];
particle.y -= dy;
particle.x += dx;
particle.pattern += 1;
}
smoke.particles.retain(|p| p.pattern < 16);
});
}
pub fn get_smoke_particles() -> Vec<Particle> {
SMOKE.with(|s| {
let smoke = s.borrow();
smoke.particles.iter().copied().collect()
})
}
pub fn clear_smoke() {
SMOKE.with(|s| {
let mut smoke = s.borrow_mut();
smoke.particles.clear();
});
}