fix terrain z scrolling
This commit is contained in:
+22
-8
@@ -1,4 +1,6 @@
|
|||||||
use crate::{game, tiles};
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use crate::{game, tilemap, tiles};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_platform::collections::hash_map::HashMap;
|
use bevy_platform::collections::hash_map::HashMap;
|
||||||
|
|
||||||
@@ -56,13 +58,13 @@ pub fn camera_z_movement(
|
|||||||
camera_moved.0 = false;
|
camera_moved.0 = false;
|
||||||
if keyboard_input.just_pressed(KeyCode::ShiftLeft) {
|
if keyboard_input.just_pressed(KeyCode::ShiftLeft) {
|
||||||
z_index.0 -= 1.0;
|
z_index.0 -= 1.0;
|
||||||
z_index.0 = z_index.0.clamp(-149.0, 5.0);
|
z_index.0 = z_index.0.clamp(-tilemap::Z_BELOW + 1.0, tilemap::Z_ABOVE);
|
||||||
camera_moved.0 = true;
|
camera_moved.0 = true;
|
||||||
println!("z_index = {}", z_index.0);
|
println!("z_index = {}", z_index.0);
|
||||||
}
|
}
|
||||||
if keyboard_input.just_pressed(KeyCode::ShiftRight) {
|
if keyboard_input.just_pressed(KeyCode::ShiftRight) {
|
||||||
z_index.0 += 1.0;
|
z_index.0 += 1.0;
|
||||||
z_index.0 = z_index.0.clamp(-149.0, 5.0);
|
z_index.0 = z_index.0.clamp(-tilemap::Z_BELOW + 1.0, tilemap::Z_ABOVE);
|
||||||
camera_moved.0 = true;
|
camera_moved.0 = true;
|
||||||
println!("z_index = {}", z_index.0);
|
println!("z_index = {}", z_index.0);
|
||||||
}
|
}
|
||||||
@@ -74,13 +76,25 @@ pub struct TileMap {
|
|||||||
pub fixture_tiles: HashMap<IVec3, (u32, bool, [u32; 8])>,
|
pub fixture_tiles: HashMap<IVec3, (u32, bool, [u32; 8])>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO, redo
|
// This system updates sprite visibility based on current z-index
|
||||||
pub fn update_tile_visibility(
|
pub fn update_tile_visibility(
|
||||||
// z_index: ResMut<game::ZIndex>,
|
z_index: Res<game::ZIndex>,
|
||||||
mut cwss: ResMut<tiles::CurrentWorldSpriteState>,
|
mut query: Query<(&tiles::TerrainSprite, &mut Visibility)>,
|
||||||
) {
|
) {
|
||||||
cwss.state = tiles::WorldSpriteState::WaitingForRender;
|
let now = Instant::now();
|
||||||
// let z_index = (z_index.0 as i32 + 150) as usize;
|
|
||||||
|
let current_z = z_index.0 as isize;
|
||||||
|
|
||||||
|
// Update visibility for all terrain sprites
|
||||||
|
for (terrain_sprite, mut visibility) in query.iter_mut() {
|
||||||
|
*visibility =
|
||||||
|
if terrain_sprite.z_index == ((current_z + tilemap::Z_BELOW as isize) as usize) {
|
||||||
|
Visibility::Visible
|
||||||
|
} else {
|
||||||
|
Visibility::Hidden
|
||||||
|
};
|
||||||
|
}
|
||||||
|
println!("Visibility update: {:.2?}", now.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|||||||
+31
-33
@@ -1,12 +1,16 @@
|
|||||||
use crate::constants::{ITILE_SIZE, TILE_SIZE};
|
use crate::constants::{ITILE_SIZE, TILE_SIZE};
|
||||||
use crate::tile::{self, FixtureTile, FloorTile, NeedsOccluded, TileMap};
|
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileMap};
|
||||||
use crate::tiles::{self, FixtureTilePrefab, FloorTilePrefab};
|
use crate::tiles::{CurrentWorldSpriteState, FixtureTilePrefab, FloorTilePrefab, WorldSpriteState};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_platform::collections::hash_map::HashMap;
|
use bevy_platform::collections::hash_map::HashMap;
|
||||||
use noise::{NoiseFn, Perlin};
|
use noise::{NoiseFn, Perlin};
|
||||||
|
|
||||||
pub const CHUNK_SIZE: i32 = 8;
|
pub const CHUNK_SIZE: i32 = 8;
|
||||||
|
|
||||||
|
pub const Z_BELOW: f32 = 30.0;
|
||||||
|
pub const Z_ABOVE: f32 = 5.0;
|
||||||
|
pub const Z_TOTAL: f32 = Z_ABOVE + Z_BELOW;
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct ChunkMap {
|
pub struct ChunkMap {
|
||||||
pub loaded_chunks: HashMap<IVec2, bool>,
|
pub loaded_chunks: HashMap<IVec2, bool>,
|
||||||
@@ -38,7 +42,7 @@ pub fn handle_tile_occlusion_updates(
|
|||||||
Query<(&mut FixtureTile, &Transform, &mut NeedsOccluded)>,
|
Query<(&mut FixtureTile, &Transform, &mut NeedsOccluded)>,
|
||||||
Query<(Entity, &mut NeedsOccluded)>,
|
Query<(Entity, &mut NeedsOccluded)>,
|
||||||
)>,
|
)>,
|
||||||
mut cwss: ResMut<tiles::CurrentWorldSpriteState>,
|
mut cwss: ResMut<CurrentWorldSpriteState>,
|
||||||
) {
|
) {
|
||||||
query_set
|
query_set
|
||||||
.p0()
|
.p0()
|
||||||
@@ -69,13 +73,13 @@ pub fn handle_tile_occlusion_updates(
|
|||||||
commands.entity(entity).remove::<NeedsOccluded>();
|
commands.entity(entity).remove::<NeedsOccluded>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cwss.state = tiles::WorldSpriteState::WaitingForRender;
|
cwss.state = WorldSpriteState::WaitingForRender;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
||||||
let mut visible_range = [0u32; 8];
|
let mut visible_range = [0u32; 8];
|
||||||
|
|
||||||
for mut camera_z in -15..=5 {
|
for mut camera_z in -Z_BELOW as i32..=Z_ABOVE as i32 {
|
||||||
camera_z *= ITILE_SIZE;
|
camera_z *= ITILE_SIZE;
|
||||||
let mut is_visible = false;
|
let mut is_visible = false;
|
||||||
|
|
||||||
@@ -85,7 +89,7 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
|||||||
|
|
||||||
let mut is_occluded = false;
|
let mut is_occluded = false;
|
||||||
|
|
||||||
'vertical_check: for z_offset in 1..10 {
|
'vertical_check: for z_offset in 1..15 {
|
||||||
let above_pos = IVec3::new(pos.x, pos.y, pos.z + (z_offset * ITILE_SIZE));
|
let above_pos = IVec3::new(pos.x, pos.y, pos.z + (z_offset * ITILE_SIZE));
|
||||||
if above_pos.z <= camera_z {
|
if above_pos.z <= camera_z {
|
||||||
if let Some(&(_, opaque, _, _, _)) = tilemap.floor_tiles.get(&above_pos) {
|
if let Some(&(_, opaque, _, _, _)) = tilemap.floor_tiles.get(&above_pos) {
|
||||||
@@ -94,16 +98,6 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
|||||||
break 'vertical_check;
|
break 'vertical_check;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if z_offset >= 4 {
|
|
||||||
// is_occluded = true;
|
|
||||||
// break 'vertical_check;
|
|
||||||
// }
|
|
||||||
// if let Some(&(_, solid, _)) = tilemap.fixtures.get(&above_pos) {
|
|
||||||
// if solid {
|
|
||||||
// is_occluded = true;
|
|
||||||
// break 'vertical_check;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
break 'vertical_check;
|
break 'vertical_check;
|
||||||
}
|
}
|
||||||
@@ -127,19 +121,13 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
|||||||
break 'neighbor_check;
|
break 'neighbor_check;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if let Some(&(id, _, _)) = tilemap.fixtures.get(&neighbor_pos) {
|
|
||||||
// if id == 0 {
|
|
||||||
// is_visible = true;
|
|
||||||
// break 'neighbor_check;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_visible {
|
if is_visible {
|
||||||
let z2 = ((camera_z / ITILE_SIZE) + 150) as usize;
|
let z2 = ((camera_z / ITILE_SIZE) + Z_BELOW as i32) as usize;
|
||||||
visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32);
|
visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +146,6 @@ pub fn generate_surface_noise(x: i32, y: i32) -> f32 {
|
|||||||
amplitude *= 0.6;
|
amplitude *= 0.6;
|
||||||
frequency *= 1.8;
|
frequency *= 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
(noise_value * 2.5) as f32
|
(noise_value * 2.5) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +155,7 @@ fn generate_chunks_from_algo(
|
|||||||
mut chunk_map: ResMut<ChunkMap>,
|
mut chunk_map: ResMut<ChunkMap>,
|
||||||
mut tilemap: ResMut<TileMap>,
|
mut tilemap: ResMut<TileMap>,
|
||||||
) {
|
) {
|
||||||
let noise = Perlin::new(0);
|
let cave_noise = Perlin::new(0);
|
||||||
|
|
||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
println!("Loading chunk {}", event.chunk_position);
|
println!("Loading chunk {}", event.chunk_position);
|
||||||
@@ -197,7 +184,7 @@ fn generate_chunks_from_algo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Spawn tiles and add them to tilemap
|
// Spawn tiles and add them to tilemap
|
||||||
for z in -10..=5 {
|
for z in -Z_BELOW as isize..=Z_ABOVE as isize {
|
||||||
let position = Vec3::new(
|
let 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(),
|
||||||
@@ -206,7 +193,7 @@ fn generate_chunks_from_algo(
|
|||||||
let pos_ivec = position.as_ivec3();
|
let pos_ivec = position.as_ivec3();
|
||||||
|
|
||||||
if z < -8 {
|
if z < -8 {
|
||||||
let noise_value = noise.get([
|
let noise_value = cave_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,
|
||||||
@@ -295,6 +282,22 @@ fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn index_z_to_absolute_z(z: f32) -> f32 {
|
||||||
|
z + Z_BELOW
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn world_z_to_absolute_z(z: f32) -> f32 {
|
||||||
|
z + Z_BELOW * ITILE_SIZE as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn absolute_z_to_index_z(z: f32) -> f32 {
|
||||||
|
z - Z_BELOW
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn absolute_z_to_world_z(z: f32) -> f32 {
|
||||||
|
z - Z_BELOW * ITILE_SIZE as f32
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TilemapPlugin;
|
pub struct TilemapPlugin;
|
||||||
|
|
||||||
impl Plugin for TilemapPlugin {
|
impl Plugin for TilemapPlugin {
|
||||||
@@ -304,12 +307,7 @@ impl Plugin for TilemapPlugin {
|
|||||||
.add_systems(Startup, (setup_chunk_system, setup_initial_chunks))
|
.add_systems(Startup, (setup_chunk_system, setup_initial_chunks))
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PostStartup,
|
PostStartup,
|
||||||
(
|
(generate_chunks_from_algo, handle_tile_occlusion_updates).chain(),
|
||||||
generate_chunks_from_algo,
|
|
||||||
handle_tile_occlusion_updates,
|
|
||||||
tile::update_tile_visibility,
|
|
||||||
)
|
|
||||||
.chain(),
|
|
||||||
)
|
)
|
||||||
.add_systems(FixedUpdate, (generate_chunks_from_algo).chain());
|
.add_systems(FixedUpdate, (generate_chunks_from_algo).chain());
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-17
@@ -1,5 +1,5 @@
|
|||||||
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileState};
|
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileState};
|
||||||
use crate::{constants::*, game};
|
use crate::{constants::*, game, tilemap};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_platform::collections::hash_map::HashMap;
|
use bevy_platform::collections::hash_map::HashMap;
|
||||||
|
|
||||||
@@ -92,34 +92,34 @@ pub struct CurrentWorldSpriteState {
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct TerrainSprite;
|
pub struct TerrainSprite {
|
||||||
|
pub z_index: usize, // Store the z-index this sprite belongs to (as world_Z)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: re-rendering on z-index change is inefficient, replace with shifting pool system for z-index change
|
// This system generates sprites for all z-indices and stores references to them
|
||||||
pub fn build_world_sprites(
|
pub fn build_world_sprites(
|
||||||
mut query: Query<(&FloorTile, &Transform)>,
|
query: Query<(&FloorTile, &Transform)>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut cwss: ResMut<CurrentWorldSpriteState>,
|
mut cwss: ResMut<CurrentWorldSpriteState>,
|
||||||
textures: Res<Textures>,
|
textures: Res<Textures>,
|
||||||
texture_ids: Res<TextureIDs>,
|
texture_ids: Res<TextureIDs>,
|
||||||
z_index: ResMut<game::ZIndex>,
|
|
||||||
query_1: Query<Entity, With<TerrainSprite>>,
|
query_1: Query<Entity, With<TerrainSprite>>,
|
||||||
) {
|
) {
|
||||||
if cwss.state != WorldSpriteState::WaitingForRender {
|
if cwss.state != WorldSpriteState::WaitingForRender {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// despawn all query_1 entities
|
let now = Instant::now();
|
||||||
|
cwss.state = WorldSpriteState::InProgress;
|
||||||
|
|
||||||
|
// despawn all existing terrain sprites
|
||||||
for entity in query_1.iter() {
|
for entity in query_1.iter() {
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = Instant::now();
|
// Generate sprites for all z-indices (0 to 150)
|
||||||
if cwss.state == WorldSpriteState::WaitingForRender {
|
for z_index in 0..=tilemap::Z_TOTAL as usize {
|
||||||
cwss.state = WorldSpriteState::InProgress;
|
for (floortile, transform) in query.iter() {
|
||||||
let z_index = (z_index.0 as i32 + 150) as usize;
|
|
||||||
println!("z_index = {}", z_index);
|
|
||||||
|
|
||||||
for (floortile, transform) in query.iter_mut() {
|
|
||||||
let is_visible =
|
let is_visible =
|
||||||
(floortile.visible_range[z_index / 32] & (1 << (z_index % 32) as u32)) != 0;
|
(floortile.visible_range[z_index / 32] & (1 << (z_index % 32) as u32)) != 0;
|
||||||
if is_visible {
|
if is_visible {
|
||||||
@@ -130,14 +130,23 @@ pub fn build_world_sprites(
|
|||||||
image: texture.clone(),
|
image: texture.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
commands.spawn((sprite, *transform, TerrainSprite));
|
|
||||||
|
// Spawn with hidden visibility initially - update_tile_visibility will handle showing/hiding
|
||||||
|
commands.spawn((
|
||||||
|
sprite,
|
||||||
|
*transform,
|
||||||
|
TerrainSprite { z_index },
|
||||||
|
Visibility::Hidden,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cwss.state = WorldSpriteState::RenderReady;
|
|
||||||
}
|
}
|
||||||
println!("{:?}", cwss.state);
|
|
||||||
|
cwss.state = WorldSpriteState::RenderReady;
|
||||||
|
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
println!("Elapsed: {:.2?}", elapsed);
|
|
||||||
|
println!("World sprites built. Elapsed: {:.2?}", elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
|
|||||||
Reference in New Issue
Block a user