From a245f35332cc3de2548344a26d8b5079d2c15672 Mon Sep 17 00:00:00 2001 From: popertots Date: Thu, 22 May 2025 13:06:27 +0100 Subject: [PATCH] Refactor visibility system to use component-based approach - Introduce VisibleGameEntity component for entities needing visibility logic - Move Z-index based visibility calculations to dedicated system - Update both citizens and logs to use new visibility system - Remove duplicated visibility logic from citizen movement system - Add compute_visibility_of_game_entities system to Update phase This improves modularity by separating visibility concerns from movement systems. --- src/citizen.rs | 25 ++++-------------------- src/tilemap.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/citizen.rs b/src/citizen.rs index 313746f..a0377f7 100644 --- a/src/citizen.rs +++ b/src/citizen.rs @@ -1,7 +1,7 @@ use crate::{ constants::*, game, - tilemap::{ChunkMap, CHUNK_SIZE}, + tilemap::{ChunkMap, VisibleGameEntity, CHUNK_SIZE}, }; use bevy::{math::ivec3, prelude::*}; @@ -17,7 +17,7 @@ impl Citizen { pub fn new(asset_server: &Res, position: Vec3) -> Self { Citizen { ambulatory: Ambulatory { - walk_speed: 0., + walk_speed: 8., run_speed: 6., target: None, current_path: None, @@ -189,24 +189,6 @@ pub fn citizen_movement( } else if direction.x < 0.0 { transform.scale.x = -PIXEL_RATIO; } - if (z_index.0 - transform.translation.z / TILE_SIZE) / 8.0 > 1.0 { - *visibility = Visibility::Hidden; - } else { - if transform.translation.z / TILE_SIZE <= z_index.0 + 1.0 { - *visibility = Visibility::Visible; - let saturation = - ((z_index.0 - (transform.translation.z / TILE_SIZE) + 1.) - / 8.0) - .clamp(0.0, 1.0); - - sprite.color = - Color::hsv(194.7, saturation, 1.0 - (saturation / 2.0)); - - sprite.color.set_alpha(1.0 - saturation); - } else { - *visibility = Visibility::Hidden; - } - } // Check if we've reached the next point if transform.translation.distance(next_point) < TILE_SIZE { @@ -409,6 +391,7 @@ pub fn spawn_citizens(mut commands: Commands, asset_server: Res) { let mut position = Vec3::new(x.round(), y.round(), 35.0) * TILE_SIZE; position.z += 0.1; - commands.spawn(Citizen::new(&asset_server, position)); + let cit = commands.spawn(Citizen::new(&asset_server, position)).id(); + commands.entity(cit).insert(VisibleGameEntity); } } diff --git a/src/tilemap.rs b/src/tilemap.rs index da4b14d..ef9de0f 100644 --- a/src/tilemap.rs +++ b/src/tilemap.rs @@ -2,6 +2,7 @@ use std::sync::Mutex; use std::time::Instant; use crate::constants::{ITILE_SIZE, TILE_SIZE}; +use crate::game; use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileMap}; use crate::tiles::{ CurrentWorldSpriteState, FixtureTilePrefab, FloorTilePrefab, TerrainSpriteState, TextureIDs, @@ -365,7 +366,7 @@ fn generate_chunk_weathering_and_precipitation(// mut commands: Commands, } fn generate_chunk_forrestry( - commands: ParallelCommands<'_, '_>, // Use ParallelCommands for parallel spawning + commands: ParallelCommands<'_, '_>, mut events: EventReader, mut tilemap: ResMut, texture_ids: Res, @@ -402,10 +403,17 @@ fn generate_chunk_forrestry( image: texture.clone(), ..Default::default() }; - commands.spawn(( - sprite, - Transform::from_xyz(above_pos.x, above_pos.y, above_pos.z), - )); + let log = commands + .spawn(( + sprite, + Transform::from_xyz( + above_pos.x, + above_pos.y, + above_pos.z, + ), + )) + .id(); + commands.entity(log).insert(VisibleGameEntity); tree_positions.push(above_pos); } } @@ -475,6 +483,38 @@ pub fn absolute_z_to_world_z(z: f32) -> f32 { z - Z_BELOW * ITILE_SIZE as f32 } +#[derive(Component)] +pub struct VisibleGameEntity; + +pub fn compute_visibility_of_game_entities( + mut query: Query<(&Transform, &mut Visibility, &mut Sprite), With>, + z_index: Res, +) { + query + .par_iter_mut() + .for_each(|(transform, mut visibility, mut sprite)| { + // if too far away, saturation does not matter + if (z_index.0 - transform.translation.z / TILE_SIZE) / 8.0 > 1.0 { + *visibility = Visibility::Hidden; + return; + } + // if too high, saturation does not matter + if (transform.translation.z) / TILE_SIZE > z_index.0 + 1.0 { + *visibility = Visibility::Hidden; + return; + } + + // if visible, calculate saturation + *visibility = Visibility::Visible; + let saturation = + ((z_index.0 - (transform.translation.z / TILE_SIZE) + 1.) / 8.0).clamp(0.0, 1.0); + + sprite.color = Color::hsv(194.7, saturation, 1.0 - (saturation / 2.0)); + + sprite.color.set_alpha(1.0 - saturation); + }); +} + pub struct TilemapPlugin; impl Plugin for TilemapPlugin { @@ -503,6 +543,7 @@ impl Plugin for TilemapPlugin { ) .chain(), ) - .add_systems(FixedUpdate, generate_chunks_from_algo); + .add_systems(FixedUpdate, generate_chunks_from_algo) + .add_systems(Update, compute_visibility_of_game_entities); } }