diff --git a/assets/dorf.png b/assets/dorf.png new file mode 100644 index 0000000..bd3070e Binary files /dev/null and b/assets/dorf.png differ diff --git a/assets/empty.png b/assets/empty.png new file mode 100644 index 0000000..bf3830a Binary files /dev/null and b/assets/empty.png differ diff --git a/assets/natural walls/rock/corner_full.png b/assets/natural walls/rock/corner_full.png new file mode 100644 index 0000000..4258059 Binary files /dev/null and b/assets/natural walls/rock/corner_full.png differ diff --git a/src/citizen.rs b/src/citizen.rs index b9aac5f..5ea70fc 100644 --- a/src/citizen.rs +++ b/src/citizen.rs @@ -1,4 +1,7 @@ -use crate::constants::*; +use crate::{ + constants::{self, *}, + tilemap, +}; use bevy::prelude::*; use rand::prelude::*; @@ -10,7 +13,7 @@ pub struct Ambulatory { #[derive(Bundle)] pub struct Citizen { - walker: Ambulatory, + walkness: Ambulatory, sprite: Sprite, transform: Transform, } @@ -18,9 +21,9 @@ pub struct Citizen { impl Citizen { pub fn new(asset_server: &Res, position: Vec3) -> Self { Citizen { - walker: Ambulatory { speed: TILE_SIZE }, + walkness: Ambulatory { speed: TILE_SIZE }, sprite: Sprite { - image: asset_server.load("character.png"), + image: asset_server.load("dorf.png"), ..Default::default() }, transform: Transform::from_translation(position).with_scale(Vec3::splat(PIXEL_RATIO)), @@ -30,29 +33,66 @@ impl Citizen { pub fn citizen_movement(mut query: Query<(&Ambulatory, &mut Transform), With>) { for (citizen, mut transform) in query.iter_mut() { - if random::() < 0.66666 { + // Skip processing if the random check fails + if rand::random::() >= 0.66666 { continue; } - let mut direction = Vec2::ZERO; - direction.y += rand::random::(); - direction.y -= rand::random::(); - direction.x -= rand::random::(); - direction.x += rand::random::(); + // Generate random directions + let direction_x = (rand::random::() - rand::random::()).round(); + let direction_y = (rand::random::() - rand::random::()).round(); - if direction.length() > 0.0 { - direction.x = direction.x.round(); - direction.y = direction.y.round(); + // Skip if there's no movement + if direction_x == 0.0 && direction_y == 0.0 { + continue; + } - let movement = direction * citizen.speed; - transform.translation.x += movement.x; - transform.translation.y += movement.y; + // Calculate movement only once + let speed = citizen.speed; + transform.translation.x += direction_x * speed; + transform.translation.y += direction_y * speed; - if direction.x > 0.0 { - transform.scale.x = PIXEL_RATIO; - } else if direction.x < 0.0 { - transform.scale.x = -PIXEL_RATIO; - } + // Adjust scale for x direction + if direction_x != 0.0 { + transform.scale.x = PIXEL_RATIO * direction_x.signum(); + } + } +} + +pub fn spawn_citizens(mut commands: Commands, asset_server: Res) { + let mut rng = rand::thread_rng(); + + // Spawn a handful of citizens + for _ in 0..10 { + let x = rng.gen_range(-10.0..10.0); + let y = rng.gen_range(-10.0..10.0); + let position = Vec3::new(x, y, 0.0) * PIXEL_RATIO; + + commands.spawn(Citizen::new(&asset_server, position)); + } +} + +pub fn check_citizen_positions_for_chunks( + query: Query<&Transform, With>, + chunk_map: Res, + mut event_writer: EventWriter, +) { + for transform in query.iter() { + let position = transform.translation; + + // Convert citizen position to chunk coordinates + let chunk_x = + (position.x / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32; + let chunk_y = + (position.y / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32; + + 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, + }); } } } diff --git a/src/constants.rs b/src/constants.rs index cba30c1..51c6b13 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,2 +1,2 @@ -pub const PIXEL_RATIO: f32 = 3.; +pub const PIXEL_RATIO: f32 = 1.; pub const TILE_SIZE: f32 = 16.0 * PIXEL_RATIO; diff --git a/src/main.rs b/src/main.rs index 9ec4ce6..8ca0eb7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,7 @@ +use std::process::exit; + use bevy::prelude::*; +use camera::PanningCamera; mod camera; mod citizen; @@ -7,6 +10,7 @@ mod cursor; mod game; mod item; mod tile; +mod tilemap; mod tiles; fn main() { @@ -24,12 +28,14 @@ fn main() { .set(ImagePlugin::default_nearest()), ) .insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0))) + .add_plugins(tilemap::TilemapPlugin) .add_systems( Startup, ( - game::setup_level, + setup_initial_chunks, camera::spawn_panning_camera, cursor::setup_cursor, + citizen::spawn_citizens, // New citizen spawning system ), ) .add_systems( @@ -47,6 +53,8 @@ fn main() { camera::camera_movement, citizen::citizen_movement, cursor::move_cursor, + check_camera_position_for_chunks, + citizen::check_citizen_positions_for_chunks, // New citizen-based chunk loading system ), ) .init_resource::() @@ -60,3 +68,45 @@ fn main() { ) .run(); } + +fn setup_initial_chunks(mut event_writer: EventWriter) { + // 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), + }); + } + } +} + +// New system to check camera position and load nearby chunks +fn check_camera_position_for_chunks( + camera_query: Query<&Transform, With>, + chunk_map: Res, + mut event_writer: EventWriter, +) { + let camera_transform = camera_query.single(); + let camera_pos = camera_transform.translation; + + // Convert camera position to chunk coordinates + let chunk_x = + (camera_pos.x / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32; + let chunk_y = + (camera_pos.y / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32; + + // Check a 3x3 area around the camera's current chunk + for x in (chunk_x - 1)..=(chunk_x + 1) { + for y in (chunk_y - 1)..=(chunk_y + 1) { + let chunk_pos = IVec2::new(x, y); + + // Only spawn new chunks if they haven't been loaded yet + if !chunk_map.loaded_chunks.contains_key(&chunk_pos) { + event_writer.send(tilemap::LoadChunkEvent { + chunk_position: chunk_pos, + }); + } + } + } +} diff --git a/src/tile.rs b/src/tile.rs index f6523f7..efa1ecc 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,11 +1,8 @@ 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)] @@ -46,9 +43,6 @@ impl Default for FixtureTile { } } -#[derive(Component, Clone)] -pub struct ConnectedTexture {} - #[derive(Resource, Default)] pub struct CameraMoved(pub bool); @@ -211,24 +205,6 @@ pub fn tile_sprite_generate_occlusion_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( @@ -270,79 +246,6 @@ pub fn update_tile_visibility( }); } -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