use parallel iter to update velocities
This commit is contained in:
parent
c366dc3ec6
commit
5158fba63b
3 changed files with 86 additions and 69 deletions
BIN
assets/models/toid3.glb
Normal file
BIN
assets/models/toid3.glb
Normal file
Binary file not shown.
151
src/lib.rs
151
src/lib.rs
|
@ -1,6 +1,7 @@
|
||||||
use argh::FromArgs;
|
use argh::FromArgs;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
tasks::ParallelIterator,
|
||||||
utils::{HashMap, HashSet},
|
utils::{HashMap, HashSet},
|
||||||
};
|
};
|
||||||
use bevy_spatial::{kdtree::KDTree3, SpatialAccess};
|
use bevy_spatial::{kdtree::KDTree3, SpatialAccess};
|
||||||
|
@ -8,7 +9,7 @@ use bevy_spatial::{kdtree::KDTree3, SpatialAccess};
|
||||||
pub type NNTree = KDTree3<Toid>;
|
pub type NNTree = KDTree3<Toid>;
|
||||||
|
|
||||||
// toid stuff
|
// toid stuff
|
||||||
const SPEED: f32 = 10.0;
|
const SPEED: f32 = 15.0;
|
||||||
const SPEED_DIFF_RANGE: f32 = 0.1; // +/- 10%
|
const SPEED_DIFF_RANGE: f32 = 0.1; // +/- 10%
|
||||||
const MAX_DELTA_V: f32 = std::f32::consts::PI * 2.0; // basically 360 degrees/sec
|
const MAX_DELTA_V: f32 = std::f32::consts::PI * 2.0; // basically 360 degrees/sec
|
||||||
|
|
||||||
|
@ -16,9 +17,9 @@ const MAX_DELTA_V: f32 = std::f32::consts::PI * 2.0; // basically 360 degrees/se
|
||||||
const RADIUS: f32 = 50.0;
|
const RADIUS: f32 = 50.0;
|
||||||
|
|
||||||
// how close to try to stay to your buddies
|
// how close to try to stay to your buddies
|
||||||
const BUDDY_RADIUS: f32 = 10.0;
|
const BUDDY_RADIUS: f32 = SPEED;
|
||||||
|
|
||||||
const MIN_ALTITUDE: f32 = 3.5;
|
const MIN_ALTITUDE: f32 = 13.5;
|
||||||
|
|
||||||
#[derive(Debug, FromArgs, Resource)]
|
#[derive(Debug, FromArgs, Resource)]
|
||||||
/// Toid Watching
|
/// Toid Watching
|
||||||
|
@ -43,6 +44,9 @@ pub struct Toid {
|
||||||
pub buddies: usize,
|
pub buddies: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Deref, DerefMut, Clone, Default)]
|
||||||
|
pub struct Paused(bool);
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)]
|
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)]
|
||||||
pub struct LookAt(Vec3);
|
pub struct LookAt(Vec3);
|
||||||
|
|
||||||
|
@ -60,7 +64,6 @@ pub fn turkey_time(
|
||||||
let y = r.gen_range(0.1..=5.5);
|
let y = r.gen_range(0.1..=5.5);
|
||||||
let pos = Vec3::new(x, MIN_ALTITUDE + y, z);
|
let pos = Vec3::new(x, MIN_ALTITUDE + y, z);
|
||||||
let xform = Transform::from_translation(pos);
|
let xform = Transform::from_translation(pos);
|
||||||
//dbg!(xform);
|
|
||||||
let spatial_bundle = (xform, Visibility::Visible);
|
let spatial_bundle = (xform, Visibility::Visible);
|
||||||
commands
|
commands
|
||||||
.spawn(spatial_bundle)
|
.spawn(spatial_bundle)
|
||||||
|
@ -68,10 +71,6 @@ pub fn turkey_time(
|
||||||
.with_children(|t| {
|
.with_children(|t| {
|
||||||
t.spawn(SceneRoot(scene.to_owned()))
|
t.spawn(SceneRoot(scene.to_owned()))
|
||||||
.insert(Transform::default());
|
.insert(Transform::default());
|
||||||
// .insert(Transform::from_rotation(Quat::from_axis_angle(
|
|
||||||
// Vec3::Y,
|
|
||||||
// -std::f32::consts::FRAC_PI_2,
|
|
||||||
// )));
|
|
||||||
})
|
})
|
||||||
.id()
|
.id()
|
||||||
}
|
}
|
||||||
|
@ -81,72 +80,79 @@ pub fn update_vel(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
positions: Res<Positions>,
|
positions: Res<Positions>,
|
||||||
index: Res<NNTree>,
|
index: Res<NNTree>,
|
||||||
|
paused: Res<Paused>,
|
||||||
) {
|
) {
|
||||||
|
if **paused {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let dt = time.delta_secs();
|
let dt = time.delta_secs();
|
||||||
let max_delta = MAX_DELTA_V * dt;
|
let max_delta = MAX_DELTA_V * dt;
|
||||||
for (xform, mut vel, toid, buddies, entity) in toids.iter_mut() {
|
toids
|
||||||
let speed = toid.speed;
|
.par_iter_mut()
|
||||||
let mut dir = vel.normalize();
|
.for_each(|(xform, mut vel, toid, buddies, entity)| {
|
||||||
let pos = xform.translation;
|
let speed = toid.speed;
|
||||||
let original_dir = dir;
|
let mut dir = vel.normalize();
|
||||||
|
let pos = xform.translation;
|
||||||
|
let original_dir = dir;
|
||||||
|
|
||||||
// find buddies and orient; point more towards further-away buddies
|
// find buddies and orient; point more towards further-away buddies
|
||||||
for buddy in buddies.iter() {
|
for buddy in buddies.iter() {
|
||||||
let bp = positions.get(buddy).unwrap();
|
let bp = positions.get(buddy).unwrap();
|
||||||
let bdir = *bp - pos;
|
let bdir = *bp - pos;
|
||||||
let dist = bdir.length();
|
let dist = bdir.length();
|
||||||
let rot = Quat::from_rotation_arc(dir, bdir.normalize());
|
let rot = Quat::from_rotation_arc(dir, bdir.normalize());
|
||||||
let s = (dist / (BUDDY_RADIUS * 1.2)).min(1.0);
|
let s = (dist / (BUDDY_RADIUS * 1.2)).min(1.0);
|
||||||
let rot = Quat::IDENTITY.slerp(rot, s);
|
let rot = Quat::IDENTITY.slerp(rot, s);
|
||||||
dir = rot.mul_vec3(dir).normalize();
|
dir = rot.mul_vec3(dir).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid flying into neighbors
|
// avoid flying into neighbors
|
||||||
let min_dist = speed * 10.0;
|
let min_dist = speed * 20.0;
|
||||||
for neighbor in index
|
for neighbor in index
|
||||||
.within_distance(pos, min_dist)
|
.within_distance(pos, min_dist)
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|n| n.1.is_some() && n.1.unwrap() != entity)
|
.filter(|n| n.1.is_some() && n.1.unwrap() != entity)
|
||||||
{
|
{
|
||||||
let bp = neighbor.0;
|
let bp = neighbor.0;
|
||||||
let bdir = pos - bp;
|
let bdir = pos - bp;
|
||||||
let dist = bdir.length();
|
let dist = bdir.length();
|
||||||
let s = 1.0 - (dist / min_dist).min(1.0);
|
let s = 1.0 - (dist / min_dist).min(1.0);
|
||||||
let rot = Quat::from_rotation_arc(dir, bdir.normalize());
|
let rot = Quat::from_rotation_arc(dir, bdir.normalize());
|
||||||
let rot = Quat::IDENTITY.slerp(rot, s);
|
let rot = Quat::IDENTITY.slerp(rot, s);
|
||||||
dir = rot.mul_vec3(dir).normalize();
|
dir = rot.mul_vec3(dir).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// nudge toward origin if too far
|
// nudge toward origin if too far
|
||||||
{
|
{
|
||||||
let dist = pos.length();
|
let dist = pos.length();
|
||||||
let toward_origin = -pos.normalize();
|
let toward_origin = -pos.normalize();
|
||||||
let s = (dist / RADIUS).min(1.0);
|
let s = (dist / RADIUS).min(1.0);
|
||||||
let rot = Quat::from_rotation_arc(dir, toward_origin);
|
let rot = Quat::from_rotation_arc(dir, toward_origin);
|
||||||
let rot = Quat::IDENTITY.slerp(rot, s);
|
let rot = Quat::IDENTITY.slerp(rot, s);
|
||||||
dir = rot.mul_vec3(dir).normalize();
|
dir = rot.mul_vec3(dir).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// nudge up if too low
|
// nudge up if too low
|
||||||
if pos.y < MIN_ALTITUDE {
|
if pos.y < MIN_ALTITUDE {
|
||||||
let dh = MIN_ALTITUDE - pos.y;
|
let dh = MIN_ALTITUDE - pos.y;
|
||||||
let s = (dh / MIN_ALTITUDE).min(1.0);
|
let s = (dh / MIN_ALTITUDE).min(1.0);
|
||||||
let rot = Quat::from_rotation_arc(dir, Vec3::Y);
|
let rot = Quat::from_rotation_arc(dir, Vec3::Y);
|
||||||
let rot = Quat::IDENTITY.slerp(rot, s);
|
let rot = Quat::IDENTITY.slerp(rot, s);
|
||||||
dir = rot.mul_vec3(dir).normalize();
|
dir = rot.mul_vec3(dir).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure velocity doesn't change too suddenly
|
// make sure velocity doesn't change too suddenly
|
||||||
let delta = dir.dot(original_dir).acos();
|
let delta = dir.dot(original_dir).acos();
|
||||||
if delta > max_delta {
|
if delta > max_delta {
|
||||||
let s = max_delta / delta;
|
let s = max_delta / delta;
|
||||||
let rot = Quat::from_rotation_arc(original_dir, dir);
|
let rot = Quat::from_rotation_arc(original_dir, dir);
|
||||||
let rot = Quat::IDENTITY.slerp(rot, s);
|
let rot = Quat::IDENTITY.slerp(rot, s);
|
||||||
dir = rot.mul_vec3(original_dir).normalize();
|
dir = rot.mul_vec3(original_dir).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
**vel = dir * speed;
|
**vel = dir * speed;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_pos(
|
pub fn update_pos(
|
||||||
|
@ -154,7 +160,12 @@ pub fn update_pos(
|
||||||
mut positions: ResMut<Positions>,
|
mut positions: ResMut<Positions>,
|
||||||
mut lookat: ResMut<LookAt>,
|
mut lookat: ResMut<LookAt>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
|
paused: Res<Paused>,
|
||||||
) {
|
) {
|
||||||
|
if **paused {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let mut new_look = Vec3::ZERO;
|
let mut new_look = Vec3::ZERO;
|
||||||
let dt = time.delta_secs();
|
let dt = time.delta_secs();
|
||||||
for (mut xform, vel, entity) in toids.iter_mut() {
|
for (mut xform, vel, entity) in toids.iter_mut() {
|
||||||
|
@ -204,13 +215,14 @@ pub fn update_gizmos(toids: Query<&Transform, With<Toid>>, mut gizmos: Gizmos) {
|
||||||
let forward = toid.forward().as_vec3();
|
let forward = toid.forward().as_vec3();
|
||||||
let right = toid.right().as_vec3();
|
let right = toid.right().as_vec3();
|
||||||
gizmos.ray(pos, pos + forward, Color::srgb_u8(255, 0, 0));
|
gizmos.ray(pos, pos + forward, Color::srgb_u8(255, 0, 0));
|
||||||
//gizmos.ray(pos, pos + up, Color::srgb_u8(0, 0, 255));
|
gizmos.ray(pos, pos + up, Color::srgb_u8(0, 0, 255));
|
||||||
//gizmos.ray(pos, pos + right, Color::srgb_u8(0, 255, 0));
|
gizmos.ray(pos, pos + right, Color::srgb_u8(0, 255, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_camera(
|
pub fn rotate_camera(
|
||||||
mut query: Query<&mut Transform, With<Camera>>,
|
mut query: Query<&mut Transform, With<Camera>>,
|
||||||
|
mut paused: ResMut<Paused>,
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
lookat: Res<LookAt>,
|
lookat: Res<LookAt>,
|
||||||
) {
|
) {
|
||||||
|
@ -219,6 +231,11 @@ pub fn rotate_camera(
|
||||||
let forward = xform.forward() * 0.7;
|
let forward = xform.forward() * 0.7;
|
||||||
let right = xform.right().as_vec3();
|
let right = xform.right().as_vec3();
|
||||||
|
|
||||||
|
if keys.just_pressed(KeyCode::Space) {
|
||||||
|
let pause = **paused;
|
||||||
|
**paused = !pause;
|
||||||
|
}
|
||||||
|
|
||||||
if keys.pressed(KeyCode::ArrowRight) {
|
if keys.pressed(KeyCode::ArrowRight) {
|
||||||
xform.translation += right;
|
xform.translation += right;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::time::Duration;
|
||||||
|
|
||||||
use audubon::*;
|
use audubon::*;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
color::palettes::css::BLACK,
|
|
||||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
@ -27,9 +26,10 @@ fn main() {
|
||||||
brightness: 1.0,
|
brightness: 1.0,
|
||||||
})
|
})
|
||||||
.insert_resource(LookAt::default())
|
.insert_resource(LookAt::default())
|
||||||
|
.insert_resource(Paused::default())
|
||||||
.add_systems(Startup, (setup, setup_ambient_light))
|
.add_systems(Startup, (setup, setup_ambient_light))
|
||||||
//.add_systems(Update, update_gizmos)
|
//.add_systems(Update, update_gizmos)
|
||||||
.add_systems(Update, (update_pos, update_buddies, update_vel).chain())
|
.add_systems(Update, (update_pos, update_buddies, update_vel))
|
||||||
.add_systems(Update, (rotate_camera, close_on_esc))
|
.add_systems(Update, (rotate_camera, close_on_esc))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue