diff --git a/src/game.rs b/src/game.rs index 12585f3..39ddd97 100644 --- a/src/game.rs +++ b/src/game.rs @@ -10,6 +10,7 @@ use rand::prelude::*; pub struct ZIndex(pub f32); pub fn setup_level(mut commands: Commands, asset_server: Res) { + println!("setup_level"); setup_tilemap(&mut commands, &asset_server); for x in -10..10 { @@ -164,7 +165,10 @@ fn setup_tilemap(commands: &mut Commands, asset_server: &Res) { commands.spawn(FixtureTilePrefab::rock_wall(fixture_position, asset_server)); } "bedrock" => { - commands.spawn(FixtureTilePrefab::bedrock_wall(fixture_position, asset_server)); + commands.spawn(FixtureTilePrefab::bedrock_wall( + fixture_position, + asset_server, + )); } _ => {} } diff --git a/src/main.rs b/src/main.rs index 406117c..9ec4ce6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ fn main() { .add_systems( PostStartup, ( + tile::build_tile_map, tile::tile_sprite_generate_occlusion_map, tile::update_tile_visibility, ) diff --git a/src/tile.rs b/src/tile.rs index 6ae9f22..f6523f7 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -2,8 +2,10 @@ use crate::constants::TILE_SIZE; use crate::game; use crate::item::Item; use bevy::ecs::system::ParamSet; +use bevy::math::ivec3; use bevy::prelude::*; use std::collections::HashMap; +use std::process::exit; #[derive(Component, Clone)] #[require(Sprite)] @@ -45,9 +47,7 @@ impl Default for FixtureTile { } #[derive(Component, Clone)] -pub struct ConnectedTexture { - -} +pub struct ConnectedTexture {} #[derive(Resource, Default)] pub struct CameraMoved(pub bool); @@ -73,136 +73,162 @@ pub fn camera_z_movement( } } +#[derive(Resource, Default)] +pub struct TileMap { + pub floors: HashMap, + pub fixtures: HashMap, +} + +pub fn build_tile_map( + mut commands: Commands, + query1: Query<(&Transform, &FloorTile)>, + query2: Query<(&Transform, &FixtureTile)>, +) { + println!("build_tile_map"); + let mut floor_tile_map = TileMap::default(); + for (transform, floor) in query1.iter() { + floor_tile_map.floors.insert( + transform.translation.as_ivec3(), + ( + floor.id, + floor.opaque, + floor.walkable, + floor.astar_weight, + floor.visible_range, + ), + ); + } + for (transform, fixture) in query2.iter() { + floor_tile_map.fixtures.insert( + transform.translation.as_ivec3(), + (fixture.id, fixture.solid, fixture.visible_range), + ); + } + commands.insert_resource(floor_tile_map); +} + pub fn tile_sprite_generate_occlusion_map( + tilemap: Res, 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(); + println!("tile_sprite_generate_occlusion_map"); - 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]; + let calculate_visibility = |pos: IVec3, tilemap: &TileMap| { + let mut visible_range = [0u32; 8]; - for mut camera_z in -150..100 { - camera_z *= tile_size; - let mut is_visible = false; + for mut camera_z in -150..100 { + camera_z *= tile_size; + let mut is_visible = false; - if pos.2 > camera_z { - continue; - } + if pos.z > camera_z { + continue; + } - let mut is_occluded = false; + 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; - } - } - } + 'vertical_check: for z_offset in 1..=35 { + // check above + let above_pos = IVec3::new(pos.x, pos.y, pos.z + (z_offset * tile_size)); + if above_pos.z <= camera_z { + // Check both floors and fixtures for occlusion + if let Some(&(_, opaque, _, _, _)) = tilemap.floors.get(&above_pos) { + if opaque { + is_occluded = true; + break 'vertical_check; } } - } - - if is_visible { - let z2 = ((camera_z / tile_size) + 150) as usize; - visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32); + if let Some(&(_, solid, _)) = tilemap.fixtures.get(&above_pos) { + if solid { + is_occluded = true; + break 'vertical_check; + } + } + } else { + break 'vertical_check; } } - visible_range - }; + if !is_occluded { + '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 = IVec3::new( + pos.x + x_offset * tile_size, + pos.y + y_offset * tile_size, + pos.z + z_offset * tile_size, + ); + + // Check both floors and fixtures for visibility + if let Some(&(id, _, _, _, _)) = tilemap.floors.get(&neighbor_pos) { + if id == 0 { + is_visible = true; + break 'neighbor_check; + } + } + if let Some(&(id, _, _)) = tilemap.fixtures.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() + .p0() .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); + let pos = transform.translation.as_ivec3(); + tile.visible_range = calculate_visibility(pos, &tilemap); }); // Update fixture tiles query_set - .p3() + .p1() .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); + let pos = transform.translation.as_ivec3() - IVec3::new(0, 0, 1); + fixture.visible_range = calculate_visibility(pos, &tilemap); }); + + use std::time::Instant; + let total: Instant = Instant::now(); + + for i in 0..1000000 { + let now: Instant = Instant::now(); + for x in -1..=1 { + for y in -1..=1 { + for z in 0..=1 { + tilemap.floors.get(&IVec3::new(x, y, z)); + } + } + } + let elapsed = now.elapsed(); + } + let elapsed = total.elapsed(); + print!("{:.4?}, ", elapsed / 1000000); + exit(0); } pub fn update_tile_visibility( @@ -212,6 +238,8 @@ pub fn update_tile_visibility( Query<(&FixtureTile, &mut Visibility)>, )>, ) { + println!("update_tile_visibility"); + let z_index = (z_index.0 as i32 + 150) as usize; // Update floor visibility @@ -258,7 +286,8 @@ fn calculate_connected_texture(floor_tiles: &HashMap<(i32, i32, i32), (bool, u32 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 + if *neighbor_id > 0 { + // assuming wall IDs are greater than 0 is_wall = true; break; } @@ -269,7 +298,7 @@ fn calculate_connected_texture(floor_tiles: &HashMap<(i32, i32, i32), (bool, u32 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 + (false, true) => textures.push("wall".to_string()), // or some other wall texture _ => panic!("Unexpected tile state"), } }