Improved water pathfinding

This commit is contained in:
Joshua Barretto 2020-11-14 23:45:27 +00:00
parent 71b7e1ef90
commit de685b00b2
8 changed files with 83 additions and 36 deletions

View File

@ -139,6 +139,7 @@ void main() {
// f_pos = v_pos + (model_offs - focus_off.xyz);
f_pos = (inst_mat * vec4(v_pos_, 1.0)).xyz * SCALE + inst_offs;
f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
// f_pos = (inst_mat * v_pos_) * SCALE + sprite_pos;
// f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz + (model_offs - focus_off.xyz);

View File

@ -131,17 +131,18 @@ impl Route {
// Determine whether we're close enough to the next to to consider it completed
let dist_sqrd = pos.xy().distance_squared(closest_tgt.xy());
if dist_sqrd < traversal_cfg.node_tolerance.powf(2.0) * if be_precise { 0.25 } else { 1.0 }
&& (pos.z - closest_tgt.z > 1.2 || (pos.z - closest_tgt.z > -0.2 && (traversal_cfg.on_ground || traversal_cfg.in_liquid)))
&& (pos.z - closest_tgt.z < 1.2 || (pos.z - closest_tgt.z < 2.9 && vel.z < -0.05))
&& vel.z <= 0.0
// Only consider the node reached if there's nothing solid between us and it
&& (vol
.ray(pos + Vec3::unit_z() * 1.5, closest_tgt + Vec3::unit_z() * 1.5)
.until(Block::is_solid)
.cast()
.0
> pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5)
&& self.next_idx < self.path.len()
&& (((pos.z - closest_tgt.z > 1.2 || (pos.z - closest_tgt.z > -0.2 && traversal_cfg.on_ground))
&& (pos.z - closest_tgt.z < 1.2 || (pos.z - closest_tgt.z < 2.9 && vel.z < -0.05))
&& vel.z <= 0.0
// Only consider the node reached if there's nothing solid between us and it
&& (vol
.ray(pos + Vec3::unit_z() * 1.5, closest_tgt + Vec3::unit_z() * 1.5)
.until(Block::is_solid)
.cast()
.0
> pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5)
&& self.next_idx < self.path.len())
|| (traversal_cfg.in_liquid && pos.z < closest_tgt.z + 0.8 && pos.z > closest_tgt.z))
{
// Node completed, move on to the next one
self.next_idx += 1;
@ -419,7 +420,7 @@ impl Chaser {
vol.get(
(pos + Vec3::<f32>::from(tgt_dir) * 2.5).map(|e| e as i32) + Vec3::unit_z() * z,
)
.map(|b| !b.is_solid())
.map(|b| b.is_air())
.unwrap_or(false)
});
@ -437,17 +438,22 @@ fn walkable<V>(vol: &V, pos: Vec3<i32>) -> bool
where
V: BaseVol<Vox = Block> + ReadVol,
{
vol.get(pos - Vec3::new(0, 0, 1))
.map(|b| b.is_filled())
.unwrap_or(false)
&& vol
.get(pos + Vec3::new(0, 0, 0))
.map(|b| !b.is_filled())
.unwrap_or(true)
&& vol
.get(pos + Vec3::new(0, 0, 1))
.map(|b| !b.is_filled())
.unwrap_or(true)
let below = vol.get(pos - Vec3::unit_z())
.ok()
.copied()
.unwrap_or_else(Block::empty);
let a = vol.get(pos)
.ok()
.copied()
.unwrap_or_else(Block::empty);
let b = vol.get(pos + Vec3::unit_z())
.ok()
.copied()
.unwrap_or_else(Block::empty);
let on_ground = below.is_filled();
let in_liquid = a.is_liquid();
(on_ground || in_liquid) && !a.is_solid() && !b.is_solid()
}
/// Attempt to search for a path to a target, returning the path (if one was
@ -546,17 +552,17 @@ where
&& ((dir.z < 1
|| vol
.get(pos + Vec3::unit_z() * 2)
.map(|b| !b.is_filled())
.map(|b| !b.is_solid())
.unwrap_or(true))
&& (dir.z < 2
|| vol
.get(pos + Vec3::unit_z() * 3)
.map(|b| !b.is_filled())
.map(|b| !b.is_solid())
.unwrap_or(true))
&& (dir.z >= 0
|| vol
.get(pos + *dir + Vec3::unit_z() * 2)
.map(|b| !b.is_filled())
.map(|b| !b.is_solid())
.unwrap_or(true)))
})
.map(move |(pos, dir)| pos + dir)

