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()) {
|
if !is_standable_tile(&tilemap, current_pos.as_ivec3()) {
|
||||||
// println!("drop");
|
|
||||||
transform.translation = below_pos + Vec3::new(0.0, 0.0, 0.1);
|
transform.translation = below_pos + Vec3::new(0.0, 0.0, 0.1);
|
||||||
// println!("transform.translation: {:?}", transform.translation);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +183,9 @@ pub fn citizen_movement(
|
|||||||
if transform.translation.distance(next_point) < ambulatory.speed {
|
if transform.translation.distance(next_point) < ambulatory.speed {
|
||||||
ambulatory.path_index += 1;
|
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 came_from = HashMap::new();
|
||||||
let mut g_scores = HashMap::new();
|
let mut g_scores = HashMap::new();
|
||||||
let mut closed_set = HashSet::new();
|
let mut closed_set = HashSet::new();
|
||||||
|
let mut in_open_set = HashSet::new();
|
||||||
|
|
||||||
let start_node = PathNode {
|
let start_node = PathNode {
|
||||||
position: start,
|
position: start,
|
||||||
f_score: manhattan_distance_3d(start, goal),
|
f_score: octile_distance_3d(start, goal),
|
||||||
g_score: 0,
|
g_score: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
open_set.push(start_node);
|
open_set.push(start_node);
|
||||||
|
in_open_set.insert(start);
|
||||||
g_scores.insert(start, 0);
|
g_scores.insert(start, 0);
|
||||||
|
|
||||||
let allowed_moves = vec![
|
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() {
|
while let Some(current_node) = open_set.pop() {
|
||||||
let current = current_node.position;
|
let current = current_node.position;
|
||||||
|
|
||||||
|
in_open_set.remove(¤t);
|
||||||
|
|
||||||
if current == goal {
|
if current == goal {
|
||||||
// println!("path found");
|
// println!("path found");
|
||||||
return reconstruct_path(came_from, current);
|
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 (
|
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,
|
move_dir.z.abs() / ITILE_SIZE,
|
||||||
) {
|
) {
|
||||||
(1, 0) => 10, // Orthogonal movement
|
(1, 0, 0) | (0, 1, 0) | (0, 0, 1) => 10, // Orthogonal movement (1 axis)
|
||||||
(2, 0) => 11, // Diagonal movement
|
(1, 1, 0) | (1, 0, 1) | (0, 1, 1) => 14, // Diagonal movement (2 axes)
|
||||||
(_, 1) => 14, // Moving up or down
|
(1, 1, 1) => 17, // Full 3D diagonal movement (3 axes)
|
||||||
_ => continue, // Invalid movement
|
_ => continue, // Invalid movement
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_g = g_scores.get(¤t).unwrap_or(&i32::MAX) + movement_cost;
|
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) {
|
if new_g < *g_scores.get(&neighbor_pos).unwrap_or(&i32::MAX) {
|
||||||
came_from.insert(neighbor_pos, current);
|
came_from.insert(neighbor_pos, current);
|
||||||
g_scores.insert(neighbor_pos, new_g);
|
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 f = new_g + h;
|
||||||
|
|
||||||
let neighbor_node = PathNode {
|
// Only add to open set if not already there
|
||||||
position: neighbor_pos,
|
if !in_open_set.contains(&neighbor_pos) {
|
||||||
f_score: f,
|
let neighbor_node = PathNode {
|
||||||
g_score: new_g,
|
position: neighbor_pos,
|
||||||
};
|
f_score: f,
|
||||||
open_set.push(neighbor_node);
|
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()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manhattan_distance_3d(a: IVec3, b: IVec3) -> i32 {
|
fn octile_distance_3d(a: IVec3, b: IVec3) -> i32 {
|
||||||
(a.x - b.x).abs() + (a.y - b.y).abs() + (a.z - b.z).abs()
|
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> {
|
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();
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
// Spawn a handful of citizens
|
// Spawn a handful of citizens
|
||||||
for _ in 0..5 {
|
for _ in 0..50 {
|
||||||
let x: f32 = rng.random_range(-8.0..8.0);
|
let x: f32 = rng.random_range(-8.0..8.0);
|
||||||
let y: 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;
|
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>,
|
// z_index: ResMut<game::ZIndex>,
|
||||||
mut cwss: ResMut<tiles::CurrentWorldSpriteState>,
|
mut cwss: ResMut<tiles::CurrentWorldSpriteState>,
|
||||||
) {
|
) {
|
||||||
println!("update_tile_visibility, cwss.state = {:?}", cwss.state);
|
|
||||||
cwss.state = tiles::WorldSpriteState::WaitingForRender;
|
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;
|
// 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");
|
println!("setup_initial_chunks");
|
||||||
for x in -7..=7 {
|
for x in -7..=7 {
|
||||||
for y in -7..=7 {
|
for y in -7..=7 {
|
||||||
event_writer.send(LoadChunkEvent {
|
event_writer.write(LoadChunkEvent {
|
||||||
chunk_position: IVec2::new(x, y),
|
chunk_position: IVec2::new(x, y),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileState};
|
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileState};
|
||||||
use crate::{constants::*, game};
|
use crate::{constants::*, game};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@@ -89,6 +88,7 @@ pub enum WorldSpriteState {
|
|||||||
pub struct CurrentWorldSpriteState {
|
pub struct CurrentWorldSpriteState {
|
||||||
pub state: WorldSpriteState,
|
pub state: WorldSpriteState,
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|||||||
Reference in New Issue
Block a user