From d2dd57bcff6a0e911ba5f8892139211eb8d15ba6 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 16 Jan 2025 23:26:37 +0200 Subject: [PATCH] feat: add game stats --- src/constants.rs | 3 +++ src/hint/mod.rs | 4 +++- src/lib.rs | 2 ++ src/screens/gameplay.rs | 8 +++++--- src/stats/components.rs | 9 +++++++++ src/stats/mod.rs | 20 +++++++++++++++++++ src/stats/resources.rs | 21 ++++++++++++++++++++ src/stats/stats.rs | 22 +++++++++++++++++++++ src/stats/systems/mod.rs | 16 ++++++++++++++++ src/stats/systems/score.rs | 39 ++++++++++++++++++++++++++++++++++++++ src/stats/systems/setup.rs | 17 +++++++++++++++++ src/theme/mod.rs | 2 +- src/theme/widgets.rs | 16 ++++++++++++++++ 13 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 src/stats/components.rs create mode 100644 src/stats/mod.rs create mode 100644 src/stats/resources.rs create mode 100644 src/stats/stats.rs create mode 100644 src/stats/systems/mod.rs create mode 100644 src/stats/systems/score.rs create mode 100644 src/stats/systems/setup.rs diff --git a/src/constants.rs b/src/constants.rs index c79e214..a31d151 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -3,3 +3,6 @@ pub const WALL_OVERLAP_MODIFIER: f32 = 1.25; pub const FLOOR_Y_OFFSET: u8 = 200; pub const MOVEMENT_COOLDOWN: f32 = 1.0; // one second cooldown pub const TITLE: &str = "Maze Ascension: The Labyrinth of Echoes"; + +pub const FLOOR_SCORE_MULTIPLIER: f32 = 100.; +pub const TIME_SCORE_MULTIPLIER: f32 = 10.0; diff --git a/src/hint/mod.rs b/src/hint/mod.rs index 371febd..08ea313 100644 --- a/src/hint/mod.rs +++ b/src/hint/mod.rs @@ -3,9 +3,11 @@ pub mod components; mod systems; use bevy::{ecs::system::RunSystemOnce, prelude::*}; +use components::IdleTimer; pub(super) fn plugin(app: &mut App) { - app.add_plugins(systems::plugin); + app.register_type::() + .add_plugins(systems::plugin); } pub fn spawn_hint_command(world: &mut World) { diff --git a/src/lib.rs b/src/lib.rs index 10921fe..e634cde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ pub mod hint; pub mod maze; pub mod player; pub mod screens; +pub mod stats; pub mod theme; use bevy::{ @@ -69,6 +70,7 @@ impl Plugin for AppPlugin { floor::plugin, player::plugin, hint::plugin, + stats::plugin, )); // Enable dev tools for dev builds. diff --git a/src/screens/gameplay.rs b/src/screens/gameplay.rs index 7374933..b41de50 100644 --- a/src/screens/gameplay.rs +++ b/src/screens/gameplay.rs @@ -1,8 +1,9 @@ //! The screen state for the main gameplay. -use crate::player::spawn_player_command; -use crate::screens::Screen; -use crate::{hint::spawn_hint_command, maze::spawn_level_command}; +use crate::{ + hint::spawn_hint_command, maze::spawn_level_command, player::spawn_player_command, + screens::Screen, stats::spawn_stats_command, +}; use bevy::{input::common_conditions::input_just_pressed, prelude::*}; @@ -13,6 +14,7 @@ pub(super) fn plugin(app: &mut App) { spawn_level_command, spawn_player_command, spawn_hint_command, + spawn_stats_command, ) .chain(), ); diff --git a/src/stats/components.rs b/src/stats/components.rs new file mode 100644 index 0000000..8aad2aa --- /dev/null +++ b/src/stats/components.rs @@ -0,0 +1,9 @@ +use bevy::prelude::*; + +#[derive(Debug, Reflect, Component, Deref, DerefMut)] +#[reflect(Component)] +pub struct Score(pub usize); + +#[derive(Debug, Reflect, Component)] +#[reflect(Component)] +pub struct StatsText; diff --git a/src/stats/mod.rs b/src/stats/mod.rs new file mode 100644 index 0000000..76c2c8a --- /dev/null +++ b/src/stats/mod.rs @@ -0,0 +1,20 @@ +pub mod components; +pub mod resources; +pub mod stats; +mod systems; + +use bevy::{ecs::system::RunSystemOnce, prelude::*}; +use components::Score; +use resources::{FloorTimer, GameTimer}; + +pub(super) fn plugin(app: &mut App) { + app.register_type::() + .init_resource::() + .init_resource::() + .insert_resource(FloorTimer(Timer::from_seconds(0.0, TimerMode::Once))) + .add_plugins(systems::plugin); +} + +pub fn spawn_stats_command(world: &mut World) { + let _ = world.run_system_once(systems::setup::setup); +} diff --git a/src/stats/resources.rs b/src/stats/resources.rs new file mode 100644 index 0000000..5c7123f --- /dev/null +++ b/src/stats/resources.rs @@ -0,0 +1,21 @@ +use bevy::prelude::*; + +#[derive(Debug, Reflect, Resource, Deref, DerefMut)] +#[reflect(Resource)] +pub struct GameTimer(pub Timer); + +#[derive(Debug, Reflect, Resource, Deref, DerefMut)] +#[reflect(Resource)] +pub struct FloorTimer(pub Timer); + +impl Default for GameTimer { + fn default() -> Self { + Self(Timer::from_seconds(0.0, TimerMode::Once)) + } +} + +impl Default for FloorTimer { + fn default() -> Self { + Self(Timer::from_seconds(0.0, TimerMode::Once)) + } +} diff --git a/src/stats/stats.rs b/src/stats/stats.rs new file mode 100644 index 0000000..95289b1 --- /dev/null +++ b/src/stats/stats.rs @@ -0,0 +1,22 @@ +use bevy::prelude::*; + +pub trait StatsContainer { + fn ui_stats(&mut self) -> EntityCommands; +} + +impl StatsContainer for Commands<'_, '_> { + fn ui_stats(&mut self) -> EntityCommands { + self.spawn(( + Name::new("Stats Root"), + Node { + position_type: PositionType::Absolute, + top: Val::Px(10.), + right: Val::Px(10.), + row_gap: Val::Px(8.), + align_items: AlignItems::End, + flex_direction: FlexDirection::Column, + ..default() + }, + )) + } +} diff --git a/src/stats/systems/mod.rs b/src/stats/systems/mod.rs new file mode 100644 index 0000000..f469cfc --- /dev/null +++ b/src/stats/systems/mod.rs @@ -0,0 +1,16 @@ +mod score; +pub mod setup; + +use bevy::prelude::*; +use score::{update_score, update_score_display}; + +use crate::screens::Screen; + +pub(super) fn plugin(app: &mut App) { + app.add_systems( + Update, + (update_score, update_score_display) + .chain() + .run_if(in_state(Screen::Gameplay)), + ); +} diff --git a/src/stats/systems/score.rs b/src/stats/systems/score.rs new file mode 100644 index 0000000..537b419 --- /dev/null +++ b/src/stats/systems/score.rs @@ -0,0 +1,39 @@ +use bevy::prelude::*; + +use crate::{ + constants::{FLOOR_SCORE_MULTIPLIER, TIME_SCORE_MULTIPLIER}, + floor::components::{CurrentFloor, Floor}, + stats::{components::Score, resources::GameTimer}, +}; + +pub fn update_score( + mut score_query: Query<&mut Score>, + mut game_timer: ResMut, + floor_query: Query<&Floor, With>, + time: Res