use crate::constants::TILE_SIZE; use crate::game; use crate::item::Item; use bevy::ecs::system::ParamSet; use bevy::prelude::*; use std::collections::HashMap; #[derive(Component, Clone)] #[require(Sprite)] pub struct FloorTile { pub id: u32, pub opaque: bool, pub walkable: bool, pub astar_weight: u8, pub visible_range: [u32; 8], } impl Default for FloorTile { fn default() -> Self { Self { id: 0, opaque: true, walkable: true, astar_weight: 0, visible_range: [0; 8], } } } #[derive(Component, Clone)] pub struct FixtureTile { pub id: u32, pub solid: bool, pub visible_range: [u32; 8], } impl Default for FixtureTile { fn default() -> Self { Self { id: 0, solid: true, visible_range: [0; 8], } } } #[derive(Component, Clone)] pub struct ConnectedTexture { } #[derive(Resource, Default)] pub struct CameraMoved(pub bool); // Modify camera_z_movement pub fn camera_z_movement( keyboard_input: Res>, mut z_index: ResMut, mut camera_moved: ResMut, ) { camera_moved.0 = false; if keyboard_input.just_pressed(KeyCode::ShiftLeft) { z_index.0 -= 1.0; z_index.0 = z_index.0.clamp(-149.0, 5.0); camera_moved.0 = true; println!("z_index = {}", z_index.0); } if keyboard_input.just_pressed(KeyCode::ShiftRight) { z_index.0 += 1.0; z_index.0 = z_index.0.clamp(-149.0, 5.0); camera_moved.0 = true; println!("z_index = {}", z_index.0); } } pub fn tile_sprite_generate_occlusion_map( mut query_set: ParamSet<( Query<(&Transform, &FloorTile)>, Query<(&Transform, &FixtureTile)>, Query<(&mut FloorTile, &Transform)>, Query<(&mut FixtureTile, &Transform)>, )>, ) { // Create the tile map using floor query let floor_tile_map: HashMap<(i32, i32, i32), (bool, u32)> = { let mut map = HashMap::new(); query_set.p0().iter().for_each(|(transform, tile)| { map.insert( ( transform.translation.x as i32, transform.translation.y as i32, transform.translation.z as i32, ), (tile.opaque, tile.id), ); }); map }; // Create the tile map using fixture query let fixture_tile_map: HashMap<(i32, i32, i32), (bool, u32)> = { let mut map = HashMap::new(); query_set.p1().iter().for_each(|(transform, tile)| { map.insert( ( transform.translation.x as i32, transform.translation.y as i32, transform.translation.z as i32, ), (tile.solid, tile.id), ); }); map }; let tile_size = TILE_SIZE as i32; // Helper function to calculate visibility let calculate_visibility = |pos: (i32, i32, i32), tile_map: &HashMap<(i32, i32, i32), (bool, u32)>| { let mut visible_range = [0u32; 8]; for mut camera_z in -150..100 { camera_z *= tile_size; let mut is_visible = false; if pos.2 > camera_z { continue; } let mut is_occluded = false; 'vertical_check: for z_offset in 1..=35 { // check above let above_pos = (pos.0, pos.1, pos.2 + (z_offset * tile_size)); if above_pos.2 <= camera_z { if let Some(&(is_opaque, _)) = tile_map.get(&above_pos) { if is_opaque { is_occluded = true; break 'vertical_check; } } } else { break 'vertical_check; } } if !is_occluded { let base_pos = (pos.0, pos.1, pos.2); 'neighbor_check: for x_offset in -1..=1 { for y_offset in -1..=1 { for z_offset in 0..=1 { if x_offset == 0 && y_offset == 0 && z_offset == 0 { continue; } let neighbor_pos = ( base_pos.0 + x_offset * tile_size, base_pos.1 + y_offset * tile_size, base_pos.2 + z_offset * tile_size, ); if let Some(&(_, id)) = tile_map.get(&neighbor_pos) { if id == 0 { is_visible = true; break 'neighbor_check; } } } } } } if is_visible { let z2 = ((camera_z / tile_size) + 150) as usize; visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32); } } visible_range }; // Update floor tiles query_set .p2() .par_iter_mut() .for_each(|(mut tile, transform)| { let pos = ( transform.translation.x as i32, transform.translation.y as i32, transform.translation.z as i32, ); tile.visible_range = calculate_visibility(pos, &floor_tile_map); }); // Update fixture tiles query_set .p3() .par_iter_mut() .for_each(|(mut fixture, transform)| { let pos = ( transform.translation.x as i32, transform.translation.y as i32, transform.translation.z as i32 - 1, ); fixture.visible_range = calculate_visibility(pos, &fixture_tile_map); }); } pub fn update_tile_visibility( z_index: ResMut, mut query_set: ParamSet<( Query<(&FloorTile, &mut Visibility)>, Query<(&FixtureTile, &mut Visibility)>, )>, ) { let z_index = (z_index.0 as i32 + 150) as usize; // Update floor visibility query_set .p0() .par_iter_mut() .for_each(|(tile, mut visibility)| { let is_visible = (tile.visible_range[z_index / 32] & (1 << (z_index % 32) as u32)) != 0; *visibility = if is_visible { Visibility::Visible } else { Visibility::Hidden }; }); // Update fixture visibility query_set .p1() .par_iter_mut() .for_each(|(fixture, mut visibility)| { let is_visible = (fixture.visible_range[z_index / 32] & (1 << (z_index % 32) as u32)) != 0; *visibility = if is_visible { Visibility::Visible } else { Visibility::Hidden }; }); } fn calculate_connected_texture(floor_tiles: &HashMap<(i32, i32, i32), (bool, u32)>) -> Vec { let mut textures = vec![]; for ((x, y, z), (is_floor, tile_id)) in floor_tiles.iter() { let mut is_wall = false; for x_offset in -1..=1 { for y_offset in -1..=1 { for z_offset in 0..=1 { if x_offset == 0 && y_offset == 0 && z_offset == 0 { continue; } let neighbor_pos = (x + x_offset, y + y_offset, z + z_offset); if let Some((_, neighbor_id)) = floor_tiles.get(&neighbor_pos) { if *neighbor_id > 0 { // assuming wall IDs are greater than 0 is_wall = true; break; } } } } } match (is_floor, is_wall) { (true, false) => textures.push("floor".to_string()), // or some other floor texture (false, true) => textures.push("wall".to_string()), // or some other wall texture _ => panic!("Unexpected tile state"), } } textures } pub fn tile_item_sprite_update( time: Res