321 lines
9.5 KiB
Rust
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,
|
|
}
|