mirror of
https://github.com/mat-1/azalea.git
synced 2024-09-19 22:52:32 +00:00
improve pathfinder heuristics
This commit is contained in:
parent
9db542f342
commit
074bb61983
4 changed files with 49 additions and 11 deletions
|
@ -259,6 +259,7 @@ impl ChunkSectionPos {
|
||||||
block >> 4
|
block >> 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The coordinates of a block inside a chunk.
|
/// The coordinates of a block inside a chunk.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ChunkBlockPos {
|
pub struct ChunkBlockPos {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{trace, warn};
|
use log::{debug, trace, warn};
|
||||||
use priority_queue::PriorityQueue;
|
use priority_queue::PriorityQueue;
|
||||||
|
|
||||||
pub struct Path<P, M>
|
pub struct Path<P, M>
|
||||||
|
@ -55,8 +55,12 @@ where
|
||||||
let mut best_paths: [P; 7] = [start; 7];
|
let mut best_paths: [P; 7] = [start; 7];
|
||||||
let mut best_path_scores: [f32; 7] = [heuristic(start); 7];
|
let mut best_path_scores: [f32; 7] = [heuristic(start); 7];
|
||||||
|
|
||||||
|
let mut num_nodes = 0;
|
||||||
|
|
||||||
while let Some((current_node, _)) = open_set.pop() {
|
while let Some((current_node, _)) = open_set.pop() {
|
||||||
|
num_nodes += 1;
|
||||||
if success(current_node) {
|
if success(current_node) {
|
||||||
|
debug!("Nodes considered: {num_nodes}");
|
||||||
return Path {
|
return Path {
|
||||||
movements: reconstruct_path(nodes, current_node),
|
movements: reconstruct_path(nodes, current_node),
|
||||||
partial: false,
|
partial: false,
|
||||||
|
@ -99,7 +103,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if start_time.elapsed() > timeout {
|
// check for timeout every ~1ms
|
||||||
|
if num_nodes % 1000 == 0 && start_time.elapsed() > timeout {
|
||||||
// timeout, just return the best path we have so far
|
// timeout, just return the best path we have so far
|
||||||
trace!("A* couldn't find a path in time, returning best path");
|
trace!("A* couldn't find a path in time, returning best path");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
use std::f32::consts::SQRT_2;
|
||||||
|
|
||||||
use azalea_core::position::{BlockPos, Vec3};
|
use azalea_core::position::{BlockPos, Vec3};
|
||||||
|
|
||||||
use super::Goal;
|
use super::{
|
||||||
|
costs::{FALL_ONE_BLOCK_COST, JUMP_ONE_BLOCK_COST},
|
||||||
|
Goal,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct BlockPosGoal(pub BlockPos);
|
pub struct BlockPosGoal(pub BlockPos);
|
||||||
impl Goal for BlockPosGoal {
|
impl Goal for BlockPosGoal {
|
||||||
|
@ -8,13 +13,32 @@ impl Goal for BlockPosGoal {
|
||||||
let dx = (self.0.x - n.x) as f32;
|
let dx = (self.0.x - n.x) as f32;
|
||||||
let dy = (self.0.y - n.y) as f32;
|
let dy = (self.0.y - n.y) as f32;
|
||||||
let dz = (self.0.z - n.z) as f32;
|
let dz = (self.0.z - n.z) as f32;
|
||||||
dx * dx + dy * dy + dz * dz
|
|
||||||
|
xz_heuristic(dx, dz) + y_heuristic(dy)
|
||||||
}
|
}
|
||||||
fn success(&self, n: BlockPos) -> bool {
|
fn success(&self, n: BlockPos) -> bool {
|
||||||
n == self.0
|
n == self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn xz_heuristic(dx: f32, dz: f32) -> f32 {
|
||||||
|
let x = dx.abs();
|
||||||
|
let z = dz.abs();
|
||||||
|
|
||||||
|
let diagonal;
|
||||||
|
let straight;
|
||||||
|
|
||||||
|
if x < z {
|
||||||
|
straight = z - x;
|
||||||
|
diagonal = x;
|
||||||
|
} else {
|
||||||
|
straight = x - z;
|
||||||
|
diagonal = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
diagonal * SQRT_2 + straight
|
||||||
|
}
|
||||||
|
|
||||||
pub struct XZGoal {
|
pub struct XZGoal {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub z: i32,
|
pub z: i32,
|
||||||
|
@ -23,20 +47,28 @@ impl Goal for XZGoal {
|
||||||
fn heuristic(&self, n: BlockPos) -> f32 {
|
fn heuristic(&self, n: BlockPos) -> f32 {
|
||||||
let dx = (self.x - n.x) as f32;
|
let dx = (self.x - n.x) as f32;
|
||||||
let dz = (self.z - n.z) as f32;
|
let dz = (self.z - n.z) as f32;
|
||||||
dx * dx + dz * dz
|
xz_heuristic(dx, dz)
|
||||||
}
|
}
|
||||||
fn success(&self, n: BlockPos) -> bool {
|
fn success(&self, n: BlockPos) -> bool {
|
||||||
n.x == self.x && n.z == self.z
|
n.x == self.x && n.z == self.z
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn y_heuristic(dy: f32) -> f32 {
|
||||||
|
if dy < 0.0 {
|
||||||
|
FALL_ONE_BLOCK_COST * -dy
|
||||||
|
} else {
|
||||||
|
*JUMP_ONE_BLOCK_COST * dy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct YGoal {
|
pub struct YGoal {
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
}
|
}
|
||||||
impl Goal for YGoal {
|
impl Goal for YGoal {
|
||||||
fn heuristic(&self, n: BlockPos) -> f32 {
|
fn heuristic(&self, n: BlockPos) -> f32 {
|
||||||
let dy = (self.y - n.y) as f32;
|
let dy = (self.y - n.y) as f32;
|
||||||
dy * dy
|
y_heuristic(dy)
|
||||||
}
|
}
|
||||||
fn success(&self, n: BlockPos) -> bool {
|
fn success(&self, n: BlockPos) -> bool {
|
||||||
n.y == self.y
|
n.y == self.y
|
||||||
|
|
|
@ -25,6 +25,11 @@ type Edge = astar::Edge<BlockPos, MoveData>;
|
||||||
|
|
||||||
pub type SuccessorsFn = fn(&mut Vec<Edge>, &PathfinderCtx, BlockPos);
|
pub type SuccessorsFn = fn(&mut Vec<Edge>, &PathfinderCtx, BlockPos);
|
||||||
|
|
||||||
|
pub fn default_move(edges: &mut Vec<Edge>, ctx: &PathfinderCtx, node: BlockPos) {
|
||||||
|
basic::basic_move(edges, ctx, node);
|
||||||
|
parkour::parkour_move(edges, ctx, node);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MoveData {
|
pub struct MoveData {
|
||||||
/// Use the context to determine what events should be sent to complete this
|
/// Use the context to determine what events should be sent to complete this
|
||||||
|
@ -272,11 +277,6 @@ pub struct IsReachedCtx<'a> {
|
||||||
pub physics: &'a azalea_entity::Physics,
|
pub physics: &'a azalea_entity::Physics,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_move(edges: &mut Vec<Edge>, ctx: &PathfinderCtx, node: BlockPos) {
|
|
||||||
basic::basic_move(edges, ctx, node);
|
|
||||||
parkour::parkour_move(edges, ctx, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the entity is at the node and should start going to the
|
/// Returns whether the entity is at the node and should start going to the
|
||||||
/// next node.
|
/// next node.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
Loading…
Reference in a new issue