diff --git a/src/game.rs b/src/game.rs index 2cafdca..8c6ecf0 100644 --- a/src/game.rs +++ b/src/game.rs @@ -15,11 +15,10 @@ use crate::systems::profiling::SystemId; use crate::systems::render::RenderDirty; use crate::systems::{ audio_system, blinking_system, collision_system, debug_render_system, directional_render_system, dirty_render_system, - ghost_movement_system, hud_render_system, item_system, profile, ready_visibility_system, render_system, AudioEvent, - AudioResource, AudioState, BackbufferResource, Collider, DebugFontResource, DebugState, DebugTextureResource, DeltaTime, - DirectionalAnimated, EntityType, Frozen, Ghost, GhostBundle, GhostCollider, GlobalState, ItemBundle, ItemCollider, - MapTextureResource, PacmanCollider, PlayerBundle, PlayerControlled, PlayerStateBundle, Renderable, ScoreResource, - StartupSequence, SystemTimings, + ghost_movement_system, hud_render_system, item_system, profile, render_system, AudioEvent, AudioResource, AudioState, + BackbufferResource, Collider, DebugFontResource, DebugState, DebugTextureResource, DeltaTime, DirectionalAnimated, + EntityType, Frozen, Ghost, GhostBundle, GhostCollider, GlobalState, ItemBundle, ItemCollider, MapTextureResource, + PacmanCollider, PlayerBundle, PlayerControlled, PlayerStateBundle, Renderable, ScoreResource, StartupSequence, SystemTimings, }; use crate::texture::animated::AnimatedTexture; use bevy_ecs::event::EventRegistry; @@ -190,7 +189,6 @@ impl Game { sprite: SpriteAtlas::get_tile(&atlas, "pacman/full.png") .ok_or_else(|| GameError::Texture(TextureError::AtlasTileNotFound("pacman/full.png".to_string())))?, layer: 0, - visible: true, }, directional_animated: DirectionalAnimated { textures, @@ -282,7 +280,6 @@ impl Game { (collision_system, ghost_collision_system, item_system).chain(), audio_system, blinking_system, - ready_visibility_system, ( directional_render_system, dirty_render_system, @@ -318,11 +315,7 @@ impl Game { let mut item = world.spawn(ItemBundle { position: Position::Stopped { node: node_id }, - sprite: Renderable { - sprite, - layer: 1, - visible: true, - }, + sprite: Renderable { sprite, layer: 1 }, entity_type: item_type, collider: Collider { size }, item_collider: ItemCollider, @@ -429,7 +422,6 @@ impl Game { }, )?, layer: 0, - visible: true, }, directional_animated: DirectionalAnimated { textures, diff --git a/src/systems/blinking.rs b/src/systems/blinking.rs index d4af5f3..9623972 100644 --- a/src/systems/blinking.rs +++ b/src/systems/blinking.rs @@ -1,9 +1,14 @@ use bevy_ecs::{ component::Component, - system::{Query, Res}, + entity::Entity, + query::{Has, With}, + system::{Commands, Query, Res}, }; -use crate::systems::components::{DeltaTime, Renderable}; +use crate::systems::{ + components::{DeltaTime, Renderable}, + Hidden, +}; #[derive(Component)] pub struct Blinking { @@ -15,13 +20,23 @@ pub struct Blinking { /// /// This system manages entities that have both `Blinking` and `Renderable` components, /// accumulating time and toggling visibility when the specified interval is reached. -pub fn blinking_system(time: Res, mut query: Query<(&mut Blinking, &mut Renderable)>) { - for (mut blinking, mut renderable) in query.iter_mut() { +pub fn blinking_system( + mut commands: Commands, + time: Res, + mut query: Query<(Entity, &mut Blinking, Has), With>, +) { + for (entity, mut blinking, hidden) in query.iter_mut() { blinking.timer += time.0; if blinking.timer >= blinking.interval { blinking.timer = 0.0; - renderable.visible = !renderable.visible; + + // Add or remove the Visible component based on whether it is currently in the query + if hidden { + commands.entity(entity).remove::(); + } else { + commands.entity(entity).insert(Hidden); + } } } } diff --git a/src/systems/components.rs b/src/systems/components.rs index 238aa12..8a355a9 100644 --- a/src/systems/components.rs +++ b/src/systems/components.rs @@ -93,7 +93,6 @@ impl EntityType { pub struct Renderable { pub sprite: AtlasTile, pub layer: u8, - pub visible: bool, } /// A component for entities that have a directional animated texture. diff --git a/src/systems/render.rs b/src/systems/render.rs index 3ea3aca..dcd3e04 100644 --- a/src/systems/render.rs +++ b/src/systems/render.rs @@ -7,6 +7,7 @@ use crate::systems::{ }; use crate::texture::sprite::SpriteAtlas; use crate::texture::text::TextTexture; +use bevy_ecs::component::Component; use bevy_ecs::entity::Entity; use bevy_ecs::event::EventWriter; use bevy_ecs::query::{Changed, Or, With, Without}; @@ -21,6 +22,9 @@ use sdl2::video::Window; #[derive(Resource, Default)] pub struct RenderDirty(pub bool); +#[derive(Component)] +pub struct Hidden; + #[allow(clippy::type_complexity)] pub fn dirty_render_system( mut dirty: ResMut, @@ -71,56 +75,6 @@ pub struct MapTextureResource(pub Texture<'static>); /// A non-send resource for the backbuffer texture. This just wraps the texture with a type so it can be differentiated when exposed as a resource. pub struct BackbufferResource(pub Texture<'static>); -/// Updates entity visibility based on StartupSequence stages -pub fn ready_visibility_system( - startup: Res, - mut player_query: Query<&mut Renderable, (With, Without)>, - mut ghost_query: Query<&mut Renderable, (With, Without)>, - mut energizer_query: Query<(&mut Blinking, &EntityType)>, -) { - match *startup { - StartupSequence::TextOnly { .. } => { - // Hide player and ghosts, disable energizer blinking - if let Ok(mut renderable) = player_query.single_mut() { - renderable.visible = false; - } - - for mut renderable in ghost_query.iter_mut() { - renderable.visible = false; - } - - // Disable energizer blinking in text-only stage - for (mut blinking, entity_type) in energizer_query.iter_mut() { - if matches!(entity_type, EntityType::PowerPellet) { - blinking.timer = 0.0; // Reset timer to prevent blinking - } - } - } - StartupSequence::CharactersVisible { .. } => { - // Show player and ghosts, enable energizer blinking - if let Ok(mut renderable) = player_query.single_mut() { - renderable.visible = true; - } - - for mut renderable in ghost_query.iter_mut() { - renderable.visible = true; - } - - // Energizer blinking is handled by the blinking system - } - StartupSequence::GameActive => { - // All entities are visible and blinking is normal - if let Ok(mut renderable) = player_query.single_mut() { - renderable.visible = true; - } - - for mut renderable in ghost_query.iter_mut() { - renderable.visible = true; - } - } - } -} - /// Renders the HUD (score, lives, etc.) on top of the game. pub fn hud_render_system( mut canvas: NonSendMut<&mut Canvas>, @@ -183,7 +137,7 @@ pub fn render_system( mut atlas: NonSendMut, map: Res, dirty: Res, - renderables: Query<(Entity, &Renderable, &Position)>, + renderables: Query<(Entity, &Renderable, &Position), Without>, mut errors: EventWriter, ) { if !dirty.0 { @@ -207,10 +161,6 @@ pub fn render_system( .sort_by_key::<(Entity, &Renderable, &Position), _>(|(_, renderable, _)| renderable.layer) .rev() { - if !renderable.visible { - continue; - } - let pos = position.get_pixel_position(&map.graph); match pos { Ok(pos) => { diff --git a/src/systems/stage.rs b/src/systems/stage.rs index 0f3ece5..e0905e0 100644 --- a/src/systems/stage.rs +++ b/src/systems/stage.rs @@ -4,8 +4,9 @@ use bevy_ecs::{ resource::Resource, system::{Commands, Query, ResMut}, }; +use tracing::debug; -use crate::systems::{Frozen, GhostCollider, PlayerControlled}; +use crate::systems::{Frozen, GhostCollider, Hidden, PlayerControlled}; #[derive(Resource, Debug, Clone, Copy)] pub enum StartupSequence { @@ -75,21 +76,14 @@ pub fn startup_stage_system( mut ghost_query: Query>, ) { if let Some((from, to)) = startup.tick() { + debug!("StartupSequence transition from {from:?} to {to:?}"); match (from, to) { - (StartupSequence::TextOnly { .. }, StartupSequence::CharactersVisible { .. }) => { - // TODO: Add TextOnly tag component to hide entities - // TODO: Add CharactersVisible tag component to show entities - // TODO: Remove TextOnly tag component - } + // (StartupSequence::TextOnly { .. }, StartupSequence::CharactersVisible { .. }) => {} (StartupSequence::CharactersVisible { .. }, StartupSequence::GameActive) => { - // Remove Frozen tag from all entities and enable player input + // Remove Frozen/Hidden tags from all entities and enable player input for entity in player_query.iter_mut().chain(ghost_query.iter_mut()) { - tracing::info!("Removing Frozen component from entity {}", entity); - commands.entity(entity).remove::(); + commands.entity(entity).remove::<(Frozen, Hidden)>(); } - - // TODO: Add GameActive tag component - // TODO: Remove CharactersVisible tag component } _ => {} }