global tilemap (ish)

This commit is contained in:
StephenAdamson
2024-12-30 22:18:20 +00:00
parent a4342c9aa0
commit 73dcbd4102
3 changed files with 139 additions and 105 deletions
+5 -1
View File
@@ -10,6 +10,7 @@ use rand::prelude::*;
pub struct ZIndex(pub f32);
pub fn setup_level(mut commands: Commands, asset_server: Res<AssetServer>) {
println!("setup_level");
setup_tilemap(&mut commands, &asset_server);
for x in -10..10 {
@@ -164,7 +165,10 @@ fn setup_tilemap(commands: &mut Commands, asset_server: &Res<AssetServer>) {
commands.spawn(FixtureTilePrefab::rock_wall(fixture_position, asset_server));
}
"bedrock" => {
commands.spawn(FixtureTilePrefab::bedrock_wall(fixture_position, asset_server));
commands.spawn(FixtureTilePrefab::bedrock_wall(
fixture_position,
asset_server,
));
}
_ => {}
}
+1
View File
@@ -35,6 +35,7 @@ fn main() {
.add_systems(
PostStartup,
(
tile::build_tile_map,
tile::tile_sprite_generate_occlusion_map,
tile::update_tile_visibility,
)
+133 -104
View File
@@ -2,8 +2,10 @@ use crate::constants::TILE_SIZE;
use crate::game;
use crate::item::Item;
use bevy::ecs::system::ParamSet;
use bevy::math::ivec3;
use bevy::prelude::*;
use std::collections::HashMap;
use std::process::exit;
#[derive(Component, Clone)]
#[require(Sprite)]
@@ -45,9 +47,7 @@ impl Default for FixtureTile {
}
#[derive(Component, Clone)]
pub struct ConnectedTexture {
}
pub struct ConnectedTexture {}
#[derive(Resource, Default)]
pub struct CameraMoved(pub bool);
@@ -73,136 +73,162 @@ pub fn camera_z_movement(
}
}
#[derive(Resource, Default)]
pub struct TileMap {
pub floors: HashMap<IVec3, (u32, bool, bool, u8, [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<(&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();
println!("tile_sprite_generate_occlusion_map");
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];
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;
for mut camera_z in -150..100 {
camera_z *= tile_size;
let mut is_visible = false;
if pos.2 > camera_z {
continue;
}
if pos.z > camera_z {
continue;
}
let mut is_occluded = false;
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;
}
}
}
'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 is_visible {
let z2 = ((camera_z / tile_size) + 150) as usize;
visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32);
if let Some(&(_, solid, _)) = tilemap.fixtures.get(&above_pos) {
if solid {
is_occluded = true;
break 'vertical_check;
}
}
} else {
break 'vertical_check;
}
}
visible_range
};
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
.p2()
.p0()
.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);
let pos = transform.translation.as_ivec3();
tile.visible_range = calculate_visibility(pos, &tilemap);
});
// Update fixture tiles
query_set
.p3()
.p1()
.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);
let pos = transform.translation.as_ivec3() - IVec3::new(0, 0, 1);
fixture.visible_range = calculate_visibility(pos, &tilemap);
});
use std::time::Instant;
let total: Instant = Instant::now();
for i in 0..1000000 {
let now: Instant = Instant::now();
for x in -1..=1 {
for y in -1..=1 {
for z in 0..=1 {
tilemap.floors.get(&IVec3::new(x, y, z));
}
}
}
let elapsed = now.elapsed();
}
let elapsed = total.elapsed();
print!("{:.4?}, ", elapsed / 1000000);
exit(0);
}
pub fn update_tile_visibility(
@@ -212,6 +238,8 @@ pub fn update_tile_visibility(
Query<(&FixtureTile, &mut Visibility)>,
)>,
) {
println!("update_tile_visibility");
let z_index = (z_index.0 as i32 + 150) as usize;
// Update floor visibility
@@ -258,7 +286,8 @@ fn calculate_connected_texture(floor_tiles: &HashMap<(i32, i32, i32), (bool, u32
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
if *neighbor_id > 0 {
// assuming wall IDs are greater than 0
is_wall = true;
break;
}
@@ -269,7 +298,7 @@ fn calculate_connected_texture(floor_tiles: &HashMap<(i32, i32, i32), (bool, u32
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
(false, true) => textures.push("wall".to_string()), // or some other wall texture
_ => panic!("Unexpected tile state"),
}
}