From fe4543ae41cca9163812312a0fccc4fce0ae8c61 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 5 Jul 2025 13:36:21 +0200 Subject: [PATCH] progress bars --- src/bar.rs | 46 ++++++++++----- src/game.rs | 95 ++++++++++++++++++++++++++++++ src/game_state.rs | 39 ------------ src/label.rs | 3 +- src/main.rs | 27 +++++---- src/{command_queue.rs => queue.rs} | 0 6 files changed, 142 insertions(+), 68 deletions(-) create mode 100644 src/game.rs delete mode 100644 src/game_state.rs rename src/{command_queue.rs => queue.rs} (100%) diff --git a/src/bar.rs b/src/bar.rs index 4ac2a71..ad38bd2 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -1,4 +1,4 @@ -use crate::command_queue::PacketQueue; +use crate::queue::PacketQueue; use crate::{Currency, GenerateCommands, Progressable}; use servicepoint::{Bitmap, BitmapCommand, Grid, Origin, TILE_SIZE, TILE_WIDTH, Tiles}; use std::time::Duration; @@ -13,15 +13,26 @@ pub struct Bar { } impl Bar { - pub(crate) fn new(factor: f64, origin: Origin) -> Bar { + pub(crate) fn new(factor: f64, origin: Origin) -> Self { Self { factor, progress: 0f64, - speed: 0.01f64, + speed: 0f64, origin, width_tiles: TILE_WIDTH / 2, // TODO: param } } + + pub(crate) fn add_speed(&self, speed: f64) -> Self { + Self { + speed: self.speed + speed, + ..*self + } + } + + pub(crate) fn is_enabled(&self) -> bool { + self.speed > 0.0 + } } impl Progressable for Bar { @@ -40,25 +51,30 @@ impl GenerateCommands for Bar { fn generate_commands(&self, q: &mut impl PacketQueue) { let mut bitmap = Bitmap::new(self.width_tiles * TILE_SIZE, TILE_SIZE).unwrap(); - // border top - let last_row = bitmap.height() - 1; - for x in 0..bitmap.width() { - bitmap.set(x, 0, true); + let margin = 1; + let bar_height = bitmap.height() - 2 * margin; + let bar_width = bitmap.width() - 2 * margin; + let border_thickness = 1; + + // border top + bottom + let last_row = bitmap.height() - margin - border_thickness; + for x in margin..bar_width { + bitmap.set(x, margin, true); bitmap.set(x, last_row, true); } - // border bottom - let last_col = bitmap.width() - 1; - for y in 0..bitmap.height() { - bitmap.set(0, y, true); + // border left + right + let last_col = bitmap.width() - margin - border_thickness; + for y in 1..=bar_height { + bitmap.set(1, y, true); bitmap.set(last_col, y, true); } // progress fill - let fill_to = (bitmap.width() as f64 * self.progress) as usize; - for y in 0..bitmap.height() { - for x in 0..fill_to { - bitmap.set(x, y, true); + let fill_to = ((bar_width - 2) as f64 * self.progress) as usize; + for y in 2..bar_height { + for x in 2..=fill_to { + bitmap.set(x, y, (x + y) % 2 == 0); } } diff --git a/src/game.rs b/src/game.rs new file mode 100644 index 0000000..2656885 --- /dev/null +++ b/src/game.rs @@ -0,0 +1,95 @@ +use crate::bar::Bar; +use crate::queue::PacketQueue; +use crate::label::Label; +use crate::{Currency, GenerateCommands, Progressable}; +use servicepoint::{Origin, TILE_WIDTH}; +use std::time::Duration; + +const STEP_COUNT: usize = 11; + +#[derive(Debug, Clone)] +pub struct Game { + pub(crate) currency: Currency, + pub(crate) bars: [Bar; STEP_COUNT], + pub(crate) names: [&'static str; STEP_COUNT], +} + +impl Game { + pub fn new() -> Self { + Self { + currency: 0f64, + bars: [ + Bar::new(1f64, Origin::new(0, 1)).add_speed(1.0), + Bar::new(2f64, Origin::new(0, 2)).add_speed(0.5), + Bar::new(4f64, Origin::new(0, 3)).add_speed(0.25), + Bar::new(8f64, Origin::new(0, 4)).add_speed(0.125), + Bar::new(16f64, Origin::new(0, 5)).add_speed(0.0625), + Bar::new(32f64, Origin::new(0, 6)).add_speed(0.03125), + Bar::new(64f64, Origin::new(0, 7)).add_speed(0.015625), + Bar::new(128f64, Origin::new(0, 8)).add_speed(0.0078125), + Bar::new(256f64, Origin::new(0, 9)).add_speed(0.00390625), + Bar::new(512f64, Origin::new(0, 10)).add_speed(0.001953125), + Bar::new(1024f64, Origin::new(0, 11)).add_speed(0.000976562), + ], + names: [ + "Powering infrastructure", + "Dusting ServicePoint", + "Activating colorful lights", + "Dimming darkroom", + "Refilling Matemat", + "Pre-heating convectiomat", + "Resetting chair heights", + "Cleaning 'block chain'", + "Refilling sticker box", + "Setting room to public", + "Welcoming creatures", + ], + } + } +} + +impl Progressable for Game { + fn progress(&self, delta: Duration) -> (Self, Currency) { + let mut currency = self.currency; + let bars = self.bars.clone().map(|bar| { + let (bar, curr) = bar.progress(delta); + currency += curr; + bar + }); + + ( + Self { + currency, + bars, + names: self.names, + }, + 0f64, + ) + } +} + +impl GenerateCommands for Game { + fn generate_commands(&self, queue: &mut impl PacketQueue) { + Label::new(Origin::ZERO, TILE_WIDTH / 2, "Discordia Boot Procedure") + .generate_commands(queue); + Label::new( + Origin::new(TILE_WIDTH / 2 + 1, 0), + TILE_WIDTH / 2, + format!("Cycles: {}", self.currency.floor()), + ) + .generate_commands(queue); + + for (index, bar) in self.bars.iter().enumerate() { + if !bar.is_enabled() { + continue; + } + bar.generate_commands(queue); + Label::new( + Origin::new(TILE_WIDTH / 2 + 1, 1 + index), + TILE_WIDTH / 2 - 1, + self.names[index], + ) + .generate_commands(queue); + } + } +} diff --git a/src/game_state.rs b/src/game_state.rs deleted file mode 100644 index ce8e457..0000000 --- a/src/game_state.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::bar::Bar; -use crate::command_queue::PacketQueue; -use crate::label::Label; -use crate::{Currency, GenerateCommands, Progressable}; -use servicepoint::{Origin, TILE_WIDTH}; -use std::time::Duration; - -#[derive(Debug, Clone)] -pub struct GameState { - pub(crate) currency: Currency, - pub(crate) first_step: Bar, -} - -impl Progressable for GameState { - fn progress(&self, delta: Duration) -> (Self, Currency) { - let (first_step, first_currency) = self.first_step.progress(delta); - - let currency = self.currency + first_currency; - - ( - Self { - currency, - first_step, - }, - 0f64, - ) - } -} - -impl GenerateCommands for GameState { - fn generate_commands(&self, queue: &mut impl PacketQueue) { - Label::new(Origin::ZERO, TILE_WIDTH, "Discordia Boot Procedure").generate_commands(queue); - - self.first_step.generate_commands(queue); - Label::new(Origin::new(TILE_WIDTH / 2 + 1, 1), TILE_WIDTH / 2 - 1, "Power infrastructure") - .generate_commands(queue); - - } -} diff --git a/src/label.rs b/src/label.rs index 8e32f0f..0cd51f4 100644 --- a/src/label.rs +++ b/src/label.rs @@ -1,7 +1,8 @@ use crate::GenerateCommands; -use crate::command_queue::PacketQueue; +use crate::queue::PacketQueue; use servicepoint::{CharGrid, CharGridCommand, Origin, Tiles}; +#[derive(Debug, Clone)] pub(crate) struct Label> { position: Origin, text: S, diff --git a/src/main.rs b/src/main.rs index 06740f9..44d0af6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,13 @@ -use crate::command_queue::PacketQueue; -use bar::Bar; -use game_state::GameState; -use servicepoint::{ClearCommand, Origin, UdpSocketExt}; +use crate::queue::PacketQueue; +use game::Game; +use servicepoint::{ClearCommand, UdpSocketExt, FRAME_PACING}; use std::net::UdpSocket; +use std::thread::sleep; use std::time::{Duration, Instant}; mod bar; -mod command_queue; -mod game_state; +mod queue; +mod game; mod label; type Currency = f64; @@ -21,13 +21,13 @@ trait GenerateCommands { fn generate_commands(&self, queue: &mut impl PacketQueue); } -fn main() { - let mut state = GameState { - currency: 0f64, - first_step: Bar::new(1f64, Origin::new(0, 1)), - }; +const DESTINATION: &str = "127.0.0.1:2342"; +//const DESTINATION: &str = "172.23.42.29:2342"; - let mut connection = UdpSocket::bind_connect("127.0.0.1:2342").unwrap(); +fn main() { + let mut state = Game::new(); + let mut connection = UdpSocket::bind_connect(DESTINATION).unwrap(); + connection.send_command(ClearCommand); let mut last_refresh = Instant::now(); loop { @@ -37,7 +37,8 @@ fn main() { (state, _) = state.progress(delta); - connection.send_command(ClearCommand); state.generate_commands(&mut connection); + + sleep(FRAME_PACING); } } diff --git a/src/command_queue.rs b/src/queue.rs similarity index 100% rename from src/command_queue.rs rename to src/queue.rs