diff --git a/assets/sky.png b/assets/sky.png index 5d4304b..81cc912 100644 Binary files a/assets/sky.png and b/assets/sky.png differ diff --git a/assets/underground.png b/assets/underground.png new file mode 100644 index 0000000..802e47d Binary files /dev/null and b/assets/underground.png differ diff --git a/src/game.rs b/src/game.rs index 5daf154..e6e4e93 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,7 +6,8 @@ use bevy::prelude::*; use noise::{NoiseFn, Perlin}; use rand::prelude::*; -pub const Z_INDEX: f32 = 0.; +#[derive(Resource)] +pub struct ZIndex(pub f32); pub fn setup_level(mut commands: Commands, asset_server: Res) { setup_tilemap(&mut commands, &asset_server); @@ -26,9 +27,9 @@ pub fn setup_level(mut commands: Commands, asset_server: Res) { fn setup_tilemap(commands: &mut Commands, asset_server: &Res) { let perlin = Perlin::new(0); - for x in -15..15 { - for y in -15..15 { - for z in -2..15 { + for x in -50..50 { + for y in -50..50 { + for z in -5..40 { let position = Vec3::new(x as f32 * TILE_SIZE, y as f32 * TILE_SIZE, -z as f32); // Generate Perlin noise value diff --git a/src/main.rs b/src/main.rs index 6d98fd5..269b272 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,17 @@ use bevy::prelude::*; -mod constants; mod camera; mod citizen; +mod constants; +mod cursor; mod game; mod item; mod tile; mod tiles; -mod cursor; fn main() { App::new() + .insert_resource(game::ZIndex(-5.0)) .add_plugins( DefaultPlugins .set(WindowPlugin { @@ -24,7 +25,7 @@ fn main() { ) .insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0))) .add_systems(Startup, (game::setup_level, camera::spawn_panning_camera)) - .add_systems(PostStartup, tile::tile_sprite_occlusion_update) + .add_systems(PostStartup, tile::tile_sprite_occlusion) .add_systems(Startup, cursor::setup_curor) .add_systems( FixedUpdate, @@ -32,6 +33,7 @@ fn main() { camera::camera_movement, citizen::citizen_movement, tile::tile_item_sprite_update, + // tile::camera_z_movement.chain(tile::tile_sprite_occlusion), ), ) .add_systems(FixedUpdate, cursor::move_cursor) diff --git a/src/tile.rs b/src/tile.rs index 58d9e0b..a793da7 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,9 +1,6 @@ use crate::item::Item; -use crate::{constants::*, game}; -use bevy::math::vec2; +use crate::game; use bevy::prelude::*; -use std::collections::HashMap; -use std::process::exit; #[derive(Component)] #[require(Sprite)] @@ -58,65 +55,93 @@ pub struct DoorTile { pub locked: bool, } -pub fn tile_sprite_occlusion_update( +// pub fn camera_z_movement( +// keyboard_input: Res>, +// mut z_index: ResMut, +// ) { +// if keyboard_input.pressed(KeyCode::ShiftLeft) { +// z_index.0 -= 1.0; +// } +// if keyboard_input.pressed(KeyCode::ShiftRight) { +// z_index.0 += 1.0; +// } +// } + +pub fn tile_sprite_occlusion( mut query: Query<(&mut Visibility, &Transform, &Tile), With>, tile_query: Query<(&Transform, &Tile)>, + z_index: ResMut, ) { - let mut z_map: HashMap<(i32, i32), i32> = HashMap::new(); + use std::collections::HashMap; - for (mut visibility, transform, tile) in query.iter_mut() { - *visibility = Visibility::Hidden; + // Build spatial lookup + let tile_map: HashMap<(i32, i32, i32), &Tile> = tile_query + .iter() + .map(|(transform, tile)| { + ( + ( + transform.translation.x.round() as i32, + transform.translation.y.round() as i32, + transform.translation.z.round() as i32, + ), + tile, + ) + }) + .collect(); - if transform.translation.z > game::Z_INDEX { - continue; - } - if let Some(z_val) = z_map.get(&( - transform.translation.x.round() as i32, - transform.translation.y.round() as i32, - )) { - if *z_val >= transform.translation.z as i32 { - continue; + query + .par_iter_mut() + .for_each(|(mut visibility, transform, _)| { + *visibility = Visibility::Hidden; + + // Early exit for above camera layer + if transform.translation.z > z_index.0 { + return; } - } - for x_offset in -1..=1 { - for y_offset in -1..=1 { - for z_offset in -1..=1 { - if x_offset == 0 && y_offset == 0 && z_offset == 0 { - continue; // don't check against itself - } - let neighbor_position = transform.translation - + Vec3::new( - x_offset as f32 * TILE_SIZE, - y_offset as f32 * TILE_SIZE, - z_offset as f32 * TILE_SIZE, - ); + let pos = ( + transform.translation.x.round() as i32, + transform.translation.y.round() as i32, + transform.translation.z.round() as i32, + ); - if let Some((_, neighbor_tile)) = - tile_query.iter().find(|(neighbor_transform, _)| { - neighbor_transform.translation == neighbor_position - }) - { - // id == 0 is sky. So if bordering a sky tile (i.e. not deep underground) - if neighbor_tile.id == 0 { - *visibility = Visibility::Visible; - // if opaque, do not look deeper on this X,Y - if tile.opaque { - z_map.insert( - ( - transform.translation.x.round() as i32, - transform.translation.y.round() as i32, - ), - transform.translation.z.round() as i32, - ); - } - break; + // Check for any opaque tiles above the current tile + for z_offset in 1..=100 { + // Adjust the max height of the check if needed + let above_pos = (pos.0, pos.1, pos.2 + z_offset); + // look up until camera height + if above_pos.2 <= z_index.0 as i32 { + // get any tiles + if let Some(neighbor_tile) = tile_map.get(&above_pos) { + // If there's an opaque tile above, hide the current tile + if neighbor_tile.opaque { + return; // No need to check further; the tile should remain hidden } } } } - } - } + + // Check all neighbors around the tile + for x_offset in -1..=1 { + for y_offset in -1..=1 { + for z_offset in -1..=1 { + if x_offset == 0 && y_offset == 0 && z_offset == 0 { + continue; + } + + let neighbor_pos = (pos.0 + x_offset, pos.1 + y_offset, pos.2 + z_offset); + + if let Some(neighbor_tile) = tile_map.get(&neighbor_pos) { + // id == 0 is sky + if neighbor_tile.id == 0 { + *visibility = Visibility::Visible; + break; + } + } + } + } + } + }); } pub fn tile_item_sprite_update( diff --git a/src/tiles.rs b/src/tiles.rs index c6ed97b..f9ec6f0 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -93,4 +93,21 @@ impl TilePrefab { }, } } + + pub fn underground(position: Vec3, asset_server: &Res) -> Self { + TilePrefab { + transform: Transform::from_translation(position).with_scale(Vec3::splat(PIXEL_RATIO)), + sprite: Sprite { + image: asset_server.load("underground.png"), + ..Default::default() + }, + tile: Tile { + id: 5, + opaque: true, + }, + tile_state: TileState { + timer: Timer::from_seconds(1.0, TimerMode::Repeating), + }, + } + } }