Made agents cleverer

This commit is contained in:
Joshua Barretto 2020-04-19 12:50:25 +01:00
parent 8af3187df4
commit d28f5f24fb
2 changed files with 53 additions and 28 deletions

View File

@ -25,6 +25,7 @@ impl Alignment {
// Never attacks
pub fn passive_towards(self, other: Alignment) -> bool {
match (self, other) {
(Alignment::Enemy, Alignment::Enemy) => true,
(Alignment::Owned(a), Alignment::Owned(b)) if a == b => true,
_ => false,
}

View File

@ -1,5 +1,5 @@
use crate::{
comp::{self, agent::Activity, Agent, Alignment, Controller, MountState, Ori, Scale, Pos, Stats, Loadout, item::{ItemKind, tool::ToolKind}, CharacterState},
comp::{self, agent::Activity, Agent, Alignment, Controller, ControlAction, MountState, Ori, Scale, Pos, Stats, Loadout, item::{ItemKind, tool::ToolKind}, CharacterState},
path::Chaser,
state::{Time, DeltaTime},
sync::UidAllocator,
@ -92,7 +92,8 @@ impl<'a> System<'a> for Sys {
const AVG_FOLLOW_DIST: f32 = 6.0;
const MAX_FOLLOW_DIST: f32 = 12.0;
const MAX_CHASE_DIST: f32 = 24.0;
const SEARCH_DIST: f32 = 30.0;
const LISTEN_DIST: f32 = 16.0;
const SEARCH_DIST: f32 = 48.0;
const SIGHT_DIST: f32 = 128.0;
const MIN_ATTACK_DIST: f32 = 3.25;
@ -124,7 +125,7 @@ impl<'a> System<'a> for Sys {
+ Vec3::from(*bearing)
.try_normalized()
.unwrap_or(Vec3::unit_y())
* 1.5
* 5.0
+ Vec3::unit_z(),
)
.until(|block| block.is_solid())
@ -142,8 +143,18 @@ impl<'a> System<'a> for Sys {
inputs.move_dir = *bearing * 0.65;
}
// Put away weapon
if thread_rng().gen::<f32>() < 0.005 {
controller.actions.push(ControlAction::Unwield);
}
// Sit
if thread_rng().gen::<f32>() < 0.0035 {
controller.actions.push(ControlAction::Sit);
}
// Sometimes try searching for new targets
if thread_rng().gen::<f32>() < 0.1 {
if thread_rng().gen::<f32>() < 0.05 {
choose_target = true;
}
},
@ -177,9 +188,9 @@ impl<'a> System<'a> for Sys {
..
} => {
enum Tactic {
Melee, // Attack: primary/secondary
Melee,
RangedPowerup,
RangedConstant,
Staff,
}
let tactic = match loadout.active_item
@ -187,7 +198,7 @@ impl<'a> System<'a> for Sys {
.and_then(|ic| if let ItemKind::Tool(tool) = &ic.item.kind { Some(&tool.kind) } else { None})
{
Some(ToolKind::Bow(_)) => Tactic::RangedPowerup,
Some(ToolKind::Staff(_)) => Tactic::RangedConstant,
Some(ToolKind::Staff(_)) => Tactic::Staff,
_ => Tactic::Melee,
};
@ -223,34 +234,40 @@ impl<'a> System<'a> for Sys {
if let Tactic::Melee = tactic {
inputs.primary.set_state(true);
} else if let Tactic::RangedPowerup = tactic {
} else if let Tactic::Staff = tactic {
inputs.primary.set_state(true);
} else {
inputs.move_dir = -Vec2::from(tgt_pos.0 - pos.0)
.try_normalized()
.unwrap_or(Vec2::unit_y());
inputs.roll.set_state(true);
}
} else if dist_sqrd < MAX_CHASE_DIST.powf(2.0)
|| (dist_sqrd < SIGHT_DIST.powf(2.0) && !*been_close)
{
if let Tactic::RangedPowerup = tactic {
if *powerup > 2.0 {
inputs.primary.set_state(false);
*powerup = 0.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
} else if let Tactic::RangedConstant = tactic {
if !character_state.is_wield() {
inputs.primary.set_state(true);
let can_see_tgt = terrain
.ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z())
.until(|block| !block.is_air())
.cast()
.0.powf(2.0) >= dist_sqrd;
if can_see_tgt {
if let Tactic::RangedPowerup = tactic {
if *powerup > 2.0 {
inputs.primary.set_state(false);
*powerup = 0.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
} else if let Tactic::Staff = tactic {
if !character_state.is_wield() {
inputs.primary.set_state(true);
}
inputs.secondary.set_state(true);
}
inputs.secondary.set_state(true);
}
if dist_sqrd < MAX_CHASE_DIST.powf(2.0) {
*been_close = true;
if dist_sqrd < MAX_CHASE_DIST.powf(2.0) {
*been_close = true;
}
}
// Long-range chase
@ -290,13 +307,20 @@ impl<'a> System<'a> for Sys {
let closest_entity = (&entities, &positions, &stats, alignments.maybe())
.join()
.filter(|(e, e_pos, e_stats, e_alignment)| {
e_pos.0.distance_squared(pos.0) < SEARCH_DIST.powf(2.0)
((e_pos.0.distance_squared(pos.0) < SEARCH_DIST.powf(2.0) && (e_pos.0 - pos.0).try_normalized().map(|v| v.dot(*inputs.look_dir) > 0.3).unwrap_or(true))
|| e_pos.0.distance_squared(pos.0) < LISTEN_DIST.powf(2.0))
&& *e != entity
&& !e_stats.is_dead
&& alignment
.and_then(|a| e_alignment.map(|b| a.hostile_towards(*b)))
.unwrap_or(false)
})
// Can we even see them?
.filter(|(_, e_pos, _, _)| terrain
.ray(pos.0 + Vec3::unit_z(), e_pos.0 + Vec3::unit_z())
.until(|block| !block.is_air())
.cast()
.0 >= e_pos.0.distance(pos.0))
.min_by_key(|(_, e_pos, _, _)| (e_pos.0.distance_squared(pos.0) * 100.0) as i32)
.map(|(e, _, _, _)| e);