This commit is contained in:
2025-01-21 23:39:00 +00:00
parent bb3905e6b9
commit ca3fcc00ff
4 changed files with 52 additions and 49 deletions
+41 -37
View File
@@ -3,7 +3,8 @@ use crate::{
tile, tile,
tilemap::{generate_surface_noise, ChunkMap, CHUNK_SIZE}, tilemap::{generate_surface_noise, ChunkMap, CHUNK_SIZE},
}; };
use bevy::prelude::*; use bevy::{math::ivec3, prelude::*};
use noise::Negate;
#[derive(Bundle)] #[derive(Bundle)]
pub struct Citizen { pub struct Citizen {
@@ -46,7 +47,7 @@ pub struct Ambulatory {
pub target: Option<Vec3>, pub target: Option<Vec3>,
} }
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq, Debug)]
struct PathNode { struct PathNode {
position: IVec3, position: IVec3,
f_score: i32, f_score: i32,
@@ -103,9 +104,9 @@ pub fn update_citizen_wandering_targets(
// Find a valid z-level near the surface // Find a valid z-level near the surface
for z in (surface_height - 3)..=(surface_height + 4) { for z in (surface_height - 3)..=(surface_height + 4) {
let mut target_pos = IVec3::new(target_x, target_y, z) * TILE_SIZE as i32; let mut target_pos = IVec3::new(target_x, target_y, z) * ITILE_SIZE;
if let Some(floor_tile) = tilemap.floor_tiles.get(&target_pos) { if let Some(floor_tile) = tilemap.floor_tiles.get(&target_pos) {
target_pos.z += TILE_SIZE as i32; target_pos.z += ITILE_SIZE;
if floor_tile.2 { if floor_tile.2 {
if let Some(floor_tile_above) = tilemap.floor_tiles.get(&target_pos) { if let Some(floor_tile_above) = tilemap.floor_tiles.get(&target_pos) {
if floor_tile_above.0 == 0 { if floor_tile_above.0 == 0 {
@@ -150,22 +151,18 @@ pub fn citizen_movement(
} }
if let Some(target) = ambulatory.target { if let Some(target) = ambulatory.target {
// Convert world position to tile coordinates
let current_tile = IVec3::new(
(transform.translation.x / TILE_SIZE).floor() as i32,
(transform.translation.y / TILE_SIZE).floor() as i32,
(transform.translation.z / TILE_SIZE).floor() as i32,
);
let target_tile = IVec3::new(
(target.x / TILE_SIZE).floor() as i32,
(target.y / TILE_SIZE).floor() as i32,
(target.z / TILE_SIZE).floor() as i32,
);
// Calculate path if needed // Calculate path if needed
if ambulatory.current_path.is_none() { if ambulatory.current_path.is_none() {
ambulatory.current_path = Some(calculate_path(&tilemap, current_tile, target_tile)); println!(
"from {:?} to {:?}",
transform.translation.as_ivec3(),
target.as_ivec3() - ivec3(0, 0, 1)
);
ambulatory.current_path = Some(calculate_path(
&tilemap,
transform.translation.as_ivec3(),
target.as_ivec3() - ivec3(0, 0, 1),
));
ambulatory.path_index = 0; ambulatory.path_index = 0;
} }
@@ -174,9 +171,9 @@ pub fn citizen_movement(
if ambulatory.path_index < path.len() { if ambulatory.path_index < path.len() {
let next_point = path[ambulatory.path_index]; let next_point = path[ambulatory.path_index];
let next_world_pos = Vec3::new( let next_world_pos = Vec3::new(
next_point.x * TILE_SIZE + TILE_SIZE / 2.0, next_point.x + TILE_SIZE / 2.0,
next_point.y * TILE_SIZE + TILE_SIZE / 2.0, next_point.y + TILE_SIZE / 2.0,
next_point.z * TILE_SIZE + TILE_SIZE / 2.0, next_point.z + TILE_SIZE / 2.0,
); );
let direction = (next_world_pos - transform.translation).normalize(); let direction = (next_world_pos - transform.translation).normalize();
@@ -206,7 +203,7 @@ fn is_valid_move(tilemap: &TileMap, pos: IVec3) -> bool {
} }
// Check if there's solid ground below // Check if there's solid ground below
let pos_below = pos - IVec3::new(0, 0, 1); let pos_below = pos - IVec3::new(0, 0, ITILE_SIZE);
if let Some(below_tile) = tilemap.floor_tiles.get(&pos_below) { if let Some(below_tile) = tilemap.floor_tiles.get(&pos_below) {
return below_tile.0 != 0; return below_tile.0 != 0;
} }
@@ -231,19 +228,20 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
// Define allowed movements: orthogonal + diagonal on same level, and up/down // Define allowed movements: orthogonal + diagonal on same level, and up/down
let allowed_moves = vec![ let allowed_moves = vec![
// Cardinal directions (same level) // Cardinal directions (same level)
IVec3::new(1, 0, 0), IVec3::new(ITILE_SIZE, 0, 0),
IVec3::new(-1, 0, 0), IVec3::new(-ITILE_SIZE, 0, 0),
IVec3::new(0, 1, 0), IVec3::new(0, ITILE_SIZE, 0),
IVec3::new(0, -1, 0), IVec3::new(0, -ITILE_SIZE, 0),
// Diagonal directions (same level) // Diagonal directions (same level)
IVec3::new(1, 1, 0), IVec3::new(ITILE_SIZE, ITILE_SIZE, 0),
IVec3::new(1, -1, 0), IVec3::new(ITILE_SIZE, -ITILE_SIZE, 0),
IVec3::new(-1, 1, 0), IVec3::new(-ITILE_SIZE, ITILE_SIZE, 0),
IVec3::new(-1, -1, 0), IVec3::new(-ITILE_SIZE, -ITILE_SIZE, 0),
]; ];
while let Some(current) = open_set.pop() { while let Some(current) = open_set.pop() {
if current.position == goal { if current.position == goal {
println!("path found");
return reconstruct_path(came_from, current.position); return reconstruct_path(came_from, current.position);
} }
@@ -254,13 +252,13 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
let mut neighbor_pos = current.position + *move_dir; let mut neighbor_pos = current.position + *move_dir;
// Try one up if same level is invalid // Try one up if same level is invalid
let up_pos = neighbor_pos + IVec3::new(0, 0, 1); let up_pos = neighbor_pos + IVec3::new(0, 0, ITILE_SIZE);
if !is_valid_move(tilemap, neighbor_pos) && is_valid_move(tilemap, up_pos) { if !is_valid_move(tilemap, neighbor_pos) && is_valid_move(tilemap, up_pos) {
neighbor_pos = up_pos; neighbor_pos = up_pos;
} }
// Try one down if same level is invalid // Try one down if same level is invalid
let down_pos = neighbor_pos - IVec3::new(0, 0, 1); let down_pos = neighbor_pos - IVec3::new(0, 0, ITILE_SIZE);
if !is_valid_move(tilemap, neighbor_pos) && is_valid_move(tilemap, down_pos) { if !is_valid_move(tilemap, neighbor_pos) && is_valid_move(tilemap, down_pos) {
neighbor_pos = down_pos; neighbor_pos = down_pos;
} }
@@ -269,15 +267,20 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
continue; continue;
} }
let current_level = ITILE_SIZE;
let upper = 2*ITILE_SIZE;
let lower = -ITILE_SIZE;
// Calculate movement cost // Calculate movement cost
let movement_cost = match ( let movement_cost = match (
move_dir.x.abs() + move_dir.y.abs(), move_dir.x.abs() + move_dir.y.abs(),
neighbor_pos.z - current.position.z, neighbor_pos.z - current.position.z,
) { ) {
(1, 0) => 10, // Orthogonal movement (current_level, 0) => 10, // Orthogonal movement
(2, 0) => 14, // Diagonal movement (upper, 0) => 14, // Diagonal movement
(_, 1) => 20, // Moving up one level (_, current_level) => 20, // Moving up one level
(_, -1) => 15, // Moving down one level (_, lower) => 15, // Moving down one level
_ => continue, // Invalid movement _ => continue, // Invalid movement
}; };
@@ -298,6 +301,7 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
} }
} }
println!("No path found");
// If no path found, return direct line // If no path found, return direct line
vec![ vec![
Vec3::new(start.x as f32, start.y as f32, start.z as f32), Vec3::new(start.x as f32, start.y as f32, start.z as f32),
@@ -341,7 +345,7 @@ pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
// Spawn a handful of citizens // Spawn a handful of citizens
for _ in 0..10 { for _ in 0..1 {
let x: f32 = rng.gen_range(-15.0..10.0); let x: f32 = rng.gen_range(-15.0..10.0);
let y: f32 = rng.gen_range(-10.0..10.0); let y: f32 = rng.gen_range(-10.0..10.0);
let mut position = Vec3::new(x.round(), y.round(), 5.0) * TILE_SIZE; let mut position = Vec3::new(x.round(), y.round(), 5.0) * TILE_SIZE;
+1
View File
@@ -1,2 +1,3 @@
pub const PIXEL_RATIO: f32 = 2.0; pub const PIXEL_RATIO: f32 = 2.0;
pub const TILE_SIZE: f32 = 16.0 * PIXEL_RATIO; pub const TILE_SIZE: f32 = 16.0 * PIXEL_RATIO;
pub const ITILE_SIZE: i32 = TILE_SIZE as i32;
+3 -3
View File
@@ -29,6 +29,7 @@ fn main() {
.add_plugins(FrameTimeDiagnosticsPlugin::default()) // Add the FrameTimeDiagnosticsPlugin here .add_plugins(FrameTimeDiagnosticsPlugin::default()) // Add the FrameTimeDiagnosticsPlugin here
.insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0))) .insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0)))
.add_plugins(tilemap::TilemapPlugin) .add_plugins(tilemap::TilemapPlugin)
.add_plugins(PathfindingPlugin)
.add_systems( .add_systems(
Startup, Startup,
( (
@@ -41,8 +42,6 @@ fn main() {
FixedUpdate, FixedUpdate,
( (
camera::camera_movement, camera::camera_movement,
citizen::update_citizen_wandering_targets,
citizen::citizen_movement,
cursor::move_cursor, cursor::move_cursor,
// citizen::check_citizen_positions_for_chunks, // citizen::check_citizen_positions_for_chunks,
), ),
@@ -54,13 +53,14 @@ fn main() {
tile::camera_z_movement, tile::camera_z_movement,
tile::update_tile_visibility tile::update_tile_visibility
.run_if(|camera_moved: Res<tile::CameraMoved>| camera_moved.0), .run_if(|camera_moved: Res<tile::CameraMoved>| camera_moved.0),
log_fps_system, // log_fps_system,
), ),
) )
.run(); .run();
} }
use bevy::diagnostic::DiagnosticsStore; use bevy::diagnostic::DiagnosticsStore;
use citizen::PathfindingPlugin;
fn log_fps_system(diagnostics: Res<DiagnosticsStore>) { fn log_fps_system(diagnostics: Res<DiagnosticsStore>) {
if let Some(fps) = diagnostics if let Some(fps) = diagnostics
+7 -9
View File
@@ -1,4 +1,4 @@
use crate::constants::TILE_SIZE; use crate::constants::{ITILE_SIZE, TILE_SIZE};
use crate::tile::{self, FixtureTile, FloorTile, NeedsOccluded, TileMap}; use crate::tile::{self, FixtureTile, FloorTile, NeedsOccluded, TileMap};
use crate::tiles::{FixtureTilePrefab, FloorTilePrefab}; use crate::tiles::{FixtureTilePrefab, FloorTilePrefab};
use bevy::prelude::*; use bevy::prelude::*;
@@ -72,12 +72,10 @@ pub fn handle_tile_occlusion_updates(
} }
pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] { pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
let tile_size = TILE_SIZE as i32;
let mut visible_range = [0u32; 8]; let mut visible_range = [0u32; 8];
for mut camera_z in -15..=5 { for mut camera_z in -15..=5 {
camera_z *= tile_size; camera_z *= ITILE_SIZE;
let mut is_visible = false; let mut is_visible = false;
if pos.z > camera_z { if pos.z > camera_z {
@@ -87,7 +85,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..5 { 'vertical_check: for z_offset in 1..5 {
let above_pos = IVec3::new(pos.x, pos.y, pos.z + (z_offset * tile_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) {
if opaque { if opaque {
@@ -117,9 +115,9 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
continue; continue;
} }
let neighbor_pos = IVec3::new( let neighbor_pos = IVec3::new(
pos.x + x_offset * tile_size, pos.x + x_offset * ITILE_SIZE,
pos.y + y_offset * tile_size, pos.y + y_offset * ITILE_SIZE,
pos.z + z_offset * tile_size, pos.z + z_offset * ITILE_SIZE,
); );
if let Some(&(id, _, _, _, _)) = tilemap.floor_tiles.get(&neighbor_pos) { if let Some(&(id, _, _, _, _)) = tilemap.floor_tiles.get(&neighbor_pos) {
@@ -140,7 +138,7 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
} }
if is_visible { if is_visible {
let z2 = ((camera_z / tile_size) + 150) as usize; let z2 = ((camera_z / ITILE_SIZE) + 150) as usize;
visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32); visible_range[z2 / 32] |= 1 << ((z2 % 32) as u32);
} }
} }