mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Smoother pathfinding for fast animals
This commit is contained in:
parent
014cab0257
commit
8a0b7fd173
@ -78,7 +78,11 @@ impl Component for Agent {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Activity {
|
||||
Idle(Vec2<f32>),
|
||||
Follow(EcsEntity, Chaser),
|
||||
Follow {
|
||||
target: EcsEntity,
|
||||
chaser: Chaser,
|
||||
move_dir: Vec2<f32>,
|
||||
},
|
||||
Attack {
|
||||
target: EcsEntity,
|
||||
chaser: Chaser,
|
||||
@ -91,7 +95,7 @@ pub enum Activity {
|
||||
impl Activity {
|
||||
pub fn is_follow(&self) -> bool {
|
||||
match self {
|
||||
Activity::Follow(_, _) => true,
|
||||
Activity::Follow { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -77,9 +77,9 @@ impl Route {
|
||||
None
|
||||
} else {
|
||||
let next_tgt = next.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0);
|
||||
if ((pos - (next_tgt + Vec3::unit_z() * 0.5)) * Vec3::new(1.0, 1.0, 0.3))
|
||||
.magnitude_squared()
|
||||
< (traversal_tolerance * 2.0).powf(2.0)
|
||||
if pos.xy().distance_squared(next_tgt.xy()) < traversal_tolerance.powf(2.0)
|
||||
&& next_tgt.z - pos.z < 0.2
|
||||
&& next_tgt.z - pos.z > -2.2
|
||||
{
|
||||
self.next_idx += 1;
|
||||
}
|
||||
@ -93,7 +93,7 @@ impl Route {
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct Chaser {
|
||||
last_search_tgt: Option<Vec3<f32>>,
|
||||
route: Route,
|
||||
route: Option<Route>,
|
||||
/// We use this hasher (AAHasher) because:
|
||||
/// (1) we care about DDOS attacks (ruling out FxHash);
|
||||
/// (2) we don't care about determinism across computers (we can use
|
||||
@ -115,21 +115,25 @@ impl Chaser {
|
||||
{
|
||||
let pos_to_tgt = pos.distance(tgt);
|
||||
|
||||
if ((pos - tgt) * Vec3::new(1.0, 1.0, 0.15)).magnitude_squared() < min_dist.powf(2.0) {
|
||||
if ((pos - tgt) * Vec3::new(1.0, 1.0, 2.0)).magnitude_squared() < min_dist.powf(2.0) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bearing = if let Some(end) = self.route.path().end().copied() {
|
||||
let bearing = if let Some(end) = self.route.as_ref().and_then(|r| r.path().end().copied()) {
|
||||
let end_to_tgt = end.map(|e| e as f32).distance(tgt);
|
||||
if end_to_tgt > pos_to_tgt * 0.3 + 5.0 {
|
||||
None
|
||||
} else {
|
||||
if thread_rng().gen::<f32>() < 0.005 {
|
||||
// TODO: Only re-calculate route when we're stuck
|
||||
self.route = Route::default();
|
||||
None
|
||||
} else {
|
||||
self.route
|
||||
.as_mut()
|
||||
.and_then(|r| r.traverse(vol, pos, traversal_tolerance))
|
||||
.filter(|b| {
|
||||
b.xy().magnitude_squared() < (traversal_tolerance + 1.0).powf(2.0)
|
||||
})
|
||||
}
|
||||
|
||||
self.route.traverse(vol, pos, traversal_tolerance)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@ -144,7 +148,12 @@ impl Chaser {
|
||||
.map(|last_tgt| last_tgt.distance(tgt) > pos_to_tgt * 0.15 + 5.0)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
self.route = find_path(&mut self.astar, vol, pos, tgt).into();
|
||||
let (start_pos, path) = find_path(&mut self.astar, vol, pos, tgt);
|
||||
if start_pos.distance_squared(pos) < 4.0f32.powf(2.0) {
|
||||
self.route = path.map(Route::from);
|
||||
} else {
|
||||
self.route = None;
|
||||
}
|
||||
}
|
||||
|
||||
Some((tgt - pos) * Vec3::new(1.0, 1.0, 0.0))
|
||||
@ -158,7 +167,7 @@ fn find_path<V>(
|
||||
vol: &V,
|
||||
startf: Vec3<f32>,
|
||||
endf: Vec3<f32>,
|
||||
) -> Path<Vec3<i32>>
|
||||
) -> (Vec3<f32>, Option<Path<Vec3<i32>>>)
|
||||
where
|
||||
V: BaseVol<Vox = Block> + ReadVol,
|
||||
{
|
||||
@ -192,7 +201,7 @@ where
|
||||
get_walkable_z(endf.map(|e| e.floor() as i32)),
|
||||
) {
|
||||
(Some(start), Some(end)) => (start, end),
|
||||
_ => return Path::default(),
|
||||
_ => return (startf, None),
|
||||
};
|
||||
|
||||
let heuristic = |pos: &Vec3<i32>| (pos.distance_squared(end) as f32).sqrt();
|
||||
@ -240,6 +249,7 @@ where
|
||||
.map(move |dir| (pos, dir))
|
||||
.filter(move |(pos, dir)| {
|
||||
is_walkable(pos)
|
||||
&& is_walkable(&(*pos + **dir))
|
||||
&& ((dir.z < 1
|
||||
|| vol
|
||||
.get(pos + Vec3::unit_z() * 2)
|
||||
@ -266,34 +276,32 @@ where
|
||||
.map(move |(dir, _)| pos + *dir),
|
||||
)
|
||||
};
|
||||
let transition = |a: &Vec3<i32>, b: &Vec3<i32>| {
|
||||
((*a - *b) * Vec3::new(1, 1, 3)).map(|e| e.abs()).reduce_max() as f32
|
||||
+ endf.distance((*b).map(|e| e as f32)) * 0.01
|
||||
};
|
||||
let transition =
|
||||
|a: &Vec3<i32>, b: &Vec3<i32>| 1.0 + endf.distance((*b).map(|e| e as f32 + 0.5)) * 0.02;
|
||||
let satisfied = |pos: &Vec3<i32>| pos == &end;
|
||||
|
||||
let mut new_astar = match astar.take() {
|
||||
None => Astar::new(20_000, start, heuristic, DefaultHashBuilder::default()),
|
||||
None => Astar::new(25_000, start, heuristic, DefaultHashBuilder::default()),
|
||||
Some(astar) => astar,
|
||||
};
|
||||
|
||||
let path_result = new_astar.poll(60, heuristic, neighbors, transition, satisfied);
|
||||
let path_result = new_astar.poll(100, heuristic, neighbors, transition, satisfied);
|
||||
|
||||
*astar = Some(new_astar);
|
||||
|
||||
match path_result {
|
||||
(startf, match path_result {
|
||||
PathResult::Path(path) => {
|
||||
*astar = None;
|
||||
path
|
||||
Some(path)
|
||||
},
|
||||
PathResult::None(path) => {
|
||||
*astar = None;
|
||||
path
|
||||
Some(path)
|
||||
},
|
||||
PathResult::Exhausted(path) => {
|
||||
*astar = None;
|
||||
path
|
||||
Some(path)
|
||||
},
|
||||
PathResult::Pending => Path::default(),
|
||||
}
|
||||
PathResult::Pending => None,
|
||||
})
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
item::{Hands, ItemKind, Tool},
|
||||
CharacterState, StateUpdate,
|
||||
Body,
|
||||
Body, CharacterState, StateUpdate,
|
||||
},
|
||||
event::LocalEvent,
|
||||
states::*,
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
agent::Activity,
|
||||
item::{tool::ToolKind, ItemKind},
|
||||
Agent, Alignment, CharacterState, ChatMsg, ControlAction, Controller, Loadout, MountState,
|
||||
Ori, Pos, Scale, Stats, Vel,
|
||||
Ori, Pos, Scale, SpeechBubble, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
path::Chaser,
|
||||
@ -126,7 +126,7 @@ impl<'a> System<'a> for Sys {
|
||||
// and so can afford to be less precise when trying to move around
|
||||
// the world (especially since they would otherwise get stuck on
|
||||
// obstacles that smaller entities would not).
|
||||
let traversal_tolerance = scale + vel.0.magnitude() * 0.35;
|
||||
let traversal_tolerance = scale + vel.0.magnitude() * 0.25;
|
||||
|
||||
let mut do_idle = false;
|
||||
let mut choose_target = false;
|
||||
@ -187,7 +187,11 @@ impl<'a> System<'a> for Sys {
|
||||
choose_target = true;
|
||||
}
|
||||
},
|
||||
Activity::Follow(target, chaser) => {
|
||||
Activity::Follow {
|
||||
target,
|
||||
chaser,
|
||||
move_dir,
|
||||
} => {
|
||||
if let (Some(tgt_pos), _tgt_stats) =
|
||||
(positions.get(*target), stats.get(*target))
|
||||
{
|
||||
@ -201,10 +205,13 @@ impl<'a> System<'a> for Sys {
|
||||
AVG_FOLLOW_DIST,
|
||||
traversal_tolerance,
|
||||
) {
|
||||
inputs.move_dir = Vec2::from(bearing)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::zero());
|
||||
inputs.jump.set_state(bearing.z > 1.0);
|
||||
*move_dir = 0.9f32 * *move_dir
|
||||
+ 0.1f32
|
||||
* Vec2::from(bearing)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::zero());
|
||||
inputs.move_dir = *move_dir;
|
||||
inputs.jump.set_state(bearing.z > 1.5);
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
@ -317,7 +324,7 @@ impl<'a> System<'a> for Sys {
|
||||
inputs.move_dir = Vec2::from(bearing)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::zero());
|
||||
inputs.jump.set_state(bearing.z > 1.0);
|
||||
inputs.jump.set_state(bearing.z > 1.5);
|
||||
}
|
||||
|
||||
if dist_sqrd < 16.0f32.powf(2.0)
|
||||
@ -419,7 +426,11 @@ impl<'a> System<'a> for Sys {
|
||||
if let Some(owner_pos) = positions.get(owner) {
|
||||
let dist_sqrd = pos.0.distance_squared(owner_pos.0);
|
||||
if dist_sqrd > MAX_FOLLOW_DIST.powf(2.0) && !agent.activity.is_follow() {
|
||||
agent.activity = Activity::Follow(owner, Chaser::default());
|
||||
agent.activity = Activity::Follow {
|
||||
target: owner,
|
||||
chaser: Chaser::default(),
|
||||
move_dir: Vec2::zero(),
|
||||
};
|
||||
}
|
||||
|
||||
// Attack owner's attacker
|
||||
|
Loading…
Reference in New Issue
Block a user