fix: correct boundary z-marking and tileset_index swap in recolor

Boundary: mark all z-levels where z_diff changed, not just 4 boundary
indices. For multi-step scrolls, every z-level between
min(old,new)-8 and max(old,new) inclusive needs recoloring.
Also fixes last_z_change_dirty_count to use actual new_keys.len().

Recolor: update tileset_index alongside color so sky tile switch at
t>=0.98 actually renders the sky texture, not sky-coloured grass.

Cleanup: removed solid_bits (was unused after recolor fix).
This commit is contained in:
2026-03-20 15:28:17 +00:00
parent 4c14f79cd2
commit 0d73311c68
+14 -42
View File
@@ -39,7 +39,6 @@ impl Default for TilemapChunkRegistry {
#[derive(Resource, Default)]
pub struct TilemapChunkStates {
pub solid_bits: HashMap<ChunkLayerKey, u64>,
pub underground_bits: HashMap<ChunkLayerKey, u64>,
}
@@ -203,17 +202,18 @@ fn populate_chunk_tiles(
fn recolor_chunk_for_depth(
tile_data: &mut TilemapChunkTileData,
z_diff: i32,
solid_bits: u64,
underground_bits: u64,
) {
for (i, slot) in tile_data.0.iter_mut().enumerate() {
let Some(td) = slot else { continue };
let is_underground = (underground_bits >> i) & 1 == 1;
td.color = if is_underground {
Color::BLACK
if is_underground {
td.color = Color::BLACK;
} else {
tile_fade_color(td.tileset_index, z_diff)
};
let recomputed = tile_for_depth(td.tileset_index, z_diff);
td.tileset_index = recomputed.tileset_index;
td.color = recomputed.color;
}
}
}
@@ -250,7 +250,6 @@ pub fn spawn_tilemap_chunks(
registry.entities.clear();
registry.dirty_keys.clear();
registry.z_change_keys.clear();
states.solid_bits.clear();
states.underground_bits.clear();
spawner.started = true;
}
@@ -269,8 +268,6 @@ pub fn spawn_tilemap_chunks(
let (tile_data, underground_bits) = if key.layer == LAYER_FLOOR {
let (tiles, ub) = populate_chunk_tiles(&tilemap, key.chunk_pos, key.z_index, camera_z);
let solid_bits = compute_solid_bits(&tiles);
states.solid_bits.insert(key, solid_bits);
states.underground_bits.insert(key, ub);
(tiles, ub)
} else {
@@ -317,18 +314,6 @@ pub fn spawn_tilemap_chunks(
bench.populate_ms += now.elapsed().as_secs_f64() * 1000.0;
}
fn compute_solid_bits(tiles: &[Option<TileData>]) -> u64 {
let mut bits: u64 = 0;
for (i, slot) in tiles.iter().enumerate() {
if let Some(td) = slot {
if td.tileset_index != 0 {
bits |= 1u64 << i;
}
}
}
bits
}
pub fn update_tilemap_chunk_visibility(
z_index: Res<ZIndex>,
mut query: Query<(&ChunkLayerKey, &mut Visibility)>,
@@ -390,9 +375,8 @@ pub fn populate_tilemap_chunk_data(
continue;
}
let solid_bits = states.solid_bits.get(&key).copied().unwrap_or(0);
let underground_bits = states.underground_bits.get(&key).copied().unwrap_or(0);
recolor_chunk_for_depth(&mut tile_data, z_diff, solid_bits, underground_bits);
recolor_chunk_for_depth(&mut tile_data, z_diff, underground_bits);
processed += 1;
}
@@ -432,8 +416,6 @@ pub fn populate_tilemap_chunk_data(
let (new_tiles, underground_bits) =
populate_chunk_tiles(&tilemap, key.chunk_pos, key.z_index, camera_z);
let solid_bits = compute_solid_bits(&new_tiles);
states.solid_bits.insert(key, solid_bits);
states.underground_bits.insert(key, underground_bits);
tile_data.0 = new_tiles;
processed += 1;
@@ -465,37 +447,28 @@ pub fn on_camera_z_changed(
let now = Instant::now();
let old_entered_idx = (old_camera_z as f32 + Z_BELOW) as usize;
let old_exited_idx = ((old_camera_z - 8) as f32 + Z_BELOW) as usize;
let new_entered_idx = (new_camera_z as f32 + Z_BELOW) as usize;
let new_exited_idx = ((new_camera_z - 8) as f32 + Z_BELOW) as usize;
let mut count = 0;
let z_min = (new_camera_z.min(old_camera_z) - 8).max(0);
let z_max = new_camera_z.max(old_camera_z);
let mut new_keys: Vec<ChunkLayerKey> = Vec::new();
for key in registry.entities.keys() {
if key.z_index == old_entered_idx
|| key.z_index == new_entered_idx
|| key.z_index == old_exited_idx
|| key.z_index == new_exited_idx
{
let tile_z = camera_z_for_z_index(key.z_index);
if tile_z >= z_min && tile_z <= z_max {
new_keys.push(*key);
count += 1;
}
}
bench.last_z_change_dirty_ms = now.elapsed().as_secs_f64() * 1000.0;
bench.last_z_change_dirty_count = new_keys.len();
if !new_keys.is_empty() {
registry.z_change_keys.clear();
for key in new_keys {
registry.z_change_keys.insert(key);
}
}
bench.last_z_change_dirty_ms = now.elapsed().as_secs_f64() * 1000.0;
bench.last_z_change_dirty_count = count;
}
pub fn despawn_tilemap_chunks(
mut commands: Commands,
chunk_map: Res<super::super::chunks::ChunkMap>,
@@ -511,7 +484,6 @@ pub fn despawn_tilemap_chunks(
registry.entities.remove(key);
registry.dirty_keys.remove(key);
registry.z_change_keys.remove(key);
states.solid_bits.remove(key);
states.underground_bits.remove(key);
}
}