async_channel_pattern/
async_channel_pattern.rs1use bevy::{
10 math::ops::{cos, sin},
11 prelude::*,
12 tasks::AsyncComputeTaskPool,
13};
14use crossbeam_channel::{Receiver, Sender};
15use futures_timer::Delay;
16use rand::RngExt;
17use std::time::Duration;
18
19const NUM_CUBES: i32 = 6;
20const LIGHT_RADIUS: f32 = 8.0;
21
22fn main() {
23 App::new()
24 .add_plugins(DefaultPlugins)
25 .add_systems(
26 Startup,
27 (
28 setup_env,
29 setup_assets,
30 setup_channel,
31 spawn_tasks.after(setup_channel),
33 ),
34 )
35 .add_systems(Update, (handle_finished_cubes, rotate_light))
36 .run();
37}
38
39fn spawn_tasks(channel: Res<CubeChannel>) {
47 let pool = AsyncComputeTaskPool::get();
48
49 for x in -NUM_CUBES..NUM_CUBES {
50 for z in -NUM_CUBES..NUM_CUBES {
51 let sender = channel.sender.clone();
52 pool.spawn(async move {
54 let delay = Duration::from_secs_f32(rand::rng().random_range(2.0..8.0));
55 Delay::new(delay).await;
57 let _ = sender.send(CubeFinished {
58 transform: Transform::from_xyz(x as f32, 0.5, z as f32),
59 });
60 })
61 .detach();
62 }
63 }
64}
65
66fn handle_finished_cubes(
70 mut commands: Commands,
71 channel: Res<CubeChannel>,
72 box_mesh: Res<BoxMeshHandle>,
73 box_material: Res<BoxMaterialHandle>,
74) {
75 for msg in channel.receiver.try_iter() {
76 commands.spawn((
78 Mesh3d(box_mesh.clone()),
79 MeshMaterial3d(box_material.clone()),
80 msg.transform,
81 ));
82 }
83}
84
85fn setup_channel(mut commands: Commands) {
90 let (sender, receiver) = crossbeam_channel::unbounded();
91 commands.insert_resource(CubeChannel { sender, receiver });
92}
93
94#[derive(Resource)]
96struct CubeChannel {
97 sender: Sender<CubeFinished>,
98 receiver: Receiver<CubeFinished>,
99}
100
101#[derive(Debug)]
103struct CubeFinished {
104 transform: Transform,
105}
106
107#[derive(Resource, Deref)]
109struct BoxMeshHandle(Handle<Mesh>);
110
111#[derive(Resource, Deref)]
113struct BoxMaterialHandle(Handle<StandardMaterial>);
114
115fn setup_assets(
117 mut commands: Commands,
118 mut meshes: ResMut<Assets<Mesh>>,
119 mut materials: ResMut<Assets<StandardMaterial>>,
120) {
121 let box_mesh_handle = meshes.add(Cuboid::new(0.4, 0.4, 0.4));
123 commands.insert_resource(BoxMeshHandle(box_mesh_handle));
124
125 let box_material_handle = materials.add(Color::srgb(1.0, 0.2, 0.3));
127 commands.insert_resource(BoxMaterialHandle(box_material_handle));
128}
129
130fn setup_env(
132 mut commands: Commands,
133 mut meshes: ResMut<Assets<Mesh>>,
134 mut materials: ResMut<Assets<StandardMaterial>>,
135) {
136 commands.spawn((
138 Mesh3d(meshes.add(Circle::new(1.618 * NUM_CUBES as f32))),
139 MeshMaterial3d(materials.add(Color::WHITE)),
140 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
141 ));
142
143 commands.spawn((
145 PointLight {
146 shadow_maps_enabled: true,
147 ..default()
148 },
149 Transform::from_xyz(0.0, LIGHT_RADIUS, 4.0),
150 ));
151
152 commands.spawn((
154 Camera3d::default(),
155 Transform::from_xyz(-6.5, 5.5, 12.0).looking_at(Vec3::ZERO, Vec3::Y),
156 ));
157}
158
159fn rotate_light(mut query: Query<&mut Transform, With<PointLight>>, time: Res<Time>) {
161 for mut transform in query.iter_mut() {
162 let angle = 1.618 * time.elapsed_secs();
163 let x = LIGHT_RADIUS * cos(angle);
164 let z = LIGHT_RADIUS * sin(angle);
165
166 transform.translation = Vec3::new(x, LIGHT_RADIUS, z);
168 }
169}