refactor led calculations
This commit is contained in:
parent
539e8ff21d
commit
67c6a76c80
37
src/bomb.rs
Normal file
37
src/bomb.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const BOMB_MAX_TIME: u64 = 40_000;
|
||||||
|
const BOMB_BLINK_DURATION: u64 = 300;
|
||||||
|
const BOMB_BLINK_SPEED: u64 = 700;
|
||||||
|
|
||||||
|
pub struct Bomb {
|
||||||
|
last_up_planted: bool,
|
||||||
|
time_bomb_planted: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bomb {
|
||||||
|
pub fn new() -> Bomb{
|
||||||
|
Bomb {
|
||||||
|
last_up_planted: false,
|
||||||
|
time_bomb_planted: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self, upstream: bool, delta_t: u64) -> u8 {
|
||||||
|
if upstream != self.last_up_planted {
|
||||||
|
// A bomb has been planted or defused reset the timer
|
||||||
|
self.time_bomb_planted = 0;
|
||||||
|
self.last_up_planted = upstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
if upstream {
|
||||||
|
self.time_bomb_planted += delta_t;
|
||||||
|
|
||||||
|
let should_blink = (self.time_bomb_planted)
|
||||||
|
% (BOMB_BLINK_SPEED * (BOMB_MAX_TIME / self.time_bomb_planted).max(1))
|
||||||
|
< BOMB_BLINK_DURATION;
|
||||||
|
|
||||||
|
return if should_blink { 255 } else { 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
12
src/curves.rs
Normal file
12
src/curves.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
pub fn qudratic_curve<T>(f64:x, f64:x2, f64: c) -> T
|
||||||
|
where T: Fn(f64) -> f64
|
||||||
|
{
|
||||||
|
return |x| x2 * x.powi(2) + x * x + c;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cubic_bezier<T>(p1: (f64,f64),p2: (f64,f64)) -> T
|
||||||
|
where T: Fn(f64) -> f64
|
||||||
|
{
|
||||||
|
return |x| (1.0 - x).powi(3) * p1.0 + 3.0 * (1.0 - x).powi(2) * x * p1.1 + 3.0 * (1.0 - x) * x.powi(2) * p2.0 + x.powi(3) * p2.1;
|
||||||
|
}
|
61
src/flash.rs
Normal file
61
src/flash.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
const FLASHED_X2: f64 = 0.00003113;
|
||||||
|
const FLASHED_X1: f64 = -0.17396053;
|
||||||
|
const FLASHED_X0: f64 = 244.51964267;
|
||||||
|
|
||||||
|
fn interpolate_flashed(time: u64) -> u8 {
|
||||||
|
if time == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let y = FLASHED_X2 * (time as f64).powi(2) + FLASHED_X1 * (time as f64) + FLASHED_X0;
|
||||||
|
|
||||||
|
return y.min(255.0).round() as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_time_from_flashed(flashed: u8) -> u64 {
|
||||||
|
let discriminant = FLASHED_X1.powi(2) - 4.0 * FLASHED_X2 * (FLASHED_X0 - flashed as f64);
|
||||||
|
|
||||||
|
let x = (-FLASHED_X1 - discriminant.sqrt()) / (2.0 * FLASHED_X2);
|
||||||
|
return x.min(5000.0) as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Flash {
|
||||||
|
last_up_flashed: u8, // Used to detect changes in upstream flashed
|
||||||
|
time_since_last_flashed: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flash {
|
||||||
|
pub fn new() -> Flash {
|
||||||
|
Flash {
|
||||||
|
last_up_flashed: 0,
|
||||||
|
time_since_last_flashed: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self, upstream: u8, delta_t: u64) -> u8 {
|
||||||
|
// Count the time since the flash started to fade
|
||||||
|
if upstream > 0 && upstream < 255 {
|
||||||
|
self.time_since_last_flashed += delta_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if upstream == self.last_up_flashed {
|
||||||
|
// Upstream value hasn't changed
|
||||||
|
|
||||||
|
if upstream == 255 {
|
||||||
|
// Flash is at max
|
||||||
|
return 255;
|
||||||
|
} else if upstream == 0 {
|
||||||
|
// Flash is off
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// Flash is fading
|
||||||
|
return interpolate_flashed(self.time_since_last_flashed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upstream value has changed
|
||||||
|
self.time_since_last_flashed = resolve_time_from_flashed(upstream);
|
||||||
|
self.last_up_flashed = upstream;
|
||||||
|
return upstream;
|
||||||
|
}
|
||||||
|
}
|
105
src/led.rs
105
src/led.rs
@ -1,4 +1,4 @@
|
|||||||
use super::state::State;
|
use super::{flash::Flash, bomb::Bomb,state::State};
|
||||||
use std::{sync::atomic::Ordering, thread};
|
use std::{sync::atomic::Ordering, thread};
|
||||||
|
|
||||||
fn build_led_package(len: u32, color: (u8, u8, u8)) -> Vec<u8> {
|
fn build_led_package(len: u32, color: (u8, u8, u8)) -> Vec<u8> {
|
||||||
@ -15,109 +15,28 @@ fn build_led_package(len: u32, color: (u8, u8, u8)) -> Vec<u8> {
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FLASHED_X2: f64 = 0.00003113;
|
pub fn led_loop(fps: u32, addr: &str, len: u32, state: State) -> ! {
|
||||||
const FLASHED_X1: f64 = -0.17396053;
|
|
||||||
const FLASHED_X0: f64 = 244.51964267;
|
|
||||||
|
|
||||||
const BOMB_MAX_TIME: u64 = 40_000;
|
|
||||||
const BOMB_BLINK_DURATION: u64 = 300;
|
|
||||||
const BOMB_BLINK_SPEED: u64 = 700;
|
|
||||||
|
|
||||||
fn interpolate_flashed(time: u64) -> u8 {
|
|
||||||
if time == 0 {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let y = FLASHED_X2 * (time as f64).powi(2) + FLASHED_X1 * (time as f64) + FLASHED_X0;
|
|
||||||
|
|
||||||
return y.min(255.0).round() as u8;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_time_from_flashed(flashed: u8) -> u64 {
|
|
||||||
let discriminant = FLASHED_X1.powi(2) - 4.0 * FLASHED_X2 * (FLASHED_X0 - flashed as f64);
|
|
||||||
|
|
||||||
let x = (-FLASHED_X1 - discriminant.sqrt()) / (2.0 * FLASHED_X2);
|
|
||||||
return x.min(5000.0) as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn led_loop(fps: u32, addr: &str, len: u32, state: State) {
|
|
||||||
let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap();
|
let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
let sleep_time: u64 = (1000 / fps).into();
|
let sleep_time: u64 = (1000 / fps).into();
|
||||||
|
|
||||||
let mut last_up_flashed: u8 = 0; // Used to detect changes in upstream flashed
|
let mut flash = Flash::new();
|
||||||
let mut interpolated_flashed: u8;
|
let mut bomb = Bomb::new();
|
||||||
let mut time_since_last_flashed: u64 = 0;
|
|
||||||
|
|
||||||
let mut last_up_planted: bool = false;
|
|
||||||
let mut time_bomb_planted: u64 = 0;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
thread::sleep(std::time::Duration::from_millis(sleep_time));
|
thread::sleep(std::time::Duration::from_millis(sleep_time));
|
||||||
|
|
||||||
let upstream_flashed = u8::try_from(state.flashed.load(Ordering::Relaxed)).unwrap_or(0);
|
let upstream_flashed = u8::try_from(state.flashed.load(Ordering::Relaxed)).unwrap_or(0);
|
||||||
|
let interpolated_flashed = flash.tick(upstream_flashed, sleep_time);
|
||||||
|
|
||||||
// Count the time since the flash started to fade
|
let planted = state.bomb_planted.load(Ordering::Relaxed);
|
||||||
if upstream_flashed > 0 && upstream_flashed < 255 {
|
// let planted = true;
|
||||||
time_since_last_flashed += sleep_time;
|
let bomb_blink = bomb.tick(planted, sleep_time);
|
||||||
}
|
|
||||||
|
|
||||||
if upstream_flashed == last_up_flashed {
|
// Merge flashed and bomb blink
|
||||||
// Upstream value hasn't changed
|
let color = (interpolated_flashed.max(bomb_blink), interpolated_flashed, interpolated_flashed);
|
||||||
|
|
||||||
if upstream_flashed == 255 {
|
let packet = build_led_package(len, color);
|
||||||
// Flash is at max
|
|
||||||
interpolated_flashed = 255;
|
|
||||||
} else if upstream_flashed == 0 {
|
|
||||||
// Flash is off
|
|
||||||
interpolated_flashed = 0;
|
|
||||||
} else {
|
|
||||||
// Flash is fading
|
|
||||||
interpolated_flashed = interpolate_flashed(time_since_last_flashed);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Upstream value has changed
|
|
||||||
|
|
||||||
time_since_last_flashed = resolve_time_from_flashed(upstream_flashed);
|
|
||||||
interpolated_flashed = upstream_flashed;
|
|
||||||
last_up_flashed = upstream_flashed;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pack = build_led_package(
|
|
||||||
len,
|
|
||||||
(
|
|
||||||
interpolated_flashed,
|
|
||||||
interpolated_flashed,
|
|
||||||
interpolated_flashed,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
socket.send_to(&pack, addr).unwrap();
|
|
||||||
|
|
||||||
// let planted = state.bomb_planted.load(Ordering::Relaxed);
|
|
||||||
let planted = true;
|
|
||||||
|
|
||||||
|
|
||||||
if planted != last_up_planted {
|
|
||||||
// A bomb has been planted or defused reset the timer
|
|
||||||
time_bomb_planted = 0;
|
|
||||||
last_up_planted = planted;
|
|
||||||
}
|
|
||||||
|
|
||||||
if planted {
|
|
||||||
time_bomb_planted += sleep_time;
|
|
||||||
|
|
||||||
println!("Time: {}", time_bomb_planted);
|
|
||||||
|
|
||||||
let should_blink = (time_bomb_planted) % (BOMB_BLINK_SPEED * (BOMB_MAX_TIME / time_bomb_planted).max(1)) < BOMB_BLINK_DURATION;
|
|
||||||
|
|
||||||
let color = if should_blink {
|
|
||||||
(255, 0, 0)
|
|
||||||
} else {
|
|
||||||
(0, 0, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
let pack = build_led_package(len, color);
|
|
||||||
socket.send_to(&pack, addr).unwrap();
|
|
||||||
|
|
||||||
}
|
socket.send_to(&packet, addr).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ use std::thread;
|
|||||||
mod gamestate;
|
mod gamestate;
|
||||||
mod led;
|
mod led;
|
||||||
mod state;
|
mod state;
|
||||||
|
mod flash;
|
||||||
|
mod bomb;
|
||||||
|
|
||||||
#[post("/gsi", data = "<data>")]
|
#[post("/gsi", data = "<data>")]
|
||||||
fn gsi(data: Json<gamestate::GamestateData>, gobal_state: &rocket::State<state::State>) -> Value {
|
fn gsi(data: Json<gamestate::GamestateData>, gobal_state: &rocket::State<state::State>) -> Value {
|
||||||
|
Loading…
Reference in New Issue
Block a user