From 0b05e56e4be1fafe1f763305860e6b9d42cf7845 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Thu, 21 Aug 2025 11:23:28 -0700 Subject: [PATCH] Logo, misc cleanup for shipping --- assets/flappy/logo.png | 3 + assets/flappy/logo.xcf | 3 + examples/parallax.rs | 16 ++- flake.lock | 6 +- flake.nix | 2 + justfile | 11 +- src/bin/flappy/main.rs | 226 ++++++++++++++++++++++++++++++++--------- src/debug.rs | 30 +++++- src/parallax.rs | 18 +++- src/ui.rs | 14 +-- 10 files changed, 256 insertions(+), 73 deletions(-) create mode 100644 assets/flappy/logo.png create mode 100644 assets/flappy/logo.xcf diff --git a/assets/flappy/logo.png b/assets/flappy/logo.png new file mode 100644 index 0000000..8aab91a --- /dev/null +++ b/assets/flappy/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f93fefb3f7b1dd2a4409b43ef28a4bada2600e15447b0e75fd97cce543f2797 +size 2583 diff --git a/assets/flappy/logo.xcf b/assets/flappy/logo.xcf new file mode 100644 index 0000000..21f68b9 --- /dev/null +++ b/assets/flappy/logo.xcf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ada3067998072f6fb8ed61f46047c272afa0628715810eacc73719c4d4bafe55 +size 13599 diff --git a/examples/parallax.rs b/examples/parallax.rs index eaefa9a..8f1f6df 100644 --- a/examples/parallax.rs +++ b/examples/parallax.rs @@ -20,7 +20,9 @@ fn spawn_background( ) { commands.spawn(( Name::new("Depth: 1.0"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, 0.0)).with_scale(Vec3::splat(50.0)), + Transform::default() + .with_translation(Vec3::new(0.0, 0.0, 0.0)) + .with_scale(Vec3::splat(50.0)), Mesh2d(meshes.add(Circle::new(1.0))), MeshMaterial2d(materials.add(ColorMaterial { texture: Some(server.load("bevy.png")), @@ -32,7 +34,9 @@ fn spawn_background( )); commands.spawn(( Name::new("Depth: 2.0"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, -1.0)).with_scale(Vec3::splat(25.0)), + Transform::default() + .with_translation(Vec3::new(0.0, 0.0, -1.0)) + .with_scale(Vec3::splat(25.0)), Mesh2d(meshes.add(Circle::new(2.0))), MeshMaterial2d(materials.add(ColorMaterial { texture: Some(server.load("bevy.png")), @@ -44,7 +48,9 @@ fn spawn_background( )); commands.spawn(( Name::new("Depth: 4.0"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, -2.0)).with_scale(Vec3::splat(12.5)), + Transform::default() + .with_translation(Vec3::new(0.0, 0.0, -2.0)) + .with_scale(Vec3::splat(12.5)), Mesh2d(meshes.add(Circle::new(4.0))), MeshMaterial2d(materials.add(ColorMaterial { texture: Some(server.load("bevy.png")), @@ -56,7 +62,9 @@ fn spawn_background( )); commands.spawn(( Name::new("Depth: 8.0"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, -3.0)).with_scale(Vec3::splat(6.25)), + Transform::default() + .with_translation(Vec3::new(0.0, 0.0, -3.0)) + .with_scale(Vec3::splat(6.25)), Mesh2d(meshes.add(Circle::new(8.0))), MeshMaterial2d(materials.add(ColorMaterial { texture: Some(server.load("bevy.png")), diff --git a/flake.lock b/flake.lock index adf40ff..013dd56 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1752480373, - "narHash": "sha256-JHQbm+OcGp32wAsXTE/FLYGNpb+4GLi5oTvCxwSoBOA=", + "lastModified": 1755615617, + "narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "62e0f05ede1da0d54515d4ea8ce9c733f12d9f08", + "rev": "20075955deac2583bb12f07151c2df830ef346b4", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a80c25e..3e060ef 100644 --- a/flake.nix +++ b/flake.nix @@ -51,6 +51,8 @@ git-bug # wasm builder wasm-bindgen-cli_0_2_100 + # wasm-opt + binaryen simple-http-server # Itch.io uploads butler diff --git a/justfile b/justfile index 774f363..0f7db68 100644 --- a/justfile +++ b/justfile @@ -6,13 +6,18 @@ web GAME: mkdir -p dist/{{GAME}}/assets/{{GAME}} # wasm binary - cargo build --bin {{GAME}} --release --target wasm32-unknown-unknown + cargo build --bin {{GAME}} --profile wasm-release --target wasm32-unknown-unknown + + # Size pass + wasm-opt -Oz \ + -o dist/{{GAME}}.wasm \ + ${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/{{GAME}}.wasm # wasm bindgen wasm-bindgen --no-typescript --target web \ --out-dir ./dist/{{GAME}} \ --out-name "bin" \ - ${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/{{GAME}}.wasm + dist/{{GAME}}.wasm # index.html cp ./web/{{GAME}}.html ./dist/{{GAME}}/index.html @@ -26,7 +31,7 @@ serve GAME: (web GAME) simple-http-server dist/{{GAME}} itchio GAME: (web GAME) - butler push dist/{{GAME}} popgame/{{GAME}}:html5 --userversion={{VERSION}} + butler push --dry-run dist/{{GAME}} popgame/{{GAME}}:html5 --userversion={{VERSION}} clean: rm -rf dist/* diff --git a/src/bin/flappy/main.rs b/src/bin/flappy/main.rs index 36493bd..811d0dd 100644 --- a/src/bin/flappy/main.rs +++ b/src/bin/flappy/main.rs @@ -6,6 +6,7 @@ use bevy::render::view::ColorGrading; use games::physics2d::*; use games::*; use std::hash::BuildHasher; +use std::time::Instant; fn main() { App::new() @@ -26,6 +27,7 @@ fn main() { .init_resource::() .init_resource::() .init_resource::() + .init_resource::() .init_state::() .add_systems( Startup, @@ -39,8 +41,11 @@ fn main() { tweak_camera.after(create_camera_2d), ), ) - .add_systems(OnEnter(PlayerState::Alive), alive_bird) - .add_systems(OnEnter(PlayerState::Alive), reset_button::) + .add_systems( + OnEnter(PlayerState::Alive), + (alive_bird, start_run, reset_button::), + ) + .add_systems(OnExit(PlayerState::Alive), end_run) .add_systems(OnEnter(PlayerState::Rewind), alive_bird) .add_systems(OnEnter(PlayerState::Pause), pause_bird) .add_systems(OnEnter(PlayerState::Stasis), pause_bird) @@ -84,8 +89,9 @@ fn main() { // Stats that get synced to the UI ( sync_resource_to_ui::.run_if(resource_changed::), - sync_resource_to_ui::.run_if(resource_changed::), + sync_resource_to_ui::.run_if(resource_changed::), sync_resource_to_ui::.run_if(resource_changed::), + sync_resource_to_ui::.run_if(resource_changed::), sync_resource_to_ui::.run_if(resource_changed::), ), (update_tooltip, debug_trail).run_if(in_state(DebuggingState::On)), @@ -346,29 +352,28 @@ fn move_pipe( rand: Res, ) { if let Ok((Batch(id), pipe, mut pipe_t)) = pipes.get_mut(trigger.target()) { - *pipe_t = { - let offset = { - let val = rand.0.hash_one(id); - - let option = val % 3; + *pipe_t = + { + let offset = { + let val = rand.0.hash_one(id); + + let option = val % 3; + + match option { + 0 => 100.0, + 1 => 0.0, + 2 => -100.0, + _ => panic!("Can only pick 1 of 3 pipe offsets"), + } + }; - match option { - 0 => 100.0, - 1 => 0.0, - 2 => -100.0, - _ => panic!("Can only pick 1 of 3 pipe offsets"), + match pipe { + Pipe::Top => Transform::from_xyz(0.0, 300.0 + offset, -2.0) + .with_scale(Vec3::splat(100.0)), + Pipe::Bottom => Transform::from_xyz(0.0, -300.0 + offset, -2.0) + .with_scale(Vec3::splat(100.0)), } }; - - match pipe { - Pipe::Top => { - Transform::from_xyz(0.0, 300.0 + offset, -2.0).with_scale(Vec3::splat(100.0)) - } - Pipe::Bottom => { - Transform::from_xyz(0.0, -300.0 + offset, -2.0).with_scale(Vec3::splat(100.0)) - } - } - }; } } @@ -407,7 +412,7 @@ fn populate_pipe( }; commands.entity(trigger.target()).insert(( - pipe_t, + pipe_t, pipe_assets.material.clone(), pipe_assets.mesh.clone(), RigidBody::Static, @@ -508,35 +513,50 @@ fn init_ui(mut commands: Commands, server: Res) { flex_direction: FlexDirection::Column, ..default() }, + BorderRadius::all(Val::Px(5.0)), + BackgroundColor(Color::WHITE), + BorderColor(BLACK.into()), PlayerState::Stasis, )) .with_children(|parent| { parent.spawn(( Text::new("Game Over...?"), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )); parent.spawn(( SyncResource::::default(), Text::default(), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )); parent.spawn(( - SyncResource::::default(), + SyncResource::::default(), Text::default(), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )); parent.spawn(( - SyncResource::::default(), + SyncResource::::default(), Text::default(), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )); parent.spawn(( - SyncResource::::default(), + SyncResource::::default(), Text::default(), + TextColor(BLACK.into()), + TextLayout::new_with_justify(JustifyText::Center), + )); + parent.spawn(( + SyncResource::::default(), + Text::default(), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )); parent.spawn(( Text::new("Press R to Rewind"), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )); parent @@ -564,12 +584,20 @@ fn init_ui(mut commands: Commands, server: Res) { parent .spawn(( Button, + BorderRadius::all(Val::Px(5.0)), + BorderColor(BLACK.into()), Node { ..default() }, - children![Text::new("Credits")], + children![(TextColor(BLACK.into()), Text::new("Credits")),], )) .observe(show_credits); parent - .spawn((Button, Node { ..default() }, children![Text::new("Quit"),])) + .spawn(( + BorderRadius::all(Val::Px(5.0)), + BorderColor(BLACK.into()), + Button, + Node { ..default() }, + children![(Text::new("Quit"), TextColor(BLACK.into()))], + )) .observe(quit_game); }); }); @@ -588,9 +616,13 @@ fn init_ui(mut commands: Commands, server: Res) { flex_direction: FlexDirection::Column, ..default() }, + BorderRadius::all(Val::Px(5.0)), + BackgroundColor(WHITE.into()), + BorderColor(BLACK.into()), PlayerState::Credits, children![( Text::new(credits_str), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center) )], )) @@ -600,33 +632,66 @@ fn init_ui(mut commands: Commands, server: Res) { align_self: AlignSelf::Center, ..default() }, + BorderRadius::all(Val::Px(5.0)), + BorderColor(BLACK.into()), Button, - children![Text::new("Close")], + children![(Text::new("Close"), TextColor(BLACK.into()))], )); }) .observe(hide_credits); + let logo = + server.load_with_settings("flappy/logo.png", |settings: &mut ImageLoaderSettings| { + // Need to use nearest filtering to avoid bleeding between the slices with tiling + settings.sampler = ImageSampler::nearest(); + }); commands.spawn(( Node { align_self: AlignSelf::Center, justify_self: JustifySelf::Center, flex_direction: FlexDirection::Column, + align_items: AlignItems::Center, + justify_items: JustifyItems::Center, ..default() }, + BackgroundColor(Color::NONE), PlayerState::Pause, - Text::new("PAUSED"), + children![ + ( + ImageNode { + image: logo, + ..default() + }, + Node { + width: Val::Px(256.0), + ..default() + } + ), + ( + Node { + margin: UiRect::all(Val::Px(5.0)), + ..default() + }, + BorderRadius::all(Val::Px(5.0)), + BorderColor(BLACK.into()), + Text::new("(paused)"), + TextColor(BLACK.into()), + ) + ], )); commands - .spawn(Node { - align_self: AlignSelf::End, - justify_self: JustifySelf::Center, - flex_direction: FlexDirection::Row, - justify_content: JustifyContent::SpaceEvenly, - width: Val::Percent(100.0), - min_height: Val::Percent(10.0), - ..default() - }) + .spawn(( + Node { + align_self: AlignSelf::End, + justify_self: JustifySelf::Center, + flex_direction: FlexDirection::Row, + justify_content: JustifyContent::SpaceEvenly, + width: Val::Percent(100.0), + min_height: Val::Percent(10.0), + ..default() + }, + )) .with_children(|parent| { let rewind_image = server.load_with_settings( "flappy/rewind.png", @@ -644,8 +709,10 @@ fn init_ui(mut commands: Commands, server: Res) { justify_content: JustifyContent::Center, ..default() }, + BorderRadius::all(Val::Px(5.0)), + BorderColor(BLACK.into()), + BackgroundColor(Color::WHITE.with_alpha(0.9)), Button, - BackgroundColor::default(), RewindButton, children![ ( @@ -660,7 +727,8 @@ fn init_ui(mut commands: Commands, server: Res) { }, ), ( - Text::new("Rewind! (R)"), + Text::new("Rewind!\n(Hold R)"), + TextColor(BLACK.into()), TextFont::from_font_size(30.0), TextLayout::new_with_justify(JustifyText::Center) ), @@ -684,11 +752,15 @@ fn init_ui(mut commands: Commands, server: Res) { justify_content: JustifyContent::Center, ..default() }, + BorderRadius::all(Val::Px(5.0)), + BorderColor(BLACK.into()), + BackgroundColor(Color::WHITE.with_alpha(0.9)), Button, FlapButton, children![ ( - Text::new("Flap! (Spacebar)"), + Text::new("Flap!\n(Spacebar)"), + TextColor(BLACK.into()), TextFont::from_font_size(30.0), TextLayout::new_with_justify(JustifyText::Center) ), @@ -714,10 +786,13 @@ fn init_ui(mut commands: Commands, server: Res) { justify_self: JustifySelf::Center, ..default() }, - BackgroundColor(WHITE.into()), + BorderRadius::all(Val::Px(5.0)), + BackgroundColor(Color::WHITE), + BorderColor(BLACK.into()), children![( SyncResource::::default(), Text::default(), + TextColor(BLACK.into()), TextLayout::new_with_justify(JustifyText::Center), )], )); @@ -993,6 +1068,61 @@ impl Display for Flaps { } } +/// Track the longest run a player has done +/// Store the latest run and upsert latest run to the longest run if it is longer +#[derive(Resource, Default)] +struct LongestRun { + /// Longest run start + start: Option, + /// Longest run end + end: Option, + /// Latest run start + latest_start: Option, + /// Latest run start + latest_end: Option, +} + +impl Display for LongestRun { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match (self.start, self.end) { + (Some(a), Some(b)) => { + if b > a { + writeln!(f, "Longest Run: {:.2?}", b - a) + } else { + writeln!(f, "Longest Run: ???") + } + } + _ => writeln!(f, "Longest Run: ???"), + } + } +} + +fn start_run(mut longest_run: ResMut) { + longest_run.latest_start = Some(Instant::now()); + longest_run.latest_end = None; +} + +fn end_run(mut longest_run: ResMut) { + longest_run.latest_end = Some(Instant::now()); + + match (longest_run.start, longest_run.end) { + // Longest run hasn't been set yet, so set it to the latest run + (None, None) => { + longest_run.start = longest_run.latest_start; + longest_run.end = longest_run.latest_end; + } + // Longest run was previously set + (Some(start), Some(end)) => { + // Check if latest run is longer than current longest run + if longest_run.latest_end.unwrap() - longest_run.latest_start.unwrap() > end - start { + longest_run.start = longest_run.latest_start; + longest_run.end = longest_run.latest_end; + } + } + _ => panic!("What?"), + } +} + // Track number of times player died #[derive(Resource, Default)] struct Deaths(usize); @@ -1142,10 +1272,10 @@ fn debug_trail( fn shimmer_button(mut bg: Single<&mut BackgroundColor, With>, time: Res