Chunking 3
This commit is contained in:
+22
-25
@@ -1,7 +1,4 @@
|
||||
use crate::{
|
||||
constants::{self, *},
|
||||
tilemap,
|
||||
};
|
||||
use crate::constants::*;
|
||||
use bevy::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(
|
||||
query: Query<&Transform, With<Ambulatory>>,
|
||||
chunk_map: Res<tilemap::ChunkMap>,
|
||||
mut event_writer: EventWriter<tilemap::LoadChunkEvent>,
|
||||
) {
|
||||
for transform in query.iter() {
|
||||
let position = transform.translation;
|
||||
// pub fn check_citizen_positions_for_chunks(
|
||||
// query: Query<&Transform, With<Ambulatory>>,
|
||||
// chunk_map: Res<tilemap::ChunkMap>,
|
||||
// mut event_writer: EventWriter<tilemap::LoadChunkEvent>,
|
||||
// ) {
|
||||
// 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;
|
||||
// // 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);
|
||||
// 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,
|
||||
// // });
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
-173
@@ -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 noise::{NoiseFn, Perlin};
|
||||
use rand::prelude::*;
|
||||
|
||||
#[derive(Resource)]
|
||||
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
@@ -1,12 +1,12 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(Sprite,Transform,Visibility )]
|
||||
#[require(Sprite, Transform, Visibility)]
|
||||
pub struct Item {
|
||||
wear: u8,
|
||||
quality: u8,
|
||||
weight: u8,
|
||||
stain_time: u16
|
||||
stain_time: u16,
|
||||
}
|
||||
|
||||
impl Default for Item {
|
||||
@@ -33,12 +33,12 @@ pub struct ItemBundle {
|
||||
pub item: Item,
|
||||
pub transform: Transform,
|
||||
pub sprite: Sprite,
|
||||
pub visibility: Visibility
|
||||
pub visibility: Visibility,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Nameable {
|
||||
pub name: String
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
|
||||
+2
-46
@@ -29,10 +29,9 @@ fn main() {
|
||||
.add_systems(
|
||||
Startup,
|
||||
(
|
||||
setup_initial_chunks,
|
||||
camera::spawn_panning_camera,
|
||||
cursor::setup_cursor,
|
||||
citizen::spawn_citizens, // New citizen spawning system
|
||||
citizen::spawn_citizens,
|
||||
),
|
||||
)
|
||||
.add_systems(
|
||||
@@ -41,8 +40,7 @@ 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
|
||||
// citizen::check_citizen_positions_for_chunks,
|
||||
),
|
||||
)
|
||||
.init_resource::<tile::CameraMoved>()
|
||||
@@ -56,45 +54,3 @@ fn main() {
|
||||
)
|
||||
.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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
use crate::constants::TILE_SIZE;
|
||||
use crate::game;
|
||||
use crate::tilemap::ChunkMap;
|
||||
use bevy::ecs::system::ParamSet;
|
||||
use bevy::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
@@ -52,7 +50,6 @@ impl Default for FixtureTile {
|
||||
#[derive(Resource, Default)]
|
||||
pub struct CameraMoved(pub bool);
|
||||
|
||||
// Modify camera_z_movement
|
||||
pub fn camera_z_movement(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut z_index: ResMut<game::ZIndex>,
|
||||
|
||||
+60
-37
@@ -1,5 +1,5 @@
|
||||
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 bevy::prelude::*;
|
||||
use noise::{NoiseFn, Perlin};
|
||||
@@ -30,7 +30,7 @@ fn setup_chunk_system(mut commands: Commands) {
|
||||
commands.insert_resource(ChunkMap::default());
|
||||
}
|
||||
|
||||
// System to handle individual tile occlusion updates
|
||||
// System to handle tile occlusion updates
|
||||
pub fn handle_tile_occlusion_updates(
|
||||
mut commands: Commands,
|
||||
tilemap: Res<TileMap>,
|
||||
@@ -144,6 +144,22 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
||||
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(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
@@ -173,16 +189,10 @@ 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 combined_noise_value = noise_value_a + noise_value_b;
|
||||
|
||||
let noise_position = Vec3::new(
|
||||
(world_x 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
|
||||
@@ -194,41 +204,43 @@ fn handle_chunk_loading(
|
||||
);
|
||||
let pos_ivec = position.as_ivec3();
|
||||
|
||||
if noise_position.z > position.z {
|
||||
if z < -8 {
|
||||
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 {
|
||||
FloorTilePrefab::air(position, &asset_server).spawn(&mut commands);
|
||||
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
|
||||
floor_positions.push((position, "air"));
|
||||
} else if noise_value < 0.8 {
|
||||
FloorTilePrefab::rock(position, &asset_server).spawn(&mut commands);
|
||||
tilemap
|
||||
.floors
|
||||
.insert(pos_ivec, (2, true, false, 255, [0; 8])); // Rock tile
|
||||
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"));
|
||||
}
|
||||
if z < -8 {
|
||||
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 {
|
||||
FloorTilePrefab::air(position, &asset_server).spawn(&mut commands);
|
||||
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
|
||||
floor_positions.push((position, "air"));
|
||||
} else if noise_value < 0.8 {
|
||||
FloorTilePrefab::rock(position, &asset_server).spawn(&mut commands);
|
||||
tilemap
|
||||
.floors
|
||||
.insert(pos_ivec, (2, true, false, 255, [0; 8])); // Rock tile
|
||||
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 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);
|
||||
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
|
||||
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;
|
||||
|
||||
impl Plugin for TilemapPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<ChunkMap>()
|
||||
.add_event::<LoadChunkEvent>()
|
||||
.add_systems(Startup, setup_chunk_system)
|
||||
.add_systems(Startup, (setup_chunk_system, setup_initial_chunks))
|
||||
.add_systems(
|
||||
FixedUpdate,
|
||||
(handle_chunk_loading, handle_tile_occlusion_updates).chain(),
|
||||
|
||||
Reference in New Issue
Block a user