cargo fmt again

This commit is contained in:
2024-07-12 10:00:27 -05:00
parent a161aacaca
commit f9ce96bbce
2 changed files with 61 additions and 83 deletions

View File

@@ -2,7 +2,7 @@ use std::time::Duration;
use bevy::{prelude::*, sprite::MaterialMesh2dBundle}; use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
use bevy_spatial::{ use bevy_spatial::{
kdtree::KDTree2, AutomaticUpdate, SpatialAccess, SpatialStructure, TransformMode kdtree::KDTree2, AutomaticUpdate, SpatialAccess, SpatialStructure, TransformMode,
}; };
const BACKGROUND_COLOR: Color = Color::srgb(0.4, 0.4, 0.4); const BACKGROUND_COLOR: Color = Color::srgb(0.4, 0.4, 0.4);
@@ -17,14 +17,17 @@ pub struct BoidsPlugin;
impl Plugin for BoidsPlugin { impl Plugin for BoidsPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app app.add_plugins(
.add_plugins(AutomaticUpdate::<TrackedByKdTree>::new() AutomaticUpdate::<TrackedByKdTree>::new()
// .with_frequency(Duration::from_secs_f32(0.3)) // .with_frequency(Duration::from_secs_f32(0.3))
.with_transform(TransformMode::GlobalTransform) .with_transform(TransformMode::GlobalTransform)
.with_spatial_ds(SpatialStructure::KDTree2)) .with_spatial_ds(SpatialStructure::KDTree2),
.insert_resource(ClearColor(BACKGROUND_COLOR)) )
.add_systems(Startup, (spawn_camera, spawn_boids)) .insert_resource(ClearColor(BACKGROUND_COLOR))
.add_systems(FixedUpdate, ( .add_systems(Startup, (spawn_camera, spawn_boids))
.add_systems(
FixedUpdate,
(
apply_velocity, apply_velocity,
turn_if_edge, turn_if_edge,
check_keyboard, check_keyboard,
@@ -32,7 +35,8 @@ impl Plugin for BoidsPlugin {
separation, separation,
alignment, alignment,
// space_brakes, // space_brakes,
)); ),
);
} }
} }
@@ -144,7 +148,7 @@ fn turn_if_edge(
fn apply_velocity( fn apply_velocity(
mut query: Query<(&mut Transform, &Velocity, &mut Acceleration)>, mut query: Query<(&mut Transform, &Velocity, &mut Acceleration)>,
time: Res<Time> time: Res<Time>,
) { ) {
for (mut transform, velocity, mut acceleration) in &mut query { for (mut transform, velocity, mut acceleration) in &mut query {
let delta_v = **acceleration * time.delta_seconds(); let delta_v = **acceleration * time.delta_seconds();
@@ -191,13 +195,8 @@ fn cohesion(
// find vector from boid to flock CoM // find vector from boid to flock CoM
// apply force // apply force
for (transform, mut acceleration) in &mut boids { for (transform, mut acceleration) in &mut boids {
let neighbors = spatial_tree.within_distance( let neighbors = spatial_tree.within_distance(transform.translation.xy(), BOID_VIEW_RANGE);
transform.translation.xy(), if let Some(center_mass) = center_of_boids(neighbors.iter().map(|boid| boid.0)) {
BOID_VIEW_RANGE
);
if let Some(center_mass) = center_of_boids(
neighbors.iter().map(|boid| boid.0 )
) {
let towards = (center_mass.extend(0.0) - transform.translation).normalize(); let towards = (center_mass.extend(0.0) - transform.translation).normalize();
acceleration.0 += towards * COHESION_FACTOR; acceleration.0 += towards * COHESION_FACTOR;
} }
@@ -213,16 +212,15 @@ fn separation(
// sum force from neighbors // sum force from neighbors
// apply force // apply force
for (boid_transform, mut boid_acceleration) in &mut boids { for (boid_transform, mut boid_acceleration) in &mut boids {
let neighbors = spatial_tree.within_distance( let neighbors =
boid_transform.translation.xy(), spatial_tree.within_distance(boid_transform.translation.xy(), BOID_VIEW_RANGE / 4.0);
BOID_VIEW_RANGE / 4.0, let accel = neighbors.iter().map(|(pos, _)| pos.extend(0.0)).fold(
); Vec3::ZERO,
let accel = neighbors.iter() |accumulator, neighbor| {
.map(|(pos, _)| pos.extend(0.0))
.fold(Vec3::ZERO, |accumulator, neighbor |{
let force = separation_force(boid_transform.translation.xy(), neighbor.xy()); let force = separation_force(boid_transform.translation.xy(), neighbor.xy());
accumulator + *force accumulator + *force
}); },
);
boid_acceleration.0 += accel; boid_acceleration.0 += accel;
} }
} }
@@ -246,23 +244,22 @@ fn alignment(
// apply steering force // apply steering force
for (transform, velocity, mut acceleration) in &mut boids { for (transform, velocity, mut acceleration) in &mut boids {
let neighbors = spatial_tree.within_distance( let neighbors = spatial_tree.within_distance(transform.translation.xy(), BOID_VIEW_RANGE);
transform.translation.xy(),
BOID_VIEW_RANGE,
);
// averaging divides by length. Guard against an empty set of neighbors // averaging divides by length. Guard against an empty set of neighbors
// so that we don't divide by zero. // so that we don't divide by zero.
if neighbors.len() > 0 { if neighbors.len() > 0 {
if let Some(avg_velocity) = velocity_of_boids( if let Some(avg_velocity) =
neighbors.iter().map(|(vel, opt_entity)| { velocity_of_boids(neighbors.iter().map(|(vel, opt_entity)| {
// I've observed no panics in the old version, nor the debug_plugins version // I've observed no panics in the old version, nor the debug_plugins version
// I'm not clear on the conditions that cause a None option, but I want to // I'm not clear on the conditions that cause a None option, but I want to
// crash when I find one. // crash when I find one.
let entity_id = opt_entity.unwrap_or_else(|| panic!("Boid has no Entity ID!")); let entity_id = opt_entity.unwrap_or_else(|| panic!("Boid has no Entity ID!"));
let vel = boid_velocities.get(entity_id).unwrap_or_else(|_| panic!("Boid has no velocity!")); let vel = boid_velocities
.get(entity_id)
.unwrap_or_else(|_| panic!("Boid has no velocity!"));
(*vel).xy() (*vel).xy()
}) }))
) { {
let deviation = -velocity.0 + avg_velocity.extend(0.0); let deviation = -velocity.0 + avg_velocity.extend(0.0);
acceleration.0 += deviation * ALIGNMENT_FACTOR; acceleration.0 += deviation * ALIGNMENT_FACTOR;
} }
@@ -270,7 +267,6 @@ fn alignment(
} }
} }
pub(crate) fn center_of_boids(points: impl Iterator<Item = Vec2>) -> Option<Vec2> { pub(crate) fn center_of_boids(points: impl Iterator<Item = Vec2>) -> Option<Vec2> {
average_of_vec2s(points) average_of_vec2s(points)
} }
@@ -285,20 +281,18 @@ fn average_of_vec2s(points: impl Iterator<Item = Vec2>) -> Option<Vec2> {
// Passing the points as an iterator means we lose the length of the // Passing the points as an iterator means we lose the length of the
// list. The `.enumerate()` iterator reintroduces that count. // list. The `.enumerate()` iterator reintroduces that count.
let mut points = points.enumerate(); let mut points = points.enumerate();
// Empty iterators have no points and so no center of mass. // Empty iterators have no points and so no center of mass.
// Try to get the first one, but exit with None if it doesn't yield. // Try to get the first one, but exit with None if it doesn't yield.
let init = points.next()?; let init = points.next()?;
// if we get one, fold all the remaining values into it. // if we get one, fold all the remaining values into it.
let (len, sum) = points.fold( let (len, sum) = points.fold(init, |(len, sum), (idx, point)| {
init, // replace length with most recent index
|(len, sum), (idx, point)| { // add running sum & new point for new running sum
// replace length with most recent index (idx, sum + point)
// add running sum & new point for new running sum });
(idx, sum + point)
});
let avg = sum / ((len + 1) as f32); let avg = sum / ((len + 1) as f32);
Some(avg) Some(avg)
} }

View File

@@ -1,11 +1,8 @@
use bevy::{prelude::*, sprite::MaterialMesh2dBundle, window::PrimaryWindow}; use bevy::{prelude::*, sprite::MaterialMesh2dBundle, window::PrimaryWindow};
use bevy_spatial::{ use bevy_spatial::{kdtree::KDTree2, SpatialAccess};
kdtree::KDTree2,
SpatialAccess,
};
use crate::birdoids_plugin::{ use crate::birdoids_plugin::{
center_of_boids, velocity_of_boids, Acceleration, Boid, TrackedByKdTree, Velocity center_of_boids, velocity_of_boids, Acceleration, Boid, TrackedByKdTree, Velocity,
}; };
const SCANRADIUS: f32 = 50.0; const SCANRADIUS: f32 = 50.0;
@@ -14,11 +11,7 @@ pub struct BoidsDebugPlugin;
impl Plugin for BoidsDebugPlugin { impl Plugin for BoidsDebugPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Startup, setup) app.add_systems(Startup, setup)
.add_systems(FixedUpdate, ( .add_systems(FixedUpdate, (update_cursor, update_scanner_mode, do_scan));
update_cursor,
update_scanner_mode,
do_scan,
));
} }
} }
@@ -30,7 +23,9 @@ fn setup(
commands.spawn(( commands.spawn((
ScannerWidget::default(), ScannerWidget::default(),
MaterialMesh2dBundle { MaterialMesh2dBundle {
mesh: meshes.add(Annulus::new(SCANRADIUS - 1.0, SCANRADIUS)).into(), mesh: meshes
.add(Annulus::new(SCANRADIUS - 1.0, SCANRADIUS))
.into(),
material: materials.add(Color::srgb(0.0, 0.0, 0.0)), material: materials.add(Color::srgb(0.0, 0.0, 0.0)),
..default() ..default()
}, },
@@ -96,11 +91,11 @@ fn update_cursor(
fn update_scanner_mode( fn update_scanner_mode(
keycodes: Res<ButtonInput<KeyCode>>, keycodes: Res<ButtonInput<KeyCode>>,
mousebuttons: Res<ButtonInput<MouseButton>>, mousebuttons: Res<ButtonInput<MouseButton>>,
mut scanner_query: Query<(&mut SelectionMode, &mut ScannerMode), With<Cursor>>, mut scanner_query: Query<(&mut SelectionMode, &mut ScannerMode), With<Cursor>>,
) { ) {
// I'm making another assertion that there is exactly one scanner. // I'm making another assertion that there is exactly one scanner.
let (mut select_mode, mut scan_mode) = scanner_query.get_single_mut().unwrap(); let (mut select_mode, mut scan_mode) = scanner_query.get_single_mut().unwrap();
// Assign selection mode // Assign selection mode
if keycodes.just_pressed(KeyCode::Digit1) { if keycodes.just_pressed(KeyCode::Digit1) {
*select_mode = SelectionMode::NearestSingle; *select_mode = SelectionMode::NearestSingle;
@@ -116,9 +111,7 @@ fn update_scanner_mode(
} }
} }
fn print_gizmo_config( fn print_gizmo_config(query: Query<(&SelectionMode, &ScannerMode), With<Cursor>>) {
query: Query<(&SelectionMode, &ScannerMode), With<Cursor>>,
) {
let (select, scan) = query.get_single().unwrap(); let (select, scan) = query.get_single().unwrap();
println!("Selection: {select:?}, Scanning: {scan:?}"); println!("Selection: {select:?}, Scanning: {scan:?}");
} }
@@ -134,43 +127,34 @@ fn do_scan(
match select_mode { match select_mode {
SelectionMode::NearestSingle => todo!(), SelectionMode::NearestSingle => todo!(),
SelectionMode::CircularArea => { SelectionMode::CircularArea => {
let boids = spatial_tree.within_distance( let boids = spatial_tree.within_distance(cursor_pos.translation.xy(), SCANRADIUS);
cursor_pos.translation.xy(),
SCANRADIUS,
);
match scan_mode { match scan_mode {
ScannerMode::CenterOfMass => { ScannerMode::CenterOfMass => {
if let Some(center_mass) = center_of_boids( if let Some(center_mass) = center_of_boids(
// boids returns too many things. // boids returns too many things.
// Map over it and extract only the Vec3's // Map over it and extract only the Vec3's
boids.iter().map(|item| { boids.iter().map(|item| item.0),
item.0
})
) { ) {
gizmos.circle_2d( gizmos.circle_2d(center_mass, 1.0, bevy::color::palettes::css::RED);
center_mass,
1.0,
bevy::color::palettes::css::RED
);
} }
}, }
ScannerMode::Velocity => { ScannerMode::Velocity => {
if let Some(avg_velocity) = velocity_of_boids( if let Some(avg_velocity) = velocity_of_boids(boids.iter().map(|item| {
boids.iter().map(|item| { let entity_id = item.1.unwrap_or_else(|| panic!("Entity has no ID!"));
let entity_id = item.1.unwrap_or_else(|| panic!("Entity has no ID!")); let (_, vel, _) = boids_query
let (_, vel, _) = boids_query.get(entity_id).unwrap_or_else(|_| panic!("Boid has no Velocity component!")); .get(entity_id)
(*vel).xy() * 1.0 .unwrap_or_else(|_| panic!("Boid has no Velocity component!"));
}) (*vel).xy() * 1.0
) { })) {
// cursor_pos.translation is already in world space, so I can skip the window -> world transform like in update_cursor() // cursor_pos.translation is already in world space, so I can skip the window -> world transform like in update_cursor()
gizmos.line_2d( gizmos.line_2d(
cursor_pos.translation.xy(), cursor_pos.translation.xy(),
cursor_pos.translation.xy() + avg_velocity, cursor_pos.translation.xy() + avg_velocity,
bevy::color::palettes::css::RED bevy::color::palettes::css::RED,
); );
} }
}, }
} }
}, }
} }
} }