path 2
This commit is contained in:
+41
-37
@@ -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,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
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user