use crate::prelude::*;
use beet_core::prelude::*;
use beet_flow::prelude::*;
#[derive(Debug, Clone, PartialEq, Component, Reflect)]
#[reflect(Default, Component)]
#[require(ContinueRun)]
pub struct Wander {
pub scalar: f32,
pub outer_distance: f32,
pub outer_radius: f32,
pub inner_radius: f32,
pub last_local_target: Vec3,
}
impl Default for Wander {
fn default() -> Self {
Self {
scalar: 1.,
outer_distance: 1.,
outer_radius: 0.5,
inner_radius: 0.05,
last_local_target: Vec3::ZERO,
}
}
}
impl Wander {
pub fn new(scalar: f32) -> Self {
Self {
scalar,
..default()
}
}
pub fn scaled_dist(mut self, dist: f32) -> Self {
self.outer_distance *= dist;
self.outer_radius *= dist;
self.inner_radius *= dist;
self
}
pub fn default_forward() -> Self {
Self {
last_local_target: Vec3::new(0., 0., -1.),
..default()
}
}
pub fn default_right() -> Self {
Self {
last_local_target: Vec3::RIGHT,
..default()
}
}
}
pub(crate) fn wander(
mut rng: ResMut<RandomSource>,
mut agents: AgentQuery<(&Transform, &Velocity, &MaxSpeed, &mut Impulse)>,
mut query: Query<(Entity, &mut Wander), With<Running>>,
) -> Result {
for (action, mut wander) in query.iter_mut() {
let (transform, velocity, max_speed, mut impulse) =
agents.get_mut(action)?;
**impulse += *wander_impulse(
&transform.translation,
&velocity,
&mut wander,
*max_speed,
&mut rng.0,
);
}
Ok(())
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use beet_core::prelude::*;
use beet_flow::prelude::*;
#[test]
fn works() {
let mut app = App::new();
app.add_plugins((
ControlFlowPlugin::default(),
BeetSpatialPlugins::default(),
))
.insert_time();
let agent = app
.world_mut()
.spawn((
Transform::default(),
ForceBundle::default(),
SteerBundle::default(),
))
.with_children(|parent| {
parent.spawn((
OnSpawn::trigger(GetOutcome),
ContinueRun,
Wander::default(),
));
})
.id();
app.update();
app.update_with_secs(1);
app.world()
.entity(agent)
.get::<Transform>()
.unwrap()
.translation
.xpect_not_eq(Vec3::ZERO);
}
}