use std::collections::HashMap; use async_channel::bounded; use bevy::{input::keyboard::Key, prelude::*, tasks::AsyncComputeTaskPool}; use rand::RngExt; use super::{ BackgroundHandle, Buddies, GeomWithData, IndexChannel, IndexMessage, LookAt, Naybs, Positions, RTree, RawMessage, RawPosChannel, Toid, Velocity, }; // toid stuff const SPEED: f32 = 6.0; const SPEED_DIFF_RANGE: f32 = 0.2; // +/- 10% 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 const RADIUS: f32 = 40.0; // how close to try to stay to your buddies const BUDDY_RADIUS: f32 = 10.0; const MIN_ALTITUDE: f32 = 3.5; pub fn setup_channels(mut commands: Commands) { let (raw_tx, raw_rx) = bounded(1); commands.insert_resource(RawPosChannel { tx: raw_tx, rx: Some(raw_rx), }); let (idx_tx, idx_rx) = bounded(1); commands.insert_resource(IndexChannel { tx: idx_tx, rx: idx_rx, }); } pub fn update_naybs( mut naybs: ResMut, raw_chan: Res, positions: Res, idx_chan: Res, ) { if let Ok(idx_msg) = idx_chan.rx.try_recv() { naybs.index = idx_msg.index; let _ = naybs.positions.insert(idx_msg.raw); return; } if let Some(mut raw) = naybs.positions.take() { for (i, (entity, pos)) in positions.iter().enumerate() { raw[i] = (*pos, *entity); } if let Err(e) = raw_chan.tx.try_send(RawMessage(raw)) { let RawMessage(raw) = e.into_inner(); let _ = naybs.positions.insert(raw); } } } pub fn init_naybs(positions: Res, mut naybs: ResMut) { let mut raw = Vec::with_capacity(positions.len()); for (entity, pos) in positions.iter() { raw.push((*pos, *entity)); } naybs.positions = Some(raw); } pub fn spawn_background( mut raw_chan: ResMut, idx_chan: Res, mut handle: ResMut, ) { let pool = AsyncComputeTaskPool::get(); let raw_rx = raw_chan.rx.take().unwrap(); let idx_tx = idx_chan.tx.clone(); let task = pool.spawn(async move { let tx = idx_tx; let rx = raw_rx; loop { match rx.recv().await { Ok(RawMessage(e_posns)) => { let idx = RTree::bulk_load( e_posns .iter() .map(|(p, e)| GeomWithData::new(p.to_array(), *e)) .collect(), ); let msg = IndexMessage { raw: e_posns, index: idx, }; if tx.send(msg).await.is_err() { break; }; } Err(_) => break, } } }); let _ = handle.0.insert(task); } pub fn turkey_time( commands: &mut Commands, r: &mut impl rand::prelude::Rng, assets: &AssetServer, positions: &mut HashMap, ) { let speed_diff = r.random_range(-SPEED_DIFF_RANGE..=SPEED_DIFF_RANGE); let speed = SPEED + (SPEED * speed_diff); let vel = unit_vec(r) * speed; let buddies = r.random_range(6..=8); let x = r.random_range(-10.0..=10.0); let z = r.random_range(-10.0..=10.0); let y = r.random_range(MIN_ALTITUDE..=(MIN_ALTITUDE + 5.5)); let entity = commands .spawn(( Velocity(vel), Buddies::default(), Toid { speed, buddies }, Transform::from_xyz(x, y, z), Visibility::Visible, )) .with_children(|t| { t.spawn(WorldAssetRoot( assets.load(GltfAssetLabel::Scene(0).from_asset("models/boid.glb")), )) .insert(Transform::default()) //.insert(Visibility::Visible); .insert(Transform::from_rotation(Quat::from_axis_angle( Vec3::Y, -std::f32::consts::FRAC_PI_2, ))); }) .id(); positions.insert(entity, Vec3::new(x, y, z)); } pub fn update_vel( mut toids: Query<(&Transform, &mut Velocity, &Toid, &Buddies, Entity)>, time: Res