use bevy::{
math::ops::{cos, sin},
prelude::*,
tasks::AsyncComputeTaskPool,
};
use crossbeam_channel::{Receiver, Sender};
use futures_timer::Delay;
use rand::Rng;
use std::time::Duration;
const NUM_CUBES: i32 = 6;
const LIGHT_RADIUS: f32 = 8.0;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(
Startup,
(
setup_env,
setup_assets,
setup_channel,
spawn_tasks.after(setup_channel),
),
)
.add_systems(Update, (handle_finished_cubes, rotate_light))
.run();
}
fn spawn_tasks(channel: Res<CubeChannel>) {
let pool = AsyncComputeTaskPool::get();
for x in -NUM_CUBES..NUM_CUBES {
for z in -NUM_CUBES..NUM_CUBES {
let sender = channel.sender.clone();
pool.spawn(async move {
let delay = Duration::from_secs_f32(rand::rng().random_range(2.0..8.0));
Delay::new(delay).await;
let _ = sender.send(CubeFinished {
transform: Transform::from_xyz(x as f32, 0.5, z as f32),
});
})
.detach();
}
}
}
fn handle_finished_cubes(
mut commands: Commands,
channel: Res<CubeChannel>,
box_mesh: Res<BoxMeshHandle>,
box_material: Res<BoxMaterialHandle>,
) {
for msg in channel.receiver.try_iter() {
commands.spawn((
Mesh3d(box_mesh.clone()),
MeshMaterial3d(box_material.clone()),
msg.transform,
));
}
}
fn setup_channel(mut commands: Commands) {
let (sender, receiver) = crossbeam_channel::unbounded();
commands.insert_resource(CubeChannel { sender, receiver });
}
#[derive(Resource)]
struct CubeChannel {
sender: Sender<CubeFinished>,
receiver: Receiver<CubeFinished>,
}
#[derive(Debug)]
struct CubeFinished {
transform: Transform,
}
#[derive(Resource, Deref)]
struct BoxMeshHandle(Handle<Mesh>);
#[derive(Resource, Deref)]
struct BoxMaterialHandle(Handle<StandardMaterial>);
fn setup_assets(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let box_mesh_handle = meshes.add(Cuboid::new(0.4, 0.4, 0.4));
commands.insert_resource(BoxMeshHandle(box_mesh_handle));
let box_material_handle = materials.add(Color::srgb(1.0, 0.2, 0.3));
commands.insert_resource(BoxMaterialHandle(box_material_handle));
}
fn setup_env(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Mesh3d(meshes.add(Circle::new(1.618 * NUM_CUBES as f32))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
));
commands.spawn((
PointLight {
shadows_enabled: true,
..default()
},
Transform::from_xyz(0.0, LIGHT_RADIUS, 4.0),
));
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-6.5, 5.5, 12.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}
fn rotate_light(mut query: Query<&mut Transform, With<PointLight>>, time: Res<Time>) {
for mut transform in query.iter_mut() {
let angle = 1.618 * time.elapsed_secs();
let x = LIGHT_RADIUS * cos(angle);
let z = LIGHT_RADIUS * sin(angle);
transform.translation = Vec3::new(x, LIGHT_RADIUS, z);
}
}