Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ecs/extraction.rs
30632 views
1
//! Demonstrates different ways of extracting components from the main world to the render world.
2
//!
3
//! This is usually done as an intermediary step for transferring data to the GPU, making
4
//! it accessible inside shaders.
5
//!
6
//! In this example, multiple entities are spawned, each with a different marker component: A, B, C.
7
//! Each component contains the current elapsed time, updated each frame on the Main World, and is
8
//! extracted to the render world in a different way.
9
10
use bevy::prelude::*;
11
use bevy::render::{
12
extract_component::{ExtractComponent, ExtractComponentPlugin},
13
sync_world::{RenderEntity, SyncToRenderWorld},
14
Extract, Render, RenderApp,
15
};
16
17
// The A component is extracted automatically through `ExtractComponentPlugin`. For this,
18
// it is required to implement `ExtractComponent`. You can do a custom implementation if you wish to
19
// do a custom extraction instead of just cloning the entire component.
20
//
21
// To be noted that the `SyncToRenderWorld` component, which spawns the corresponding entity on the Render World,
22
// is automatically added as a requirement through the `ExtractComponentPlugin`.
23
#[derive(Component, Clone, ExtractComponent, Debug)]
24
struct A(pub f32);
25
26
// The B component is extracted manually inside the `extract_components` system.
27
// `SyncToRenderWorld` ensures that an equivalent entity will be spawned in the Render World
28
// and the two will be associated in the Extract schedule through the `RenderEntity` component.
29
#[derive(Component, Clone, Debug)]
30
#[require(SyncToRenderWorld)]
31
struct B(pub f32);
32
33
// The C component is the same B, but it only extracts when the `Space` key is pressed.
34
#[derive(Component, Clone, Debug)]
35
#[require(SyncToRenderWorld)]
36
struct C(pub f32);
37
38
// Message sent when the `Space` key is pressed, causing the extraction of C.
39
#[derive(Message)]
40
struct ExtractMessage;
41
42
// Resource inserted in each World, used to display its name.
43
#[derive(Resource)]
44
struct WorldName(pub String);
45
46
fn main() {
47
let mut app = App::new();
48
49
// Main World
50
app.insert_resource(WorldName("Main World".into()))
51
.add_plugins((
52
DefaultPlugins,
53
// Plugin for automatically extracting A.
54
ExtractComponentPlugin::<A>::default(),
55
))
56
.add_message::<ExtractMessage>()
57
.add_systems(Startup, setup)
58
.add_systems(Update, (set_time, trigger_extraction, display_state));
59
60
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
61
return;
62
};
63
64
// Render World
65
render_app
66
.insert_resource(WorldName("Render World".into()))
67
.add_systems(ExtractSchedule, extract_components)
68
.add_systems(Render, display_state);
69
70
app.run();
71
}
72
73
// Spawns the components on the Main World. Runs on Startup.
74
fn setup(mut commands: Commands, time: Res<Time>) {
75
commands.spawn(A(time.elapsed_secs()));
76
commands.spawn(B(time.elapsed_secs()));
77
commands.spawn(C(time.elapsed_secs()));
78
}
79
80
// Sets the elapsed time on each of the components on the Main World. Runs each frame.
81
fn set_time(mut a: Single<&mut A>, mut b: Single<&mut B>, mut c: Single<&mut C>, time: Res<Time>) {
82
a.0 = time.elapsed_secs();
83
b.0 = time.elapsed_secs();
84
c.0 = time.elapsed_secs();
85
}
86
87
// Displays the values from each of the components. The same system is used for both Worlds.
88
fn display_state(
89
a: Option<Single<(Entity, &A)>>,
90
b: Option<Single<(Entity, &B)>>,
91
c: Option<Single<(Entity, &C)>>,
92
93
// Resource used to debug the name of the World.
94
world_name: Res<WorldName>,
95
) {
96
let (a, b, c) = (
97
a.map(Single::into_inner),
98
b.map(Single::into_inner),
99
c.map(Single::into_inner),
100
);
101
info!(?a, ?b, ?c, "{: >12}", world_name.0);
102
}
103
104
// Writes a message when the `Space` key is pressed, which is later read by the `extract_components` system.
105
fn trigger_extraction(mut writer: MessageWriter<ExtractMessage>, keys: Res<ButtonInput<KeyCode>>) {
106
if keys.pressed(KeyCode::Space) {
107
writer.write(ExtractMessage);
108
}
109
}
110
111
// System that Extracts B each frame, and C only when the `Space` key was just pressed (see the `trigger_extraction` system).
112
// Extraction is done by inserting a clone of the component on the corresponding Render World entity.
113
fn extract_components(
114
b: Extract<Query<(RenderEntity, &B)>>,
115
c: Extract<Query<(RenderEntity, &C)>>,
116
mut reader: Extract<MessageReader<ExtractMessage>>,
117
mut commands: Commands,
118
) {
119
for (entity, b) in &b {
120
commands.entity(entity).insert(b.clone());
121
}
122
123
if !reader.is_empty() {
124
for (entity, c) in &c {
125
commands.entity(entity).insert(c.clone());
126
}
127
reader.clear();
128
}
129
}
130
131