View File

@ -239,9 +239,9 @@ impl<'a> System<'a> for Sys {
.unwrap_or(Vec2::zero())
* speed.min(agent.rtsim_controller.speed_factor);
inputs.jump.set_state(bearing.z > 1.5);
inputs.climb = Some(comp::Climb::Up)
.filter(|_| bearing.z > 1.5 || physics_state.in_liquid.is_some());
inputs.move_z = bearing.z;
inputs.climb = Some(comp::Climb::Up);
//.filter(|_| bearing.z > 0.1 || physics_state.in_liquid.is_some());
inputs.move_z = bearing.z + 0.05;
}
} else {
*bearing += Vec2::new(

View File

@ -116,11 +116,15 @@ impl TerrainGrid {
let mut z_diff = 0;
for _ in 0..128 {
let test_pos = pos + Vec3::unit_z() * z_diff;
if (0..2)
.all(|z| self
.get(test_pos + Vec3::unit_z() * z)
.map(|b| !b.is_solid())
.unwrap_or(true))
if self
.get(test_pos - Vec3::unit_z())
.map(|b| b.is_filled())
.unwrap_or(false)
&& (0..2)
.all(|z| self
.get(test_pos + Vec3::unit_z() * z)
.map(|b| !b.is_solid())
.unwrap_or(true))
{
return test_pos;
}

View File

@ -101,7 +101,7 @@ impl Entity {
let travel_to = self.pos.xy() + Vec3::from((wpos.map(|e| e as f32 + 0.5) - self.pos.xy())
.try_normalized()
.unwrap_or_else(Vec2::zero)) * 32.0;
.unwrap_or_else(Vec2::zero)) * 64.0;
let travel_to_alt = world.sim().get_alt_approx(travel_to.map(|e| e as i32)).unwrap_or(0.0) as i32;
let travel_to = terrain.find_space(Vec3::new(travel_to.x as i32, travel_to.y as i32, travel_to_alt)).map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0);
self.controller.travel_to = Some(travel_to);

View File

@ -87,7 +87,7 @@ pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
pub fn init(state: &mut State, world: &world::World) {
let mut rtsim = RtSim::new(world.sim().get_size());
for _ in 0..10000 {
for _ in 0..2500 {
let pos = rtsim.chunks.size().map2(
TerrainChunk::RECT_SIZE,
|sz, chunk_sz| thread_rng().gen_range(0, sz * chunk_sz) as i32,

View File

@ -24,6 +24,7 @@ pub mod sim;
pub mod sim2;
pub mod site;
pub mod util;
pub mod pathfinding;
// Reexports
pub use crate::{

35
world/src/pathfinding.rs Normal file
View File

@ -0,0 +1,35 @@
use crate::sim::WorldSim;
use common::{
astar::Astar,
path::Path,
};
use hashbrown::hash_map::DefaultHashBuilder;
use vek::*;
pub struct SearchCfg {
// 0.0 = no discount, 1.0 = free travel
path_discount: f32,
// Cost per metre altitude change per metre horizontal
// 0.0 = no cost, 1.0 = same cost vertical as horizontal
gradient_aversion: f32,
}
pub struct Searcher<'a> {
land: &'a WorldSim,
pub cfg: SearchCfg,
}
impl<'a> Searcher<'a> {
/// Attempt to find a path between two chunks on the map.
pub fn search(self, a: Vec2<i32>, b: Vec2<i32>) -> Option<Path<i32>> {
let heuristic = |pos: &Vec2<i32>| (pos - b).map(|e| e as f32).magnitude();
// Astar::new(
// 100_000,
// a,
// heuristc,
// DefaultHashBuilder::default(),
// );
None
}
}