less blocking - targets will try to path to any space around their tar

This commit is contained in:
Llywelwyn 2023-08-30 09:15:45 +01:00
parent 340aefa9e1
commit 64caf0dc1a
16 changed files with 252 additions and 68 deletions

View file

@ -7,6 +7,7 @@ pub struct ApproachAI {}
impl<'a> System<'a> for ApproachAI {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteExpect<'a, RandomNumberGenerator>,
WriteStorage<'a, TakingTurn>,
WriteStorage<'a, WantsToApproach>,
WriteStorage<'a, Position>,
@ -19,6 +20,7 @@ impl<'a> System<'a> for ApproachAI {
fn run(&mut self, data: Self::SystemData) {
let (
mut rng,
mut turns,
mut wants_to_approach,
mut positions,
@ -37,11 +39,26 @@ impl<'a> System<'a> for ApproachAI {
&turns,
).join() {
turn_done.push(entity);
let path = a_star_search(
map.xy_idx(pos.x, pos.y) as i32,
map.xy_idx(approach.idx % map.width, approach.idx / map.width) as i32,
&mut *map
);
let target_idxs = if let Some(paths) = get_adjacent_unblocked(&map, approach.idx as usize) {
paths
} else {
continue;
};
let mut path: Option<NavigationPath> = None;
let idx = map.xy_idx(pos.x, pos.y);
for tar_idx in target_idxs {
let potential_path = rltk::a_star_search(idx, tar_idx, &mut *map);
if potential_path.success && potential_path.steps.len() > 1 {
if path.is_none() || potential_path.steps.len() < path.as_ref().unwrap().steps.len() {
path = Some(potential_path);
}
}
}
let path = if path.is_some() {
path.unwrap()
} else {
continue;
};
if path.success && path.steps.len() > 1 {
let idx = map.xy_idx(pos.x, pos.y);
pos.x = (path.steps[1] as i32) % map.width;
@ -61,3 +78,25 @@ impl<'a> System<'a> for ApproachAI {
}
}
}
/// Try to get an unblocked index within one tile of a given idx, or None.
pub fn get_adjacent_unblocked(map: &WriteExpect<Map>, idx: usize) -> Option<Vec<usize>> {
let mut adjacent = Vec::new();
let x = (idx as i32) % map.width;
let y = (idx as i32) / map.width;
for i in -1..2 {
for j in -1..2 {
if i == 0 && j == 0 {
continue;
}
let new_idx = (x + i + (y + j) * map.width) as usize;
if !crate::spatial::is_blocked(new_idx) {
adjacent.push(new_idx);
}
}
}
if adjacent.is_empty() {
return None;
}
return Some(adjacent);
}

View file

@ -2,6 +2,7 @@ use crate::{ Chasing, EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed
use rltk::prelude::*;
use specs::prelude::*;
use std::collections::HashMap;
use super::approach_ai_system::get_adjacent_unblocked;
// If the target is beyond this distance, they're no longer being detected,
// so stop following them. This is essentially a combined value of the sound
@ -57,11 +58,27 @@ impl<'a> System<'a> for ChaseAI {
).join() {
turn_done.push(entity);
let target_pos = targets[&entity];
let path = a_star_search(
map.xy_idx(pos.x, pos.y) as i32,
map.xy_idx(target_pos.0, target_pos.1) as i32,
&mut *map
);
let target_idx = map.xy_idx(target_pos.0, target_pos.1);
let target_idxs = if let Some(paths) = get_adjacent_unblocked(&map, target_idx) {
paths
} else {
continue;
};
let mut path: Option<NavigationPath> = None;
let idx = map.xy_idx(pos.x, pos.y);
for tar_idx in target_idxs {
let potential_path = rltk::a_star_search(idx, tar_idx, &mut *map);
if potential_path.success && potential_path.steps.len() > 1 {
if path.is_none() || potential_path.steps.len() < path.as_ref().unwrap().steps.len() {
path = Some(potential_path);
}
}
}
let path = if path.is_some() {
path.unwrap()
} else {
continue;
};
if path.success && path.steps.len() > 1 && path.steps.len() < MAX_CHASE_DISTANCE {
let idx = map.xy_idx(pos.x, pos.y);
pos.x = (path.steps[1] as i32) % map.width;