From 6c3232df74f4050e9fdfc95b8ed6df95b2245c14 Mon Sep 17 00:00:00 2001 From: popertots Date: Wed, 8 Jan 2025 01:33:18 +0000 Subject: [PATCH] chunk2? --- src/citizen.rs | 12 +- src/main.rs | 14 +-- src/tile.rs | 136 +------------------- src/tilemap.rs | 333 ++++++++++++++++++++++++++++++++++--------------- src/tiles.rs | 9 ++ 5 files changed, 252 insertions(+), 252 deletions(-) diff --git a/src/citizen.rs b/src/citizen.rs index 5ea70fc..7ca1462 100644 --- a/src/citizen.rs +++ b/src/citizen.rs @@ -88,11 +88,11 @@ pub fn check_citizen_positions_for_chunks( let chunk_pos = IVec2::new(chunk_x, chunk_y); - // Load chunk if not already loaded - if !chunk_map.loaded_chunks.contains_key(&chunk_pos) { - event_writer.send(tilemap::LoadChunkEvent { - chunk_position: chunk_pos, - }); - } + // // Load chunk if not already loaded + // if !chunk_map.loaded_chunks.contains_key(&chunk_pos) { + // event_writer.send(tilemap::LoadChunkEvent { + // chunk_position: chunk_pos, + // }); + // } } } diff --git a/src/main.rs b/src/main.rs index 8ca0eb7..e77ab91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,5 @@ -use std::process::exit; use bevy::prelude::*; -use camera::PanningCamera; mod camera; mod citizen; @@ -29,6 +27,7 @@ fn main() { ) .insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0))) .add_plugins(tilemap::TilemapPlugin) + .add_plugins(tilemap::OcclusionPlugin) .add_systems( Startup, ( @@ -38,15 +37,6 @@ fn main() { citizen::spawn_citizens, // New citizen spawning system ), ) - .add_systems( - PostStartup, - ( - tile::build_tile_map, - tile::tile_sprite_generate_occlusion_map, - tile::update_tile_visibility, - ) - .chain(), - ) .add_systems( FixedUpdate, ( @@ -70,10 +60,10 @@ fn main() { } fn setup_initial_chunks(mut event_writer: EventWriter) { + println!("setup_initial_chunks"); // Spawn a 3x3 grid of chunks around the origin for x in -1..=1 { for y in -1..=1 { - println!("setup_initial_chunks: x = {}, y = {}", x, y); event_writer.send(tilemap::LoadChunkEvent { chunk_position: IVec2::new(x, y), }); diff --git a/src/tile.rs b/src/tile.rs index efa1ecc..c7376f5 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,5 +1,6 @@ use crate::constants::TILE_SIZE; use crate::game; +use crate::tilemap::ChunkMap; use bevy::ecs::system::ParamSet; use bevy::prelude::*; use std::collections::HashMap; @@ -73,140 +74,6 @@ pub struct TileMap { 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<(&mut FloorTile, &Transform)>, - Query<(&mut FixtureTile, &Transform)>, - )>, -) { - println!("tile_sprite_generate_occlusion_map"); - - let tile_size = TILE_SIZE as i32; - - // Helper function to calculate visibility - 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; - - if pos.z > camera_z { - continue; - } - - let mut is_occluded = false; - - '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 let Some(&(_, solid, _)) = tilemap.fixtures.get(&above_pos) { - if solid { - is_occluded = true; - break 'vertical_check; - } - } - } else { - break 'vertical_check; - } - } - - 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 - .p0() - .par_iter_mut() - .for_each(|(mut tile, transform)| { - let pos = transform.translation.as_ivec3(); - tile.visible_range = calculate_visibility(pos, &tilemap); - }); - - // Update fixture tiles - query_set - .p1() - .par_iter_mut() - .for_each(|(mut fixture, transform)| { - let pos = transform.translation.as_ivec3() - IVec3::new(0, 0, 1); - fixture.visible_range = calculate_visibility(pos, &tilemap); - }); -} - pub fn update_tile_visibility( z_index: ResMut, mut query_set: ParamSet<( @@ -214,7 +81,6 @@ pub fn update_tile_visibility( Query<(&FixtureTile, &mut Visibility)>, )>, ) { - println!("update_tile_visibility"); let z_index = (z_index.0 as i32 + 150) as usize; diff --git a/src/tilemap.rs b/src/tilemap.rs index 51252ce..6d003c5 100644 --- a/src/tilemap.rs +++ b/src/tilemap.rs @@ -1,12 +1,11 @@ use crate::constants::TILE_SIZE; +use crate::tile::{FixtureTile, FloorTile, TileMap}; use crate::tiles::{FixtureTilePrefab, FloorTilePrefab}; use bevy::prelude::*; use noise::{NoiseFn, Perlin}; use std::collections::HashMap; -use std::process::exit; pub const CHUNK_SIZE: i32 = 8; -pub const CHUNK_HEIGHT: i32 = 200; #[derive(Resource)] pub struct ChunkMap { @@ -27,28 +26,150 @@ pub struct LoadChunkEvent { } fn setup_chunk_system(mut commands: Commands) { + commands.insert_resource(TileMap::default()); commands.insert_resource(ChunkMap::default()); } +// Events +#[derive(Event)] +pub struct ChunkOcclusionEvent { + pub chunk_pos: IVec2, +} + +#[derive(Event)] +pub struct TileOcclusionUpdateEvent { + pub positions: Vec, +} + + +// System to handle individual tile occlusion updates +fn handle_tile_occlusion_updates( + mut events: EventReader, + tilemap: Res, + mut query_set: ParamSet<( + Query<(&mut FloorTile, &Transform)>, + Query<(&mut FixtureTile, &Transform)>, + )>, +) { + let tile_size = TILE_SIZE as i32; + + 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; + + if pos.z > camera_z { + continue; + } + + let mut is_occluded = false; + + 'vertical_check: for z_offset in 1..=35 { + 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 let Some(&(_, solid, _)) = tilemap.fixtures.get(&above_pos) { + if solid { + is_occluded = true; + break 'vertical_check; + } + } + } else { + break 'vertical_check; + } + } + 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 { + print!("#"); + let z2 = ((camera_z / tile_size) + 150) as usize; + visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32); + } + } + + visible_range + }; + + for event in events.read() { + print!("event2"); + // Process floor tiles + for (mut tile, transform) in query_set.p0().iter_mut() { + let pos = transform.translation.as_ivec3(); + if event.positions.contains(&pos) { + // this never calls + print!("floor"); + tile.visible_range = calculate_visibility(pos, &tilemap); + } + } + + // Process fixture tiles + for (mut fixture, transform) in query_set.p1().iter_mut() { + let pos = transform.translation.as_ivec3(); + if event.positions.contains(&pos) { + // this never calls + print!("fixture"); + let adjusted_pos = pos - IVec3::new(0, 0, 1); + fixture.visible_range = calculate_visibility(adjusted_pos, &tilemap); + } + } + } +} + fn handle_chunk_loading( mut commands: Commands, asset_server: Res, mut events: EventReader, mut chunk_map: ResMut, + mut tilemap: ResMut, + mut occlusion_events: EventWriter, ) { let noise = Perlin::new(0); for event in events.read() { let chunk_pos = event.chunk_position; - // Skip if chunk is already loaded if chunk_map.loaded_chunks.contains_key(&chunk_pos) { continue; } - // Mark chunk as loaded chunk_map.loaded_chunks.insert(chunk_pos, true); - // Calculate world space coordinates for chunk let start_x = chunk_pos.x * CHUNK_SIZE; let start_y = chunk_pos.y * CHUNK_SIZE; @@ -60,10 +181,8 @@ fn handle_chunk_loading( let world_x = start_x + local_x; let world_y = start_y + local_y; - let noise_value_a = - noise.get([world_x as f64 * 0.01, world_y as f64 * 0.01]) * 1.25; - let noise_value_b = - noise.get([world_x as f64 * 0.05, world_y as f64 * 0.05]) * 0.25; + let noise_value_a = noise.get([world_x as f64 * 0.01, world_y as f64 * 0.01]) * 1.25; + let noise_value_b = noise.get([world_x as f64 * 0.05, world_y as f64 * 0.05]) * 0.25; let combined_noise_value = noise_value_a + noise_value_b; let noise_position = Vec3::new( @@ -71,112 +190,113 @@ fn handle_chunk_loading( (world_y as f32 * TILE_SIZE).round(), (combined_noise_value * 4.).round() as f32 * TILE_SIZE, ); - generate_vertical_slice( - &mut commands, - &asset_server, - world_x, - world_y, - &noise, - noise_position, - &mut floor_positions, - ); - } - } - // Generate fixtures after floor tiles - generate_fixtures_for_chunk(&mut commands, &asset_server, &floor_positions); - } -} + // Spawn tiles and add them to tilemap + for z in -150..50 { + let position = Vec3::new( + (world_x as f32 * TILE_SIZE).round(), + (world_y as f32 * TILE_SIZE).round(), + (z as f32 * TILE_SIZE).round(), + ); + let pos_ivec = position.as_ivec3(); -fn generate_vertical_slice( - commands: &mut Commands, - asset_server: &Res, - x: i32, - y: i32, - noise: &Perlin, - noise_position: Vec3, - floor_positions: &mut Vec<(Vec3, &'static str)>, -) { - for z in -150..50 { - let position = Vec3::new( - (x as f32 * TILE_SIZE).round(), - (y as f32 * TILE_SIZE).round(), - (z as f32 * TILE_SIZE).round(), - ); - - let floor_type = if noise_position.z > position.z { - if z < -15 { - let noise_value = noise.get([x as f64 * 0.05, y as f64 * 0.05, z as f64 * 0.05]); - if noise_value < -0.5 { - spawn_tile(commands, FloorTilePrefab::air(position, asset_server)); - Some("air") - } else if noise_value < 0.8 { - spawn_tile(commands, FloorTilePrefab::rock(position, asset_server)); - Some("rock") - } else { - spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server)); - Some("dirt") + if noise_position.z > position.z { + if z < -15 { + let noise_value = noise.get([world_x as f64 * 0.05, world_y as f64 * 0.05, z as f64 * 0.05]); + if noise_value < -0.5 { + commands.spawn(FloorTilePrefab::air(position, &asset_server)); + tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile + floor_positions.push((position, "air")); + } else if noise_value < 0.8 { + commands.spawn(FloorTilePrefab::rock(position, &asset_server)); + tilemap.floors.insert(pos_ivec, (2, true, false, 255, [0; 8])); // Rock tile + floor_positions.push((position, "rock")); + } else { + commands.spawn(FloorTilePrefab::dirt(position, &asset_server)); + tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile + floor_positions.push((position, "dirt")); + } + } else { + commands.spawn(FloorTilePrefab::dirt(position, &asset_server)); + tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile + floor_positions.push((position, "dirt")); + } + } else if noise_position.z < position.z { + commands.spawn(FloorTilePrefab::air(position, &asset_server)); + tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile + floor_positions.push((position, "air")); + } else { + commands.spawn(FloorTilePrefab::dirt(position, &asset_server)); + tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile + floor_positions.push((position, "dirt")); + } } - } else { - spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server)); - Some("dirt") } - } else if noise_position.z < position.z { - spawn_tile(commands, FloorTilePrefab::air(position, asset_server)); - Some("air") - } else { - spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server)); - Some("dirt") - }; - - if let Some(floor_type) = floor_type { - floor_positions.push((position, floor_type)); } - } -} -fn spawn_tile(commands: &mut Commands, bundle: impl Bundle) -> Entity { - commands.spawn(bundle).id() -} + // Generate fixtures and add them to tilemap + for (position, floor_type) in floor_positions.iter() { + let above_pos = *position + Vec3::new(0.0, 0.0, TILE_SIZE); + let above_ivec = above_pos.as_ivec3(); -fn generate_fixtures_for_chunk( - commands: &mut Commands, - asset_server: &Res, - floor_positions: &[(Vec3, &str)], -) { - let floor_map: HashMap<(i32, i32, i32), &str> = floor_positions - .iter() - .map(|(pos, floor_type)| ((pos.x as i32, pos.y as i32, pos.z as i32), *floor_type)) - .collect(); - - for (position, _) in floor_positions { - let x = position.x as i32; - let y = position.y as i32; - let z = position.z as i32; - - if let Some(&above_floor_type) = floor_map.get(&(x, y, z + TILE_SIZE as i32)) { - if above_floor_type == "air" { - continue; - } - - let fixture_position = Vec3::new(position.x, position.y, position.z + 1.); - - match above_floor_type { + match *floor_type { "dirt" => { - commands.spawn(FixtureTilePrefab::dirt_wall(fixture_position, asset_server)); + commands.spawn(FixtureTilePrefab::dirt_wall(above_pos, &asset_server)); + tilemap.fixtures.insert(above_ivec, (1, true, [0; 8])); // Dirt wall } "rock" => { - commands.spawn(FixtureTilePrefab::rock_wall(fixture_position, asset_server)); + commands.spawn(FixtureTilePrefab::rock_wall(above_pos, &asset_server)); + tilemap.fixtures.insert(above_ivec, (2, true, [0; 8])); // Rock wall } "bedrock" => { - commands.spawn(FixtureTilePrefab::bedrock_wall( - fixture_position, - asset_server, - )); + commands.spawn(FixtureTilePrefab::bedrock_wall(above_pos, &asset_server)); + tilemap.fixtures.insert(above_ivec, (3, true, [0; 8])); // Bedrock wall } _ => {} } } + + // Emit occlusion event for this chunk + occlusion_events.send(ChunkOcclusionEvent { + chunk_pos, + }); + } +} + + + +// System to handle chunk occlusion events +fn handle_chunk_occlusion_events( + mut events: EventReader, + tilemap: Res, + mut tile_update_events: EventWriter, +) { + for event in events.read() { + let chunk_pos = event.chunk_pos; + let tile_size = TILE_SIZE as i32; + let start_x = chunk_pos.x * CHUNK_SIZE * tile_size; + let end_x = start_x + (CHUNK_SIZE * tile_size); + let start_y = chunk_pos.y * CHUNK_SIZE * tile_size; + let end_y = start_y + (CHUNK_SIZE * tile_size); + + // Collect positions that need visibility updates + let mut positions = Vec::new(); + + // Add positions from the current chunk + for x in (start_x..end_x).step_by(tile_size as usize) { + for y in (start_y..end_y).step_by(tile_size as usize) { + for z in -150..50 { + let pos = IVec3::new(y, x, z * tile_size); + if tilemap.floors.contains_key(&pos) || tilemap.fixtures.contains_key(&pos) { + positions.push(pos); + } + } + } + } + // Send update event if we have positions to process + if !positions.is_empty() { + tile_update_events.send(TileOcclusionUpdateEvent { positions }); + } } } @@ -190,3 +310,18 @@ impl Plugin for TilemapPlugin { .add_systems(Update, handle_chunk_loading); } } + +// Plugin to handle occlusion systems +pub struct OcclusionPlugin; + + +impl Plugin for OcclusionPlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_systems(Update, ( + handle_chunk_occlusion_events, + handle_tile_occlusion_updates, + ).chain()); + } +} \ No newline at end of file diff --git a/src/tiles.rs b/src/tiles.rs index d3183d6..7f4bb31 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -8,6 +8,7 @@ pub struct FloorTilePrefab { sprite: Sprite, tile: FloorTile, tile_state: TileState, + visibility: Visibility } impl FloorTilePrefab { @@ -25,6 +26,7 @@ impl FloorTilePrefab { tile_state: TileState { timer: Timer::from_seconds(1.0, TimerMode::Repeating), }, + visibility: Visibility::Hidden, } } @@ -42,6 +44,7 @@ impl FloorTilePrefab { tile_state: TileState { timer: Timer::from_seconds(1.0, TimerMode::Repeating), }, + visibility: Visibility::Hidden, } } @@ -60,6 +63,7 @@ impl FloorTilePrefab { tile_state: TileState { timer: Timer::from_seconds(1.0, TimerMode::Repeating), }, + visibility: Visibility::Hidden, } } @@ -77,6 +81,7 @@ impl FloorTilePrefab { tile_state: TileState { timer: Timer::from_seconds(1.0, TimerMode::Repeating), }, + visibility: Visibility::Hidden, } } } @@ -86,6 +91,7 @@ pub struct FixtureTilePrefab { transform: Transform, sprite: Sprite, tile: FixtureTile, + visibility: Visibility } impl FixtureTilePrefab { @@ -100,6 +106,7 @@ impl FixtureTilePrefab { id: 1, ..Default::default() }, + visibility: Visibility::Hidden, } } @@ -114,6 +121,7 @@ impl FixtureTilePrefab { id: 2, ..Default::default() }, + visibility: Visibility::Hidden, } } @@ -128,6 +136,7 @@ impl FixtureTilePrefab { id: 0, ..Default::default() }, + visibility: Visibility::Hidden, } } }