manhattan to octile
This commit is contained in:
+56
-18
@@ -144,9 +144,7 @@ pub fn citizen_movement(
|
||||
);
|
||||
|
||||
if !is_standable_tile(&tilemap, current_pos.as_ivec3()) {
|
||||
// println!("drop");
|
||||
transform.translation = below_pos + Vec3::new(0.0, 0.0, 0.1);
|
||||
// println!("transform.translation: {:?}", transform.translation);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -185,6 +183,9 @@ pub fn citizen_movement(
|
||||
if transform.translation.distance(next_point) < ambulatory.speed {
|
||||
ambulatory.path_index += 1;
|
||||
}
|
||||
} else {
|
||||
ambulatory.current_path = None;
|
||||
ambulatory.target = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,14 +224,16 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
|
||||
let mut came_from = HashMap::new();
|
||||
let mut g_scores = HashMap::new();
|
||||
let mut closed_set = HashSet::new();
|
||||
let mut in_open_set = HashSet::new();
|
||||
|
||||
let start_node = PathNode {
|
||||
position: start,
|
||||
f_score: manhattan_distance_3d(start, goal),
|
||||
f_score: octile_distance_3d(start, goal),
|
||||
g_score: 0,
|
||||
};
|
||||
|
||||
open_set.push(start_node);
|
||||
in_open_set.insert(start);
|
||||
g_scores.insert(start, 0);
|
||||
|
||||
let allowed_moves = vec![
|
||||
@@ -267,6 +270,8 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
|
||||
while let Some(current_node) = open_set.pop() {
|
||||
let current = current_node.position;
|
||||
|
||||
in_open_set.remove(¤t);
|
||||
|
||||
if current == goal {
|
||||
// println!("path found");
|
||||
return reconstruct_path(came_from, current);
|
||||
@@ -282,13 +287,14 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
|
||||
}
|
||||
|
||||
let movement_cost = match (
|
||||
move_dir.x.abs() / ITILE_SIZE + move_dir.y.abs() / ITILE_SIZE,
|
||||
move_dir.x.abs() / ITILE_SIZE,
|
||||
move_dir.y.abs() / ITILE_SIZE,
|
||||
move_dir.z.abs() / ITILE_SIZE,
|
||||
) {
|
||||
(1, 0) => 10, // Orthogonal movement
|
||||
(2, 0) => 11, // Diagonal movement
|
||||
(_, 1) => 14, // Moving up or down
|
||||
_ => continue, // Invalid movement
|
||||
(1, 0, 0) | (0, 1, 0) | (0, 0, 1) => 10, // Orthogonal movement (1 axis)
|
||||
(1, 1, 0) | (1, 0, 1) | (0, 1, 1) => 14, // Diagonal movement (2 axes)
|
||||
(1, 1, 1) => 17, // Full 3D diagonal movement (3 axes)
|
||||
_ => continue, // Invalid movement
|
||||
};
|
||||
|
||||
let new_g = g_scores.get(¤t).unwrap_or(&i32::MAX) + movement_cost;
|
||||
@@ -296,15 +302,29 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
|
||||
if new_g < *g_scores.get(&neighbor_pos).unwrap_or(&i32::MAX) {
|
||||
came_from.insert(neighbor_pos, current);
|
||||
g_scores.insert(neighbor_pos, new_g);
|
||||
let h = manhattan_distance_3d(neighbor_pos, goal);
|
||||
let h = octile_distance_3d(neighbor_pos, goal);
|
||||
let f = new_g + h;
|
||||
|
||||
let neighbor_node = PathNode {
|
||||
position: neighbor_pos,
|
||||
f_score: f,
|
||||
g_score: new_g,
|
||||
};
|
||||
open_set.push(neighbor_node);
|
||||
// Only add to open set if not already there
|
||||
if !in_open_set.contains(&neighbor_pos) {
|
||||
let neighbor_node = PathNode {
|
||||
position: neighbor_pos,
|
||||
f_score: f,
|
||||
g_score: new_g,
|
||||
};
|
||||
open_set.push(neighbor_node);
|
||||
in_open_set.insert(neighbor_pos);
|
||||
} else {
|
||||
// For nodes already in the open set, we need to update their priority
|
||||
// This is tricky with a binary heap - one approach is to add a new entry
|
||||
// The old one will still be there but will be ignored when we check the closed set
|
||||
let neighbor_node = PathNode {
|
||||
position: neighbor_pos,
|
||||
f_score: f,
|
||||
g_score: new_g,
|
||||
};
|
||||
open_set.push(neighbor_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,8 +332,26 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn manhattan_distance_3d(a: IVec3, b: IVec3) -> i32 {
|
||||
(a.x - b.x).abs() + (a.y - b.y).abs() + (a.z - b.z).abs()
|
||||
fn octile_distance_3d(a: IVec3, b: IVec3) -> i32 {
|
||||
let dx = (a.x - b.x).abs();
|
||||
let dy = (a.y - b.y).abs();
|
||||
let dz = (a.z - b.z).abs();
|
||||
|
||||
// Costs for movement along 1, 2, or 3 axes
|
||||
let cost1 = 10; // Orthogonal
|
||||
let cost2 = 14; // 2D Diagonal
|
||||
let cost3 = 17; // 3D Diagonal
|
||||
|
||||
// The heuristic calculation sorts the dimensions implicitly
|
||||
// It calculates the minimum number of diagonal steps needed
|
||||
let mut diffs = [dx, dy, dz];
|
||||
diffs.sort_unstable(); // Sorts ascending: [dmin, dmid, dmax]
|
||||
|
||||
let dmin = diffs[0];
|
||||
let dmid = diffs[1];
|
||||
let dmax = diffs[2];
|
||||
|
||||
cost3 * dmin + cost2 * (dmid - dmin) + cost1 * (dmax - dmid) // Yikes..
|
||||
}
|
||||
|
||||
fn reconstruct_path(came_from: HashMap<IVec3, IVec3>, mut current: IVec3) -> Vec<Vec3> {
|
||||
@@ -340,7 +378,7 @@ pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let mut rng = rand::rng();
|
||||
|
||||
// Spawn a handful of citizens
|
||||
for _ in 0..5 {
|
||||
for _ in 0..50 {
|
||||
let x: f32 = rng.random_range(-8.0..8.0);
|
||||
let y: f32 = rng.random_range(-8.0..8.0);
|
||||
let mut position = Vec3::new(x.round(), y.round(), 30.0) * TILE_SIZE;
|
||||
|
||||
@@ -79,10 +79,7 @@ pub fn update_tile_visibility(
|
||||
// z_index: ResMut<game::ZIndex>,
|
||||
mut cwss: ResMut<tiles::CurrentWorldSpriteState>,
|
||||
) {
|
||||
println!("update_tile_visibility, cwss.state = {:?}", cwss.state);
|
||||
cwss.state = tiles::WorldSpriteState::WaitingForRender;
|
||||
println!("update_tile_visibility, cwss.state = {:?}", cwss.state);
|
||||
println!();
|
||||
// let z_index = (z_index.0 as i32 + 150) as usize;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -288,7 +288,7 @@ fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
|
||||
println!("setup_initial_chunks");
|
||||
for x in -7..=7 {
|
||||
for y in -7..=7 {
|
||||
event_writer.send(LoadChunkEvent {
|
||||
event_writer.write(LoadChunkEvent {
|
||||
chunk_position: IVec2::new(x, y),
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,3 @@
|
||||
|
||||
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileState};
|
||||
use crate::{constants::*, game};
|
||||
use bevy::prelude::*;
|
||||
@@ -89,6 +88,7 @@ pub enum WorldSpriteState {
|
||||
pub struct CurrentWorldSpriteState {
|
||||
pub state: WorldSpriteState,
|
||||
}
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Component)]
|
||||
|
||||
Reference in New Issue
Block a user