manhattan to octile

This commit is contained in:
2025-05-03 20:27:44 +01:00
parent b5a3fd1714
commit 9df3f7ecaf
4 changed files with 58 additions and 23 deletions
+56 -18
View File
@@ -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(&current);
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(&current).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;
-3
View File
@@ -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
View File
@@ -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
View File
@@ -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)]