chunk2?
This commit is contained in:
+6
-6
@@ -88,11 +88,11 @@ pub fn check_citizen_positions_for_chunks(
|
|||||||
|
|
||||||
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,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-12
@@ -1,7 +1,5 @@
|
|||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use camera::PanningCamera;
|
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
mod citizen;
|
mod citizen;
|
||||||
@@ -29,6 +27,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0)))
|
.insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0)))
|
||||||
.add_plugins(tilemap::TilemapPlugin)
|
.add_plugins(tilemap::TilemapPlugin)
|
||||||
|
.add_plugins(tilemap::OcclusionPlugin)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
(
|
(
|
||||||
@@ -38,15 +37,6 @@ fn main() {
|
|||||||
citizen::spawn_citizens, // New citizen spawning system
|
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(
|
.add_systems(
|
||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
(
|
(
|
||||||
@@ -70,10 +60,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_initial_chunks(mut event_writer: EventWriter<tilemap::LoadChunkEvent>) {
|
fn setup_initial_chunks(mut event_writer: EventWriter<tilemap::LoadChunkEvent>) {
|
||||||
|
println!("setup_initial_chunks");
|
||||||
// Spawn a 3x3 grid of chunks around the origin
|
// Spawn a 3x3 grid of chunks around the origin
|
||||||
for x in -1..=1 {
|
for x in -1..=1 {
|
||||||
for y in -1..=1 {
|
for y in -1..=1 {
|
||||||
println!("setup_initial_chunks: x = {}, y = {}", x, y);
|
|
||||||
event_writer.send(tilemap::LoadChunkEvent {
|
event_writer.send(tilemap::LoadChunkEvent {
|
||||||
chunk_position: IVec2::new(x, y),
|
chunk_position: IVec2::new(x, y),
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-135
@@ -1,5 +1,6 @@
|
|||||||
use crate::constants::TILE_SIZE;
|
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;
|
||||||
@@ -73,140 +74,6 @@ pub struct TileMap {
|
|||||||
pub fixtures: HashMap<IVec3, (u32, bool, [u32; 8])>,
|
pub fixtures: HashMap<IVec3, (u32, bool, [u32; 8])>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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<TileMap>,
|
|
||||||
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(
|
pub fn update_tile_visibility(
|
||||||
z_index: ResMut<game::ZIndex>,
|
z_index: ResMut<game::ZIndex>,
|
||||||
mut query_set: ParamSet<(
|
mut query_set: ParamSet<(
|
||||||
@@ -214,7 +81,6 @@ pub fn update_tile_visibility(
|
|||||||
Query<(&FixtureTile, &mut Visibility)>,
|
Query<(&FixtureTile, &mut Visibility)>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
println!("update_tile_visibility");
|
|
||||||
|
|
||||||
let z_index = (z_index.0 as i32 + 150) as usize;
|
let z_index = (z_index.0 as i32 + 150) as usize;
|
||||||
|
|
||||||
|
|||||||
+234
-99
@@ -1,12 +1,11 @@
|
|||||||
use crate::constants::TILE_SIZE;
|
use crate::constants::TILE_SIZE;
|
||||||
|
use crate::tile::{FixtureTile, FloorTile, 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};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
pub const CHUNK_SIZE: i32 = 8;
|
pub const CHUNK_SIZE: i32 = 8;
|
||||||
pub const CHUNK_HEIGHT: i32 = 200;
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct ChunkMap {
|
pub struct ChunkMap {
|
||||||
@@ -27,28 +26,150 @@ pub struct LoadChunkEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_chunk_system(mut commands: Commands) {
|
fn setup_chunk_system(mut commands: Commands) {
|
||||||
|
commands.insert_resource(TileMap::default());
|
||||||
commands.insert_resource(ChunkMap::default());
|
commands.insert_resource(ChunkMap::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct ChunkOcclusionEvent {
|
||||||
|
pub chunk_pos: IVec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct TileOcclusionUpdateEvent {
|
||||||
|
pub positions: Vec<IVec3>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// System to handle individual tile occlusion updates
|
||||||
|
fn handle_tile_occlusion_updates(
|
||||||
|
mut events: EventReader<TileOcclusionUpdateEvent>,
|
||||||
|
tilemap: Res<TileMap>,
|
||||||
|
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(
|
fn handle_chunk_loading(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
mut events: EventReader<LoadChunkEvent>,
|
mut events: EventReader<LoadChunkEvent>,
|
||||||
mut chunk_map: ResMut<ChunkMap>,
|
mut chunk_map: ResMut<ChunkMap>,
|
||||||
|
mut tilemap: ResMut<TileMap>,
|
||||||
|
mut occlusion_events: EventWriter<ChunkOcclusionEvent>,
|
||||||
) {
|
) {
|
||||||
let noise = Perlin::new(0);
|
let noise = Perlin::new(0);
|
||||||
|
|
||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
let chunk_pos = event.chunk_position;
|
let chunk_pos = event.chunk_position;
|
||||||
// Skip if chunk is already loaded
|
|
||||||
if chunk_map.loaded_chunks.contains_key(&chunk_pos) {
|
if chunk_map.loaded_chunks.contains_key(&chunk_pos) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark chunk as loaded
|
|
||||||
chunk_map.loaded_chunks.insert(chunk_pos, true);
|
chunk_map.loaded_chunks.insert(chunk_pos, true);
|
||||||
|
|
||||||
// Calculate world space coordinates for chunk
|
|
||||||
let start_x = chunk_pos.x * CHUNK_SIZE;
|
let start_x = chunk_pos.x * CHUNK_SIZE;
|
||||||
let start_y = chunk_pos.y * 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_x = start_x + local_x;
|
||||||
let world_y = start_y + local_y;
|
let world_y = start_y + local_y;
|
||||||
|
|
||||||
let noise_value_a =
|
let noise_value_a = noise.get([world_x as f64 * 0.01, world_y as f64 * 0.01]) * 1.25;
|
||||||
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_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 combined_noise_value = noise_value_a + noise_value_b;
|
||||||
|
|
||||||
let noise_position = Vec3::new(
|
let noise_position = Vec3::new(
|
||||||
@@ -71,112 +190,113 @@ fn handle_chunk_loading(
|
|||||||
(world_y as f32 * TILE_SIZE).round(),
|
(world_y as f32 * TILE_SIZE).round(),
|
||||||
(combined_noise_value * 4.).round() as f32 * TILE_SIZE,
|
(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
|
// Spawn tiles and add them to tilemap
|
||||||
generate_fixtures_for_chunk(&mut commands, &asset_server, &floor_positions);
|
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(
|
if noise_position.z > position.z {
|
||||||
commands: &mut Commands,
|
if z < -15 {
|
||||||
asset_server: &Res<AssetServer>,
|
let noise_value = noise.get([world_x as f64 * 0.05, world_y as f64 * 0.05, z as f64 * 0.05]);
|
||||||
x: i32,
|
if noise_value < -0.5 {
|
||||||
y: i32,
|
commands.spawn(FloorTilePrefab::air(position, &asset_server));
|
||||||
noise: &Perlin,
|
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
|
||||||
noise_position: Vec3,
|
floor_positions.push((position, "air"));
|
||||||
floor_positions: &mut Vec<(Vec3, &'static str)>,
|
} else if noise_value < 0.8 {
|
||||||
) {
|
commands.spawn(FloorTilePrefab::rock(position, &asset_server));
|
||||||
for z in -150..50 {
|
tilemap.floors.insert(pos_ivec, (2, true, false, 255, [0; 8])); // Rock tile
|
||||||
let position = Vec3::new(
|
floor_positions.push((position, "rock"));
|
||||||
(x as f32 * TILE_SIZE).round(),
|
} else {
|
||||||
(y as f32 * TILE_SIZE).round(),
|
commands.spawn(FloorTilePrefab::dirt(position, &asset_server));
|
||||||
(z as f32 * TILE_SIZE).round(),
|
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile
|
||||||
);
|
floor_positions.push((position, "dirt"));
|
||||||
|
}
|
||||||
let floor_type = if noise_position.z > position.z {
|
} else {
|
||||||
if z < -15 {
|
commands.spawn(FloorTilePrefab::dirt(position, &asset_server));
|
||||||
let noise_value = noise.get([x as f64 * 0.05, y as f64 * 0.05, z as f64 * 0.05]);
|
tilemap.floors.insert(pos_ivec, (1, true, true, 1, [0; 8])); // Dirt tile
|
||||||
if noise_value < -0.5 {
|
floor_positions.push((position, "dirt"));
|
||||||
spawn_tile(commands, FloorTilePrefab::air(position, asset_server));
|
}
|
||||||
Some("air")
|
} else if noise_position.z < position.z {
|
||||||
} else if noise_value < 0.8 {
|
commands.spawn(FloorTilePrefab::air(position, &asset_server));
|
||||||
spawn_tile(commands, FloorTilePrefab::rock(position, asset_server));
|
tilemap.floors.insert(pos_ivec, (0, false, true, 1, [0; 8])); // Air tile
|
||||||
Some("rock")
|
floor_positions.push((position, "air"));
|
||||||
} else {
|
} else {
|
||||||
spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server));
|
commands.spawn(FloorTilePrefab::dirt(position, &asset_server));
|
||||||
Some("dirt")
|
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 {
|
// Generate fixtures and add them to tilemap
|
||||||
commands.spawn(bundle).id()
|
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(
|
match *floor_type {
|
||||||
commands: &mut Commands,
|
|
||||||
asset_server: &Res<AssetServer>,
|
|
||||||
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 {
|
|
||||||
"dirt" => {
|
"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" => {
|
"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" => {
|
"bedrock" => {
|
||||||
commands.spawn(FixtureTilePrefab::bedrock_wall(
|
commands.spawn(FixtureTilePrefab::bedrock_wall(above_pos, &asset_server));
|
||||||
fixture_position,
|
tilemap.fixtures.insert(above_ivec, (3, true, [0; 8])); // Bedrock wall
|
||||||
asset_server,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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<ChunkOcclusionEvent>,
|
||||||
|
tilemap: Res<TileMap>,
|
||||||
|
mut tile_update_events: EventWriter<TileOcclusionUpdateEvent>,
|
||||||
|
) {
|
||||||
|
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);
|
.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::<ChunkOcclusionEvent>()
|
||||||
|
.add_event::<TileOcclusionUpdateEvent>()
|
||||||
|
.add_systems(Update, (
|
||||||
|
handle_chunk_occlusion_events,
|
||||||
|
handle_tile_occlusion_updates,
|
||||||
|
).chain());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ pub struct FloorTilePrefab {
|
|||||||
sprite: Sprite,
|
sprite: Sprite,
|
||||||
tile: FloorTile,
|
tile: FloorTile,
|
||||||
tile_state: TileState,
|
tile_state: TileState,
|
||||||
|
visibility: Visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloorTilePrefab {
|
impl FloorTilePrefab {
|
||||||
@@ -25,6 +26,7 @@ impl FloorTilePrefab {
|
|||||||
tile_state: TileState {
|
tile_state: TileState {
|
||||||
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +44,7 @@ impl FloorTilePrefab {
|
|||||||
tile_state: TileState {
|
tile_state: TileState {
|
||||||
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +63,7 @@ impl FloorTilePrefab {
|
|||||||
tile_state: TileState {
|
tile_state: TileState {
|
||||||
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +81,7 @@ impl FloorTilePrefab {
|
|||||||
tile_state: TileState {
|
tile_state: TileState {
|
||||||
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
timer: Timer::from_seconds(1.0, TimerMode::Repeating),
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +91,7 @@ pub struct FixtureTilePrefab {
|
|||||||
transform: Transform,
|
transform: Transform,
|
||||||
sprite: Sprite,
|
sprite: Sprite,
|
||||||
tile: FixtureTile,
|
tile: FixtureTile,
|
||||||
|
visibility: Visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FixtureTilePrefab {
|
impl FixtureTilePrefab {
|
||||||
@@ -100,6 +106,7 @@ impl FixtureTilePrefab {
|
|||||||
id: 1,
|
id: 1,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +121,7 @@ impl FixtureTilePrefab {
|
|||||||
id: 2,
|
id: 2,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +136,7 @@ impl FixtureTilePrefab {
|
|||||||
id: 0,
|
id: 0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
visibility: Visibility::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user