runs about 4x as fast as previous
This commit is contained in:
parent
279ebaa4c1
commit
4a9c2bdb02
4 changed files with 154 additions and 25 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -865,6 +865,7 @@ dependencies = [
|
|||
"bevy_reflect",
|
||||
"bevy_render",
|
||||
"bevy_shader",
|
||||
"bevy_sprite_render",
|
||||
"bevy_transform",
|
||||
"bevy_utils",
|
||||
"bytemuck",
|
||||
|
|
@ -963,6 +964,7 @@ dependencies = [
|
|||
"bevy_ecs",
|
||||
"bevy_input",
|
||||
"bevy_math",
|
||||
"bevy_picking",
|
||||
"bevy_reflect",
|
||||
"bevy_window",
|
||||
"log",
|
||||
|
|
@ -1003,6 +1005,7 @@ dependencies = [
|
|||
"bevy_math",
|
||||
"bevy_mesh",
|
||||
"bevy_pbr",
|
||||
"bevy_picking",
|
||||
"bevy_platform",
|
||||
"bevy_post_process",
|
||||
"bevy_ptr",
|
||||
|
|
@ -1018,6 +1021,8 @@ dependencies = [
|
|||
"bevy_time",
|
||||
"bevy_transform",
|
||||
"bevy_ui",
|
||||
"bevy_ui_render",
|
||||
"bevy_ui_widgets",
|
||||
"bevy_utils",
|
||||
"bevy_window",
|
||||
"bevy_winit",
|
||||
|
|
@ -1224,11 +1229,13 @@ dependencies = [
|
|||
"bevy_ecs",
|
||||
"bevy_input",
|
||||
"bevy_math",
|
||||
"bevy_mesh",
|
||||
"bevy_platform",
|
||||
"bevy_reflect",
|
||||
"bevy_time",
|
||||
"bevy_transform",
|
||||
"bevy_window",
|
||||
"crossbeam-channel",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
|
@ -1464,6 +1471,7 @@ dependencies = [
|
|||
"bevy_log",
|
||||
"bevy_math",
|
||||
"bevy_mesh",
|
||||
"bevy_picking",
|
||||
"bevy_reflect",
|
||||
"bevy_text",
|
||||
"bevy_transform",
|
||||
|
|
@ -4787,8 +4795,8 @@ name = "toids"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"async-channel",
|
||||
"bevy",
|
||||
"crossbeam-channel",
|
||||
"rand",
|
||||
"rstar",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ name = "toids"
|
|||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
debug = ["bevy/debug"]
|
||||
|
||||
[dependencies]
|
||||
argh = "0.1.12"
|
||||
bevy = { version = "0.19", default-features = false, features = ["default_app", "default_platform", "bevy_scene", "3d_bevy_render", "bevy_ui"] }
|
||||
crossbeam-channel = "0.5"
|
||||
bevy = { version = "0.19", default-features = false, features = ["3d", "ui"] }
|
||||
async-channel = "2"
|
||||
rand = { version = "0.10", features = ["thread_rng"] }
|
||||
rstar = "0.13"
|
||||
|
|
|
|||
129
src/lib.rs
129
src/lib.rs
|
|
@ -1,12 +1,15 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use argh::FromArgs;
|
||||
use async_channel::{bounded, Receiver, Sender};
|
||||
use bevy::{input::keyboard::Key, prelude::*, tasks::AsyncComputeTaskPool};
|
||||
use crossbeam_channel::{bounded, Receiver, Sender};
|
||||
use rand::RngExt;
|
||||
use rstar::{primitives::GeomWithData, RTree};
|
||||
|
||||
type Index = RTree<GeomWithData<[f32; 3], Entity>>;
|
||||
type IndexElement = GeomWithData<[f32; 3], Entity>;
|
||||
type Index = RTree<IndexElement>;
|
||||
|
||||
type EntityPos = (Vec3, Entity);
|
||||
|
||||
// toid stuff
|
||||
const SPEED: f32 = 2.0;
|
||||
|
|
@ -41,22 +44,32 @@ pub struct Velocity(Vec3);
|
|||
|
||||
#[derive(Debug, Default, Resource)]
|
||||
pub struct Naybs {
|
||||
index: Index,
|
||||
positions: Option<Box<[Vec3]>>,
|
||||
pub index: Index,
|
||||
pub positions: Option<Vec<EntityPos>>,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct RawPosChannel {
|
||||
tx: Sender<Box<[Vec3]>>,
|
||||
rx: Receiver<Box<[Vec3]>>,
|
||||
tx: Sender<RawMessage>,
|
||||
rx: Option<Receiver<RawMessage>>,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct IndexChannel {
|
||||
tx: Sender<(Box<[Vec3]>, Index)>,
|
||||
rx: Receiver<(Box<[Vec3]>, Index)>,
|
||||
tx: Sender<IndexMessage>,
|
||||
rx: Receiver<IndexMessage>,
|
||||
}
|
||||
|
||||
struct IndexMessage {
|
||||
raw: Vec<EntityPos>,
|
||||
index: Index,
|
||||
}
|
||||
|
||||
struct RawMessage(Vec<EntityPos>);
|
||||
|
||||
#[derive(Default, Resource, Deref, DerefMut)]
|
||||
pub struct BackgroundHandle(Option<bevy::tasks::Task<()>>);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Toid {
|
||||
pub speed: f32,
|
||||
|
|
@ -66,11 +79,96 @@ pub struct Toid {
|
|||
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)]
|
||||
pub struct LookAt(Vec3);
|
||||
|
||||
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<Naybs>,
|
||||
raw_chan: Res<RawPosChannel>,
|
||||
positions: Res<Positions>,
|
||||
idx_chan: Res<IndexChannel>,
|
||||
) {
|
||||
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<Positions>, mut naybs: ResMut<Naybs>) {
|
||||
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<RawPosChannel>,
|
||||
idx_chan: Res<IndexChannel>,
|
||||
mut handle: ResMut<BackgroundHandle>,
|
||||
) {
|
||||
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,
|
||||
) -> Entity {
|
||||
positions: &mut HashMap<Entity, Vec3>,
|
||||
) {
|
||||
let speed_diff = r.random_range(-SPEED_DIFF_RANGE..=SPEED_DIFF_RANGE);
|
||||
let speed = SPEED + (SPEED * speed_diff);
|
||||
let vel = unit_vec(r) * speed;
|
||||
|
|
@ -78,24 +176,29 @@ pub fn turkey_time(
|
|||
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));
|
||||
commands
|
||||
|
||||
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/toid.glb")),
|
||||
assets.load(GltfAssetLabel::Scene(0).from_asset("models/boid.glb")),
|
||||
))
|
||||
.insert(Transform::default());
|
||||
.insert(Transform::default())
|
||||
.insert(Visibility::Visible);
|
||||
// .insert(Transform::from_rotation(Quat::from_axis_angle(
|
||||
// Vec3::Y,
|
||||
// -std::f32::consts::FRAC_PI_2,
|
||||
// )));
|
||||
})
|
||||
.id()
|
||||
.id();
|
||||
|
||||
positions.insert(entity, Vec3::new(x, y, z));
|
||||
}
|
||||
|
||||
pub fn update_vel(
|
||||
|
|
|
|||
33
src/main.rs
33
src/main.rs
|
|
@ -1,12 +1,12 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use bevy::{
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
input::keyboard::Key,
|
||||
prelude::*,
|
||||
};
|
||||
use rstar::RTree;
|
||||
use toids::{
|
||||
rotate_camera, turkey_time, update_buddies, update_pos, update_vel, Config, LookAt, Positions,
|
||||
init_naybs, rotate_camera, setup_channels, spawn_background, turkey_time, update_buddies,
|
||||
update_naybs, update_pos, update_vel, BackgroundHandle, Config, LookAt, Naybs, Positions,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
|
|
@ -22,13 +22,25 @@ fn main() {
|
|||
.insert_resource(ClearColor(Color::srgb(0.64, 0.745, 0.937))) // a nice light blue
|
||||
.insert_resource(GlobalAmbientLight {
|
||||
color: Color::WHITE,
|
||||
brightness: 1.0,
|
||||
brightness: 150.0,
|
||||
affects_lightmapped_meshes: true,
|
||||
..Default::default()
|
||||
})
|
||||
.insert_resource(Naybs {
|
||||
index: RTree::new(),
|
||||
positions: None,
|
||||
})
|
||||
.insert_resource(BackgroundHandle::default())
|
||||
.insert_resource(LookAt::default())
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(
|
||||
Startup,
|
||||
(setup_channels, setup, init_naybs, spawn_background).chain(),
|
||||
)
|
||||
.add_systems(Update, (update_pos, update_buddies, update_vel).chain())
|
||||
.add_systems(Update, (rotate_camera, close_on_esc))
|
||||
.add_systems(
|
||||
Update,
|
||||
(rotate_camera, close_on_esc, update_naybs.after(update_pos)),
|
||||
)
|
||||
//.add_systems(Update, update_gizmos)
|
||||
.run();
|
||||
}
|
||||
|
|
@ -37,6 +49,7 @@ fn setup(
|
|||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut positions: ResMut<Positions>,
|
||||
config: Res<Config>,
|
||||
models: Res<AssetServer>,
|
||||
) {
|
||||
|
|
@ -49,18 +62,20 @@ fn setup(
|
|||
// plane
|
||||
commands.spawn((
|
||||
Mesh3d(meshes.add(Mesh::from(Plane3d::new(Vec3::Y, Vec2::splat(500.0))))),
|
||||
MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))),
|
||||
MeshMaterial3d(materials.add(Color::srgb(0.3, 0.9, 0.3))),
|
||||
Visibility::Visible,
|
||||
Transform::default(),
|
||||
));
|
||||
|
||||
// let toid_model = models.load("models/boid.glb#Scene0");
|
||||
|
||||
for _ in 0..config.toids {
|
||||
let _ = turkey_time(&mut commands, rand, &models);
|
||||
turkey_time(&mut commands, rand, &models, &mut positions.0);
|
||||
}
|
||||
|
||||
// instructions
|
||||
commands.spawn((
|
||||
Visibility::Visible,
|
||||
Node {
|
||||
position_type: PositionType::Absolute,
|
||||
top: px(12.0),
|
||||
|
|
@ -81,6 +96,7 @@ fn close_on_esc(
|
|||
mut commands: Commands,
|
||||
focused_windows: Query<(Entity, &Window)>,
|
||||
input: Res<ButtonInput<Key>>,
|
||||
mut handle: ResMut<BackgroundHandle>,
|
||||
) {
|
||||
for (window, focus) in focused_windows.iter() {
|
||||
if !focus.focused {
|
||||
|
|
@ -88,6 +104,7 @@ fn close_on_esc(
|
|||
}
|
||||
|
||||
if input.just_pressed(Key::Escape) {
|
||||
drop((*handle).take());
|
||||
commands.entity(window).despawn();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue