Compare commits
No commits in common. "b4ad5000013409cfc892691925c555a6a25d61c8" and "3d7663e0324d34df51ce43a325a9449015372ef8" have entirely different histories.
b4ad500001
...
3d7663e032
3 changed files with 117 additions and 142 deletions
|
|
@ -8,7 +8,7 @@ use rstar::{primitives::GeomWithData, RTree};
|
||||||
mod systems;
|
mod systems;
|
||||||
|
|
||||||
pub use systems::{
|
pub use systems::{
|
||||||
handle_inputs, init_naybs, setup_channels, spawn_background, turkey_time, update_buddies,
|
init_naybs, rotate_camera, setup_channels, spawn_background, turkey_time, update_buddies,
|
||||||
update_gizmos, update_naybs, update_pos, update_vel,
|
update_gizmos, update_naybs, update_pos, update_vel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -59,8 +59,8 @@ struct IndexMessage {
|
||||||
|
|
||||||
struct RawMessage(Vec<EntityPos>);
|
struct RawMessage(Vec<EntityPos>);
|
||||||
|
|
||||||
#[derive(Resource, Deref, DerefMut)]
|
#[derive(Default, Resource, Deref, DerefMut)]
|
||||||
pub struct BackgroundHandle(bevy::tasks::Task<()>);
|
pub struct BackgroundHandle(Option<bevy::tasks::Task<()>>);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Toid {
|
pub struct Toid {
|
||||||
|
|
@ -70,6 +70,3 @@ pub struct Toid {
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)]
|
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)]
|
||||||
pub struct LookAt(Vec3);
|
pub struct LookAt(Vec3);
|
||||||
|
|
||||||
#[derive(Resource, Debug, Deref, DerefMut, Clone, Default)]
|
|
||||||
pub struct Paused(bool);
|
|
||||||
|
|
|
||||||
54
src/main.rs
54
src/main.rs
|
|
@ -2,18 +2,16 @@ use bevy::{
|
||||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||||
input::keyboard::Key,
|
input::keyboard::Key,
|
||||||
prelude::{
|
prelude::{
|
||||||
children, default, px, warn, App, AssetServer, Assets, ButtonInput, Camera3d, ClearColor,
|
children, default, px, App, AssetServer, Assets, ButtonInput, Camera3d, ClearColor, Color,
|
||||||
Color, Commands, DefaultPlugins, Entity, FontSize, GlobalAmbientLight, IntoScheduleConfigs,
|
Commands, DefaultPlugins, Entity, FontSize, GlobalAmbientLight, IntoScheduleConfigs, Mesh,
|
||||||
Mesh, Mesh3d, MeshMaterial3d, Node, Plane3d, PositionType, Query, Res, ResMut,
|
Mesh3d, MeshMaterial3d, Node, Plane3d, PositionType, Query, Res, ResMut, StandardMaterial,
|
||||||
StandardMaterial, Startup, Text, TextFont, Transform, Update, Vec2, Vec3, Visibility,
|
Startup, Text, TextFont, Transform, Update, Vec2, Vec3, Visibility, Window,
|
||||||
Window, With,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use rstar::RTree;
|
use rstar::RTree;
|
||||||
use toids::{
|
use toids::{
|
||||||
handle_inputs, init_naybs, setup_channels, spawn_background, turkey_time, update_buddies,
|
init_naybs, rotate_camera, setup_channels, spawn_background, turkey_time, update_buddies,
|
||||||
update_naybs, update_pos, update_vel, BackgroundHandle, Config, LookAt, Naybs, Paused,
|
update_naybs, update_pos, update_vel, BackgroundHandle, Config, LookAt, Naybs, Positions,
|
||||||
Positions,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -25,7 +23,6 @@ fn main() {
|
||||||
LogDiagnosticsPlugin::default(),
|
LogDiagnosticsPlugin::default(),
|
||||||
))
|
))
|
||||||
.insert_resource(config)
|
.insert_resource(config)
|
||||||
.insert_resource(Paused::default())
|
|
||||||
.insert_resource(Positions::default())
|
.insert_resource(Positions::default())
|
||||||
.insert_resource(ClearColor(Color::srgb(0.64, 0.745, 0.937))) // a nice light blue
|
.insert_resource(ClearColor(Color::srgb(0.64, 0.745, 0.937))) // a nice light blue
|
||||||
.insert_resource(GlobalAmbientLight {
|
.insert_resource(GlobalAmbientLight {
|
||||||
|
|
@ -38,20 +35,16 @@ fn main() {
|
||||||
index: RTree::new(),
|
index: RTree::new(),
|
||||||
positions: None,
|
positions: None,
|
||||||
})
|
})
|
||||||
|
.insert_resource(BackgroundHandle::default())
|
||||||
.insert_resource(LookAt::default())
|
.insert_resource(LookAt::default())
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
(setup_channels, setup, init_naybs, spawn_background).chain(),
|
(setup_channels, setup, init_naybs, spawn_background).chain(),
|
||||||
)
|
)
|
||||||
|
.add_systems(Update, (update_pos, update_buddies, update_vel).chain())
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(update_pos, update_buddies, update_vel)
|
(rotate_camera, close_on_esc, update_naybs.after(update_pos)),
|
||||||
.chain()
|
|
||||||
.run_if(should_run),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
Update,
|
|
||||||
(handle_inputs, close_on_esc, update_naybs.after(update_pos)),
|
|
||||||
)
|
)
|
||||||
//.add_systems(Update, update_gizmos)
|
//.add_systems(Update, update_gizmos)
|
||||||
.run();
|
.run();
|
||||||
|
|
@ -79,8 +72,10 @@ fn setup(
|
||||||
Transform::default(),
|
Transform::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// let toid_model = models.load("models/boid.glb#Scene0");
|
||||||
|
|
||||||
for _ in 0..config.toids {
|
for _ in 0..config.toids {
|
||||||
turkey_time(&mut commands, rand, &models, &mut positions);
|
turkey_time(&mut commands, rand, &models, &mut positions.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// instructions
|
// instructions
|
||||||
|
|
@ -93,7 +88,7 @@ fn setup(
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
children![(
|
children![(
|
||||||
Text::new("Up and down for camera forward and back; hold shift to change height.\nLeft or right to move left or right.\nPress 'SPACE' to pause, 'ESC' to quit."),
|
Text::new("Up and down for camera forward and back; hold shift to change height.\nLeft or right to move left or right.\nPress 'ESC' to quit."),
|
||||||
TextFont {
|
TextFont {
|
||||||
font_size: FontSize::Px(20.0),
|
font_size: FontSize::Px(20.0),
|
||||||
..default()
|
..default()
|
||||||
|
|
@ -104,27 +99,18 @@ fn setup(
|
||||||
|
|
||||||
fn close_on_esc(
|
fn close_on_esc(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
windows: Query<Entity, With<Window>>,
|
focused_windows: Query<(Entity, &Window)>,
|
||||||
input: Res<ButtonInput<Key>>,
|
input: Res<ButtonInput<Key>>,
|
||||||
handle: ResMut<BackgroundHandle>,
|
mut handle: ResMut<BackgroundHandle>,
|
||||||
) {
|
) {
|
||||||
let background_gone = handle.as_ref().is_finished();
|
for (window, focus) in focused_windows.iter() {
|
||||||
if background_gone {
|
if !focus.focused {
|
||||||
warn!("background is gone, shutting down");
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let exited = background_gone || input.just_pressed(Key::Escape);
|
if input.just_pressed(Key::Escape) {
|
||||||
if !exited {
|
drop((*handle).take());
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(handle);
|
|
||||||
|
|
||||||
for window in windows.iter() {
|
|
||||||
commands.entity(window).despawn();
|
commands.entity(window).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_run(paused: Res<Paused>) -> bool {
|
|
||||||
!**paused
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,23 @@ use bevy::{input::keyboard::Key, prelude::*, tasks::AsyncComputeTaskPool};
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
BackgroundHandle, Buddies, GeomWithData, IndexChannel, IndexMessage, LookAt, Naybs, Paused,
|
BackgroundHandle, Buddies, GeomWithData, IndexChannel, IndexMessage, LookAt, Naybs, Positions,
|
||||||
Positions, RTree, RawMessage, RawPosChannel, Toid, Velocity,
|
RTree, RawMessage, RawPosChannel, Toid, Velocity,
|
||||||
};
|
};
|
||||||
|
|
||||||
// toid stuff
|
// toid stuff
|
||||||
const SPEED: f32 = 12.0;
|
const SPEED: f32 = 6.0;
|
||||||
const SPEED_DIFF_RANGE: f32 = 0.1;
|
const SPEED_DIFF_RANGE: f32 = 0.2; // +/- 10%
|
||||||
const MAX_DELTA_V: f32 = std::f32::consts::PI * 1.2;
|
const MAX_DELTA_V: f32 = std::f32::consts::PI * 1.5; // basically 360
|
||||||
|
// degrees/sec
|
||||||
|
|
||||||
// how far from origin before really wanting to come back
|
// how far from origin before really wanting to come back
|
||||||
const RADIUS: f32 = 30.0;
|
const RADIUS: f32 = 40.0;
|
||||||
|
|
||||||
// how close to try to stay to your buddies
|
// how close to try to stay to your buddies
|
||||||
const BUDDY_RADIUS: f32 = SPEED;
|
const BUDDY_RADIUS: f32 = 10.0;
|
||||||
|
|
||||||
const MIN_ALTITUDE: f32 = 13.5;
|
const MIN_ALTITUDE: f32 = 3.5;
|
||||||
|
|
||||||
pub fn setup_channels(mut commands: Commands) {
|
pub fn setup_channels(mut commands: Commands) {
|
||||||
let (raw_tx, raw_rx) = bounded(1);
|
let (raw_tx, raw_rx) = bounded(1);
|
||||||
|
|
@ -44,6 +46,7 @@ pub fn update_naybs(
|
||||||
if let Ok(idx_msg) = idx_chan.rx.try_recv() {
|
if let Ok(idx_msg) = idx_chan.rx.try_recv() {
|
||||||
naybs.index = idx_msg.index;
|
naybs.index = idx_msg.index;
|
||||||
let _ = naybs.positions.insert(idx_msg.raw);
|
let _ = naybs.positions.insert(idx_msg.raw);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut raw) = naybs.positions.take() {
|
if let Some(mut raw) = naybs.positions.take() {
|
||||||
|
|
@ -67,9 +70,9 @@ pub fn init_naybs(positions: Res<Positions>, mut naybs: ResMut<Naybs>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_background(
|
pub fn spawn_background(
|
||||||
mut commands: Commands,
|
|
||||||
mut raw_chan: ResMut<RawPosChannel>,
|
mut raw_chan: ResMut<RawPosChannel>,
|
||||||
idx_chan: Res<IndexChannel>,
|
idx_chan: Res<IndexChannel>,
|
||||||
|
mut handle: ResMut<BackgroundHandle>,
|
||||||
) {
|
) {
|
||||||
let pool = AsyncComputeTaskPool::get();
|
let pool = AsyncComputeTaskPool::get();
|
||||||
|
|
||||||
|
|
@ -79,7 +82,6 @@ pub fn spawn_background(
|
||||||
let task = pool.spawn(async move {
|
let task = pool.spawn(async move {
|
||||||
let tx = idx_tx;
|
let tx = idx_tx;
|
||||||
let rx = raw_rx;
|
let rx = raw_rx;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match rx.recv().await {
|
match rx.recv().await {
|
||||||
Ok(RawMessage(e_posns)) => {
|
Ok(RawMessage(e_posns)) => {
|
||||||
|
|
@ -102,7 +104,7 @@ pub fn spawn_background(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
commands.insert_resource(BackgroundHandle(task));
|
let _ = handle.0.insert(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn turkey_time(
|
pub fn turkey_time(
|
||||||
|
|
@ -151,16 +153,14 @@ pub fn update_vel(
|
||||||
) {
|
) {
|
||||||
let dt = time.delta_secs();
|
let dt = time.delta_secs();
|
||||||
let max_delta = MAX_DELTA_V * dt;
|
let max_delta = MAX_DELTA_V * dt;
|
||||||
toids
|
for (xform, mut vel, toid, buddies, entity) in toids.iter_mut() {
|
||||||
.par_iter_mut()
|
|
||||||
.for_each(|(xform, mut vel, toid, buddies, entity)| {
|
|
||||||
let speed = toid.speed;
|
let speed = toid.speed;
|
||||||
let mut dir = vel.normalize();
|
let mut dir = vel.normalize();
|
||||||
let pos = xform.translation;
|
let pos = xform.translation;
|
||||||
let original_dir = dir;
|
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.0.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();
|
||||||
|
|
@ -174,7 +174,7 @@ pub fn update_vel(
|
||||||
let min_dist = speed;
|
let min_dist = speed;
|
||||||
for neighbor in index
|
for neighbor in index
|
||||||
.index
|
.index
|
||||||
.locate_within_distance(pos.to_array(), speed.powi(2))
|
.locate_within_distance(pos.to_array(), min_dist)
|
||||||
.filter(|n| n.data != entity)
|
.filter(|n| n.data != entity)
|
||||||
{
|
{
|
||||||
let bp = Vec3::from_array(*neighbor.geom());
|
let bp = Vec3::from_array(*neighbor.geom());
|
||||||
|
|
@ -215,7 +215,7 @@ pub fn update_vel(
|
||||||
}
|
}
|
||||||
|
|
||||||
**vel = dir * speed;
|
**vel = dir * speed;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_pos(
|
pub fn update_pos(
|
||||||
|
|
@ -230,7 +230,7 @@ pub fn update_pos(
|
||||||
let look_at = xform.translation + vel.0;
|
let look_at = xform.translation + vel.0;
|
||||||
xform.translation += vel.0 * dt;
|
xform.translation += vel.0 * dt;
|
||||||
xform.look_at(look_at, Vec3::Y);
|
xform.look_at(look_at, Vec3::Y);
|
||||||
positions.insert(entity, xform.translation);
|
*positions.entry(entity).or_insert(Vec3::ZERO) = xform.translation;
|
||||||
new_look += xform.translation;
|
new_look += xform.translation;
|
||||||
}
|
}
|
||||||
**lookat = new_look / positions.len() as f32;
|
**lookat = new_look / positions.len() as f32;
|
||||||
|
|
@ -242,12 +242,10 @@ pub fn update_buddies(
|
||||||
positions: Res<Positions>,
|
positions: Res<Positions>,
|
||||||
) {
|
) {
|
||||||
let d2 = (BUDDY_RADIUS * 1.5).powi(2);
|
let d2 = (BUDDY_RADIUS * 1.5).powi(2);
|
||||||
toids
|
for (xform, entity, toid, mut buddies) in toids.iter_mut() {
|
||||||
.par_iter_mut()
|
|
||||||
.for_each(|(xform, entity, toid, mut buddies)| {
|
|
||||||
let pos = xform.translation;
|
let pos = xform.translation;
|
||||||
for buddy in buddies.clone().iter() {
|
for buddy in buddies.clone().iter() {
|
||||||
let bp = positions.get(buddy).unwrap();
|
let bp = positions[buddy];
|
||||||
let bd2 = (bp - pos).length_squared();
|
let bd2 = (bp - pos).length_squared();
|
||||||
if bd2 > d2 {
|
if bd2 > d2 {
|
||||||
buddies.remove(buddy);
|
buddies.remove(buddy);
|
||||||
|
|
@ -265,7 +263,7 @@ pub fn update_buddies(
|
||||||
buddies.insert(neighbor.data);
|
buddies.insert(neighbor.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_gizmos(toids: Query<&Transform, With<Toid>>, mut gizmos: Gizmos) {
|
pub fn update_gizmos(toids: Query<&Transform, With<Toid>>, mut gizmos: Gizmos) {
|
||||||
|
|
@ -280,17 +278,11 @@ pub fn update_gizmos(toids: Query<&Transform, With<Toid>>, mut gizmos: Gizmos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_inputs(
|
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<Key>>,
|
keys: Res<ButtonInput<Key>>,
|
||||||
lookat: Res<LookAt>,
|
lookat: Res<LookAt>,
|
||||||
) {
|
) {
|
||||||
if keys.just_pressed(Key::Space) {
|
|
||||||
let pause = **paused;
|
|
||||||
**paused = !pause;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut xform = query.single_mut().unwrap();
|
let mut xform = query.single_mut().unwrap();
|
||||||
|
|
||||||
let forward = xform.forward().as_vec3() * 0.7;
|
let forward = xform.forward().as_vec3() * 0.7;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue