Files
dorf/src/tile.rs
T
2024-12-29 19:03:26 +00:00

321 lines
9.5 KiB
Rust

use crate::constants::TILE_SIZE;
use crate::game;
use crate::item::Item;
use bevy::ecs::system::ParamSet;
use bevy::prelude::*;
use std::collections::HashMap;
#[derive(Component, Clone)]
#[require(Sprite)]
pub struct FloorTile {
pub id: u32,
pub opaque: bool,
pub walkable: bool,
pub astar_weight: u8,
pub visible_range: [u32; 8],
}
impl Default for FloorTile {
fn default() -> Self {
Self {
id: 0,
opaque: true,
walkable: true,
astar_weight: 0,
visible_range: [0; 8],
}
}
}
#[derive(Component, Clone)]
pub struct FixtureTile {
pub id: u32,
pub solid: bool,
pub visible_range: [u32; 8],
}
impl Default for FixtureTile {
fn default() -> Self {
Self {
id: 0,
solid: true,
visible_range: [0; 8],
}
}
}
#[derive(Component, Clone)]
pub struct ConnectedTexture {
}
#[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>,
mut camera_moved: ResMut<CameraMoved>,
) {
camera_moved.0 = false;
if keyboard_input.just_pressed(KeyCode::ShiftLeft) {
z_index.0 -= 1.0;
z_index.0 = z_index.0.clamp(-149.0, 5.0);
camera_moved.0 = true;
println!("z_index = {}", z_index.0);
}
if keyboard_input.just_pressed(KeyCode::ShiftRight) {
z_index.0 += 1.0;
z_index.0 = z_index.0.clamp(-149.0, 5.0);
camera_moved.0 = true;
println!("z_index = {}", z_index.0);
}
}
pub fn tile_sprite_generate_occlusion_map(
mut query_set: ParamSet<(
Query<(&Transform, &FloorTile)>,
Query<(&Transform, &FixtureTile)>,
Query<(&mut FloorTile, &Transform)>,
Query<(&mut FixtureTile, &Transform)>,
)>,
) {
// Create the tile map using floor query
let floor_tile_map: HashMap<(i32, i32, i32), (bool, u32)> = {
let mut map = HashMap::new();
query_set.p0().iter().for_each(|(transform, tile)| {
map.insert(
(
transform.translation.x as i32,
transform.translation.y as i32,
transform.translation.z as i32,
),
(tile.opaque, tile.id),
);
});
map
};
// Create the tile map using fixture query
let fixture_tile_map: HashMap<(i32, i32, i32), (bool, u32)> = {
let mut map = HashMap::new();
query_set.p1().iter().for_each(|(transform, tile)| {
map.insert(
(
transform.translation.x as i32,
transform.translation.y as i32,
transform.translation.z as i32,
),
(tile.solid, tile.id),
);
});
map
};
let tile_size = TILE_SIZE as i32;
// Helper function to calculate visibility
let calculate_visibility =
|pos: (i32, i32, i32), tile_map: &HashMap<(i32, i32, i32), (bool, u32)>| {
let mut visible_range = [0u32; 8];
for mut camera_z in -150..100 {
camera_z *= tile_size;
let mut is_visible = false;
if pos.2 > camera_z {
continue;
}
let mut is_occluded = false;
'vertical_check: for z_offset in 1..=35 {
// check above
let above_pos = (pos.0, pos.1, pos.2 + (z_offset * tile_size));
if above_pos.2 <= camera_z {
if let Some(&(is_opaque, _)) = tile_map.get(&above_pos) {
if is_opaque {
is_occluded = true;
break 'vertical_check;
}
}
} else {
break 'vertical_check;
}
}
if !is_occluded {
let base_pos = (pos.0, pos.1, pos.2);
'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 = (
base_pos.0 + x_offset * tile_size,
base_pos.1 + y_offset * tile_size,
base_pos.2 + z_offset * tile_size,
);
if let Some(&(_, id)) = tile_map.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
.p2()
.par_iter_mut()
.for_each(|(mut tile, transform)| {
let pos = (
transform.translation.x as i32,
transform.translation.y as i32,
transform.translation.z as i32,
);
tile.visible_range = calculate_visibility(pos, &floor_tile_map);
});
// Update fixture tiles
query_set
.p3()
.par_iter_mut()
.for_each(|(mut fixture, transform)| {
let pos = (
transform.translation.x as i32,
transform.translation.y as i32,
transform.translation.z as i32 - 1,
);
fixture.visible_range = calculate_visibility(pos, &fixture_tile_map);
});
}
pub fn update_tile_visibility(
z_index: ResMut<game::ZIndex>,
mut query_set: ParamSet<(
Query<(&FloorTile, &mut Visibility)>,
Query<(&FixtureTile, &mut Visibility)>,
)>,
) {
let z_index = (z_index.0 as i32 + 150) as usize;
// Update floor visibility
query_set
.p0()
.par_iter_mut()
.for_each(|(tile, mut visibility)| {
let is_visible = (tile.visible_range[z_index / 32] & (1 << (z_index % 32) as u32)) != 0;
*visibility = if is_visible {
Visibility::Visible
} else {
Visibility::Hidden
};
});
// Update fixture visibility
query_set
.p1()
.par_iter_mut()
.for_each(|(fixture, mut visibility)| {
let is_visible =
(fixture.visible_range[z_index / 32] & (1 << (z_index % 32) as u32)) != 0;
*visibility = if is_visible {
Visibility::Visible
} else {
Visibility::Hidden
};
});
}
fn calculate_connected_texture(floor_tiles: &HashMap<(i32, i32, i32), (bool, u32)>) -> Vec<String> {
let mut textures = vec![];
for ((x, y, z), (is_floor, tile_id)) in floor_tiles.iter() {
let mut is_wall = false;
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 = (x + x_offset, y + y_offset, z + z_offset);
if let Some((_, neighbor_id)) = floor_tiles.get(&neighbor_pos) {
if *neighbor_id > 0 { // assuming wall IDs are greater than 0
is_wall = true;
break;
}
}
}
}
}
match (is_floor, is_wall) {
(true, false) => textures.push("floor".to_string()), // or some other floor texture
(false, true) => textures.push("wall".to_string()), // or some other wall texture
_ => panic!("Unexpected tile state"),
}
}
textures
}
pub fn tile_item_sprite_update(
time: Res<Time>,
mut query_tile: Query<(Entity, &Children, &mut TileState)>,
mut query_item: Query<(&mut Visibility, &Item)>,
) {
for (_, children, mut state) in query_tile.iter_mut() {
state.timer.tick(time.delta());
if !state.timer.finished() {
continue;
}
let mut visible_index: Option<usize> = None;
for (i, &child) in children.iter().enumerate() {
if let Ok((mut visibility, _)) = query_item.get_mut(child) {
if matches!(*visibility, Visibility::Visible) {
visible_index = Some(i);
*visibility = Visibility::Hidden;
break;
}
}
}
let next_index = if let Some(current_index) = visible_index {
(current_index + 1) % children.len()
} else {
0
};
if let Some(&next_child) = children.get(next_index) {
if let Ok((mut visibility, _)) = query_item.get_mut(next_child) {
*visibility = Visibility::Visible;
}
}
}
}
#[derive(Component)]
pub struct TileState {
pub timer: Timer,
}