Chunking 3

This commit is contained in:
StephenAdamson
2025-01-15 19:50:18 +00:00
parent 7f1ec77ab0
commit d2e9bb0cf3
6 changed files with 88 additions and 288 deletions
+22 -25
View File
@@ -1,7 +1,4 @@
use crate::{ use crate::constants::*;
constants::{self, *},
tilemap,
};
use bevy::prelude::*; use bevy::prelude::*;
use rand::prelude::*; use rand::prelude::*;
@@ -72,27 +69,27 @@ pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
} }
} }
pub fn check_citizen_positions_for_chunks( // pub fn check_citizen_positions_for_chunks(
query: Query<&Transform, With<Ambulatory>>, // query: Query<&Transform, With<Ambulatory>>,
chunk_map: Res<tilemap::ChunkMap>, // chunk_map: Res<tilemap::ChunkMap>,
mut event_writer: EventWriter<tilemap::LoadChunkEvent>, // mut event_writer: EventWriter<tilemap::LoadChunkEvent>,
) { // ) {
for transform in query.iter() { // for transform in query.iter() {
let position = transform.translation; // let position = transform.translation;
// Convert citizen position to chunk coordinates // // Convert citizen position to chunk coordinates
let chunk_x = // let chunk_x =
(position.x / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32; // (position.x / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32;
let chunk_y = // let chunk_y =
(position.y / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32; // (position.y / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32;
let chunk_pos = IVec2::new(chunk_x, chunk_y); // let chunk_pos = IVec2::new(chunk_x, chunk_y);
// // Load chunk if not already loaded // // // Load chunk if not already loaded
// if !chunk_map.loaded_chunks.contains_key(&chunk_pos) { // // if !chunk_map.loaded_chunks.contains_key(&chunk_pos) {
// event_writer.send(tilemap::LoadChunkEvent { // // event_writer.send(tilemap::LoadChunkEvent {
// chunk_position: chunk_pos, // // chunk_position: chunk_pos,
// }); // // });
// } // // }
} // }
} // }
-173
View File
@@ -1,177 +1,4 @@
use crate::constants::*;
use crate::item::ItemBundle;
use crate::tiles::FloorTilePrefab;
use crate::{citizen::Citizen, tiles::FixtureTilePrefab};
use bevy::prelude::*; use bevy::prelude::*;
use noise::{NoiseFn, Perlin};
use rand::prelude::*;
#[derive(Resource)] #[derive(Resource)]
pub struct ZIndex(pub f32); pub struct ZIndex(pub f32);
pub fn setup_level(mut commands: Commands, asset_server: Res<AssetServer>) {
println!("setup_level");
setup_tilemap(&mut commands, &asset_server);
for x in -10..10 {
for y in -10..10 {
if random::<f32>() < 0.1 {
commands.spawn(Citizen::new(
&asset_server,
Vec3::new(x as f32 * TILE_SIZE, y as f32 * TILE_SIZE, 0.9),
));
}
}
}
}
fn setup_tilemap(commands: &mut Commands, asset_server: &Res<AssetServer>) {
let noise = Perlin::new(0);
let mut floor_positions = Vec::new();
// First pass: Generate and store floor tiles
for y in -50..50 {
for x in -50..50 {
let noise_value_a = noise.get([x as f64 * 0.01, y as f64 * 0.01]) * 1.25;
let noise_value_b = noise.get([x as f64 * 0.05, y as f64 * 0.05]) * 0.25;
let combined_noise_value = noise_value_a + noise_value_b;
let noise_position = Vec3::new(
(x as f32 * TILE_SIZE).round(),
(y as f32 * TILE_SIZE).round(),
(combined_noise_value * 4.).round() as f32 * TILE_SIZE,
);
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 items: Vec<ItemBundle> = vec![];
let mut floor_type = None;
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 {
commands
.spawn(FloorTilePrefab::air(position, asset_server))
.with_children(|parent| {
for item in items {
parent.spawn(item);
}
});
floor_type = Some("air");
} else if noise_value < 0.8 {
commands
.spawn(FloorTilePrefab::rock(position, asset_server))
.with_children(|parent| {
for item in items {
parent.spawn(item);
}
});
floor_type = Some("rock");
} else {
commands
.spawn(FloorTilePrefab::dirt(position, asset_server))
.with_children(|parent| {
for item in items {
parent.spawn(item);
}
});
floor_type = Some("dirt");
}
} else {
commands
.spawn(FloorTilePrefab::dirt(position, asset_server))
.with_children(|parent| {
for item in items {
parent.spawn(item);
}
});
floor_type = Some("dirt");
}
} else if noise_position.z < position.z {
commands
.spawn(FloorTilePrefab::air(position, asset_server))
.with_children(|parent| {
for item in items {
parent.spawn(item);
}
});
floor_type = Some("air");
} else {
commands
.spawn(FloorTilePrefab::dirt(position, asset_server))
.with_children(|parent| {
for item in items {
parent.spawn(item);
}
});
floor_type = Some("dirt");
}
// Store floor type and position
if let Some(floor_type) = floor_type {
floor_positions.push((position, floor_type));
}
}
}
}
// Generate bedrock floor
for x in -50..50 {
for y in -50..50 {
let position = Vec3::new(x as f32 * TILE_SIZE, y as f32 * TILE_SIZE, -150.);
commands.spawn(FloorTilePrefab::bedrock(position, asset_server));
floor_positions.push((position, "bedrock"));
}
}
// Sort floor positions by z coordinate (highest to lowest) to process from top to bottom
floor_positions.sort_by(|a, b| b.0.z.partial_cmp(&a.0.z).unwrap());
// Create a map to easily look up floor types at specific positions
let floor_map: std::collections::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();
// Second pass: Generate fixtures based on floor tiles above
for (position, _) in floor_positions.iter() {
let x = position.x as i32;
let y = position.y as i32;
let z = position.z as i32;
// Look up the floor type one z-level above
if let Some(above_floor_type) = floor_map.get(&(x, y, z + TILE_SIZE as i32)) {
// Skip if the floor above is air or if we're at the surface
if *above_floor_type == "air" {
continue;
}
// Calculate fixture position (one tile above current floor)
let fixture_position = Vec3::new(position.x, position.y, position.z + 1.);
// Spawn appropriate fixture based on floor type above
match *above_floor_type {
"dirt" => {
commands.spawn(FixtureTilePrefab::dirt_wall(fixture_position, asset_server));
}
"rock" => {
commands.spawn(FixtureTilePrefab::rock_wall(fixture_position, asset_server));
}
"bedrock" => {
commands.spawn(FixtureTilePrefab::bedrock_wall(
fixture_position,
asset_server,
));
}
_ => {}
}
}
}
}
+4 -4
View File
@@ -1,12 +1,12 @@
use bevy::prelude::*; use bevy::prelude::*;
#[derive(Component)] #[derive(Component)]
#[require(Sprite,Transform,Visibility )] #[require(Sprite, Transform, Visibility)]
pub struct Item { pub struct Item {
wear: u8, wear: u8,
quality: u8, quality: u8,
weight: u8, weight: u8,
stain_time: u16 stain_time: u16,
} }
impl Default for Item { impl Default for Item {
@@ -33,12 +33,12 @@ pub struct ItemBundle {
pub item: Item, pub item: Item,
pub transform: Transform, pub transform: Transform,
pub sprite: Sprite, pub sprite: Sprite,
pub visibility: Visibility pub visibility: Visibility,
} }
#[derive(Component)] #[derive(Component)]
pub struct Nameable { pub struct Nameable {
pub name: String pub name: String,
} }
#[derive(Component)] #[derive(Component)]
+2 -46
View File
@@ -29,10 +29,9 @@ fn main() {
.add_systems( .add_systems(
Startup, Startup,
( (
setup_initial_chunks,
camera::spawn_panning_camera, camera::spawn_panning_camera,
cursor::setup_cursor, cursor::setup_cursor,
citizen::spawn_citizens, // New citizen spawning system citizen::spawn_citizens,
), ),
) )
.add_systems( .add_systems(
@@ -41,8 +40,7 @@ fn main() {
camera::camera_movement, camera::camera_movement,
citizen::citizen_movement, citizen::citizen_movement,
cursor::move_cursor, cursor::move_cursor,
check_camera_position_for_chunks, // citizen::check_citizen_positions_for_chunks,
citizen::check_citizen_positions_for_chunks, // New citizen-based chunk loading system
), ),
) )
.init_resource::<tile::CameraMoved>() .init_resource::<tile::CameraMoved>()
@@ -56,45 +54,3 @@ fn main() {
) )
.run(); .run();
} }
fn setup_initial_chunks(mut event_writer: EventWriter<tilemap::LoadChunkEvent>) {
println!("setup_initial_chunks");
// // Spawn a 3x3 grid of chunks around the origin
// for x in -5..=5 {
// for y in -5..=5 {
// 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<Camera>>,
chunk_map: Res<tilemap::ChunkMap>,
mut event_writer: EventWriter<tilemap::LoadChunkEvent>,
) {
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 - 2)..=(chunk_x + 2) {
for y in (chunk_y - 2)..=(chunk_y + 2) {
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,
});
}
}
}
}
-3
View File
@@ -1,6 +1,4 @@
use crate::constants::TILE_SIZE;
use crate::game; use crate::game;
use crate::tilemap::ChunkMap;
use bevy::ecs::system::ParamSet; use bevy::ecs::system::ParamSet;
use bevy::prelude::*; use bevy::prelude::*;
use std::collections::HashMap; use std::collections::HashMap;
@@ -52,7 +50,6 @@ impl Default for FixtureTile {
#[derive(Resource, Default)] #[derive(Resource, Default)]
pub struct CameraMoved(pub bool); pub struct CameraMoved(pub bool);
// Modify camera_z_movement
pub fn camera_z_movement( pub fn camera_z_movement(
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
mut z_index: ResMut<game::ZIndex>, mut z_index: ResMut<game::ZIndex>,
+60 -37
View File
@@ -1,5 +1,5 @@
use crate::constants::TILE_SIZE; use crate::constants::TILE_SIZE;
use crate::tile::{self, FixtureTile, FloorTile, NeedsOccluded, TileMap}; use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileMap};
use crate::tiles::{FixtureTilePrefab, FloorTilePrefab}; use crate::tiles::{FixtureTilePrefab, FloorTilePrefab};
use bevy::prelude::*; use bevy::prelude::*;
use noise::{NoiseFn, Perlin}; use noise::{NoiseFn, Perlin};
@@ -30,7 +30,7 @@ fn setup_chunk_system(mut commands: Commands) {
commands.insert_resource(ChunkMap::default()); commands.insert_resource(ChunkMap::default());
} }
// System to handle individual tile occlusion updates // System to handle tile occlusion updates
pub fn handle_tile_occlusion_updates( pub fn handle_tile_occlusion_updates(
mut commands: Commands, mut commands: Commands,
tilemap: Res<TileMap>, tilemap: Res<TileMap>,
@@ -144,6 +144,22 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
visible_range visible_range
} }
pub fn generate_surface_noise(x: i32, y: i32) -> f32 {
let noise = Perlin::new(0);
let mut noise_value = 0.0;
let mut amplitude = 1.0;
let mut frequency = 0.008; // Reduced initial frequency for smoother base terrain
// Reduced number of octaves for less rough detail
for _ in 0..6 {
noise_value += noise.get([x as f64 * frequency, y as f64 * frequency]) * amplitude;
amplitude *= 0.6; // Gentler amplitude falloff
frequency *= 1.8; // Gentler frequency increase
}
(noise_value * 2.5) as f32 // Reduced height multiplier for less extreme elevation
}
fn handle_chunk_loading( fn handle_chunk_loading(
mut commands: Commands, mut commands: Commands,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
@@ -173,16 +189,10 @@ fn handle_chunk_loading(
let world_x = start_x + local_x; let world_x = start_x + local_x;
let world_y = start_y + local_y; 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 combined_noise_value = noise_value_a + noise_value_b;
let noise_position = Vec3::new( let noise_position = Vec3::new(
(world_x as f32 * TILE_SIZE).round(), (world_x as f32 * TILE_SIZE).round(),
(world_y as f32 * TILE_SIZE).round(), (world_y as f32 * TILE_SIZE).round(),
(combined_noise_value * 4.).round() as f32 * TILE_SIZE, (generate_surface_noise(world_x, world_y) * TILE_SIZE).round(),
); );
// Spawn tiles and add them to tilemap // Spawn tiles and add them to tilemap
@@ -194,41 +204,43 @@ fn handle_chunk_loading(
); );
let pos_ivec = position.as_ivec3(); let pos_ivec = position.as_ivec3();
if noise_position.z > position.z { if z < -8 {
if z < -8 { let noise_value = noise.get([
let noise_value = noise.get([ world_x as f64 * 0.05,
world_x as f64 * 0.05, world_y as f64 * 0.05,
world_y as f64 * 0.05, z as f64 * 0.05,
z as f64 * 0.05, ]);
]); if noise_value < -0.5 {
if noise_value < -0.5 { FloorTilePrefab::air(position, &asset_server).spawn(&mut commands);
FloorTilePrefab::air(position, &asset_server).spawn(&mut commands); tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile floor_positions.push((position, "air"));
floor_positions.push((position, "air")); } else if noise_value < 0.8 {
} else if noise_value < 0.8 { FloorTilePrefab::rock(position, &asset_server).spawn(&mut commands);
FloorTilePrefab::rock(position, &asset_server).spawn(&mut commands); tilemap
tilemap .floors
.floors .insert(pos_ivec, (2, true, false, 255, [0; 8])); // Rock tile
.insert(pos_ivec, (2, true, false, 255, [0; 8])); // Rock tile floor_positions.push((position, "rock"));
floor_positions.push((position, "rock"));
} else {
FloorTilePrefab::dirt(position, &asset_server).spawn(&mut commands);
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile
floor_positions.push((position, "dirt"));
}
} else { } else {
FloorTilePrefab::dirt(position, &asset_server).spawn(&mut commands); FloorTilePrefab::dirt(position, &asset_server).spawn(&mut commands);
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile
floor_positions.push((position, "dirt")); floor_positions.push((position, "dirt"));
} }
} else if noise_position.z < position.z { } else if noise_position.z > position.z {
if (generate_surface_noise(world_x, world_y) * TILE_SIZE).round()
<= position.z + TILE_SIZE
{
FloorTilePrefab::grass(position, &asset_server).spawn(&mut commands);
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile (grass)
floor_positions.push((position, "dirt"));
} else {
FloorTilePrefab::dirt(position, &asset_server).spawn(&mut commands);
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile
floor_positions.push((position, "dirt"));
}
} else {
FloorTilePrefab::air(position, &asset_server).spawn(&mut commands); FloorTilePrefab::air(position, &asset_server).spawn(&mut commands);
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
floor_positions.push((position, "air")); floor_positions.push((position, "air"));
} else {
FloorTilePrefab::grass(position, &asset_server).spawn(&mut commands);
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Grass tile
floor_positions.push((position, "dirt"));
} }
} }
} }
@@ -258,13 +270,24 @@ fn handle_chunk_loading(
} }
} }
fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
println!("setup_initial_chunks");
for x in -5..=5 {
for y in -5..=5 {
event_writer.send(LoadChunkEvent {
chunk_position: IVec2::new(x, y),
});
}
}
}
pub struct TilemapPlugin; pub struct TilemapPlugin;
impl Plugin for TilemapPlugin { impl Plugin for TilemapPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<ChunkMap>() app.init_resource::<ChunkMap>()
.add_event::<LoadChunkEvent>() .add_event::<LoadChunkEvent>()
.add_systems(Startup, setup_chunk_system) .add_systems(Startup, (setup_chunk_system, setup_initial_chunks))
.add_systems( .add_systems(
FixedUpdate, FixedUpdate,
(handle_chunk_loading, handle_tile_occlusion_updates).chain(), (handle_chunk_loading, handle_tile_occlusion_updates).chain(),