organize examples and add ecs guide
87
Cargo.toml
|
@ -48,6 +48,7 @@ glam = "0.8.6"
|
|||
[workspace]
|
||||
members = [
|
||||
"crates/*",
|
||||
"examples/app/dynamic_plugin_loading/example_plugin"
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -58,4 +59,88 @@ type-uuid = "0.1"
|
|||
env_logger = "0.7"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
opt-level = 3
|
||||
|
||||
[[example]]
|
||||
name = "hello_world"
|
||||
path = "examples/hello_world.rs"
|
||||
|
||||
[[example]]
|
||||
name = "load_model"
|
||||
path = "examples/3d/load_model.rs"
|
||||
|
||||
[[example]]
|
||||
name = "parenting"
|
||||
path = "examples/3d/parenting.rs"
|
||||
|
||||
[[example]]
|
||||
name = "scene"
|
||||
path = "examples/3d/scene.rs"
|
||||
|
||||
[[example]]
|
||||
name = "spawner"
|
||||
path = "examples/3d/spawner.rs"
|
||||
|
||||
[[example]]
|
||||
name = "texture"
|
||||
path = "examples/3d/texture.rs"
|
||||
|
||||
[[example]]
|
||||
name = "dynamic_plugin_loading"
|
||||
path = "examples/app/dynamic_plugin_loading/main.rs"
|
||||
|
||||
[[example]]
|
||||
name = "empty_defaults"
|
||||
path = "examples/app/empty_defaults.rs"
|
||||
|
||||
[[example]]
|
||||
name = "empty"
|
||||
path = "examples/app/empty.rs"
|
||||
|
||||
[[example]]
|
||||
name = "headless"
|
||||
path = "examples/app/headless.rs"
|
||||
|
||||
[[example]]
|
||||
name = "event"
|
||||
path = "examples/ecs/event.rs"
|
||||
|
||||
[[example]]
|
||||
name = "startup_system"
|
||||
path = "examples/ecs/startup_system.rs"
|
||||
|
||||
[[example]]
|
||||
name = "ecs_guide"
|
||||
path = "examples/ecs/ecs_guide.rs"
|
||||
|
||||
[[example]]
|
||||
name = "input_mouse"
|
||||
path = "examples/input/input_mouse.rs"
|
||||
|
||||
[[example]]
|
||||
name = "input_keyboard"
|
||||
path = "examples/input/input_keyboard.rs"
|
||||
|
||||
[[example]]
|
||||
name = "serializing"
|
||||
path = "examples/serializing/serializing.rs"
|
||||
|
||||
[[example]]
|
||||
name = "shader_custom_material"
|
||||
path = "examples/shader/shader_custom_material.rs"
|
||||
|
||||
[[example]]
|
||||
name = "shader_defs"
|
||||
path = "examples/shader/shader_defs.rs"
|
||||
|
||||
[[example]]
|
||||
name = "ui"
|
||||
path = "examples/ui/ui.rs"
|
||||
|
||||
[[example]]
|
||||
name = "ui_bench"
|
||||
path = "examples/ui/ui_bench.rs"
|
||||
|
||||
[[example]]
|
||||
name = "multiple_windows"
|
||||
path = "examples/window/multiple_windows.rs"
|
|
@ -1,4 +1,4 @@
|
|||
# [![Bevy](assets/bevy_logo_light_small.svg)](https://bevyengine.org)
|
||||
# [![Bevy](assets/branding/bevy_logo_light_small.svg)](https://bevyengine.org)
|
||||
[![Crates.io](https://img.shields.io/crates/v/bevy.svg)](https://crates.io/crates/bevy)
|
||||
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bevyengine/bevy/LICENSE)
|
||||
[![Crates.io](https://img.shields.io/crates/d/bevy.svg)](https://crates.io/crates/bevy)
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
@ -116,14 +116,14 @@ impl AppBuilder {
|
|||
self.add_system_to_stage(stage::UPDATE, system)
|
||||
}
|
||||
|
||||
pub fn add_system_init<T>(&mut self, build: impl FnMut(&mut Resources) -> T) -> &mut Self
|
||||
pub fn init_system<T>(&mut self, build: impl FnMut(&mut Resources) -> T) -> &mut Self
|
||||
where
|
||||
T: Into<System>,
|
||||
{
|
||||
self.add_system_to_stage_init(stage::UPDATE, build)
|
||||
self.init_system_to_stage(stage::UPDATE, build)
|
||||
}
|
||||
|
||||
pub fn add_system_to_stage_init<T>(
|
||||
pub fn init_system_to_stage<T>(
|
||||
&mut self,
|
||||
stage: &str,
|
||||
mut build: impl FnMut(&mut Resources) -> T,
|
||||
|
@ -151,17 +151,17 @@ impl AppBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_startup_system_init<T>(
|
||||
pub fn init_startup_system<T>(
|
||||
&mut self,
|
||||
build: impl FnMut(&mut Resources) -> T,
|
||||
) -> &mut Self
|
||||
where
|
||||
T: Into<System>,
|
||||
{
|
||||
self.add_startup_system_to_stage_init(stage::STARTUP, build)
|
||||
self.init_startup_system_to_stage(stage::STARTUP, build)
|
||||
}
|
||||
|
||||
pub fn add_startup_system_to_stage_init<T>(
|
||||
pub fn init_startup_system_to_stage<T>(
|
||||
&mut self,
|
||||
stage: &str,
|
||||
mut build: impl FnMut(&mut Resources) -> T,
|
||||
|
@ -211,7 +211,7 @@ impl AppBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_resource_init<R>(&mut self) -> &mut Self
|
||||
pub fn init_resource<R>(&mut self) -> &mut Self
|
||||
where
|
||||
R: FromResources + Send + Sync + 'static,
|
||||
{
|
||||
|
|
|
@ -19,6 +19,20 @@ pub struct ScheduleRunnerPlugin {
|
|||
pub run_mode: RunMode,
|
||||
}
|
||||
|
||||
impl ScheduleRunnerPlugin {
|
||||
pub fn run_once() -> Self {
|
||||
ScheduleRunnerPlugin {
|
||||
run_mode: RunMode::Once,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_loop(wait_duration: Duration) -> Self {
|
||||
ScheduleRunnerPlugin {
|
||||
run_mode: RunMode::Loop { wait: Some(wait_duration) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppPlugin for ScheduleRunnerPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
let run_mode = self.run_mode;
|
||||
|
|
|
@ -28,7 +28,7 @@ impl Default for DiagnosticsPlugin {
|
|||
|
||||
impl AppPlugin for DiagnosticsPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_resource_init::<Diagnostics>();
|
||||
app.init_resource::<Diagnostics>();
|
||||
if self.add_defaults {
|
||||
app.add_startup_system(setup_frame_time_diagnostic_system.system())
|
||||
.add_system(frame_time_diagnostic_system.system());
|
||||
|
|
|
@ -70,10 +70,10 @@ impl AppPlugin for RenderPlugin {
|
|||
.add_resource(AssetBatchers::default())
|
||||
// core systems
|
||||
.add_system(entity_render_resource_assignments_system())
|
||||
.add_system_to_stage_init(stage::POST_UPDATE, camera::camera_update_system)
|
||||
.init_system_to_stage(stage::POST_UPDATE, camera::camera_update_system)
|
||||
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_specializer_system())
|
||||
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_batcher_system())
|
||||
// render resource provider systems
|
||||
.add_system_to_stage_init(RENDER_RESOURCE_STAGE, mesh_resource_provider_system);
|
||||
.init_system_to_stage(RENDER_RESOURCE_STAGE, mesh_resource_provider_system);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,29 +36,6 @@ impl Asset<TextureType> for Texture {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_texels(size: usize) -> Vec<u8> {
|
||||
use std::iter;
|
||||
|
||||
(0..size * size)
|
||||
.flat_map(|id| {
|
||||
// get high five for recognizing this ;)
|
||||
let cx = 3.0 * (id % size) as f32 / (size - 1) as f32 - 2.0;
|
||||
let cy = 2.0 * (id / size) as f32 / (size - 1) as f32 - 1.0;
|
||||
let (mut x, mut y, mut count) = (cx, cy, 0);
|
||||
while count < 0xFF && x * x + y * y < 4.0 {
|
||||
let old_x = x;
|
||||
x = x * x - y * y + cx;
|
||||
y = 2.0 * old_x * y + cy;
|
||||
count += 1;
|
||||
}
|
||||
iter::once(0xFF - (count * 5) as u8)
|
||||
.chain(iter::once(0xFF - (count * 15) as u8))
|
||||
.chain(iter::once(0xFF - (count * 50) as u8))
|
||||
.chain(iter::once(1))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl ShaderDefSuffixProvider for Option<Handle<Texture>> {
|
||||
fn get_shader_def(&self) -> Option<&'static str> {
|
||||
match *self {
|
||||
|
|
|
@ -4,15 +4,13 @@ fn main() {
|
|||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_startup_system(setup)
|
||||
.add_system_init(bevy::input::system::exit_on_esc_system)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(world: &mut World, resources: &mut Resources) {
|
||||
// load the mesh
|
||||
let mesh = gltf::load_gltf("examples/assets/Monkey.gltf")
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let model_path = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/models/Monkey.gltf");
|
||||
let mesh = gltf::load_gltf(&model_path).unwrap().unwrap();
|
||||
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mesh_handle = mesh_storage.add(mesh);
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_input::system::exit_on_esc_system;
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_startup_system(setup)
|
||||
.add_system_init(exit_on_esc_system)
|
||||
.run();
|
||||
}
|
||||
|
|
@ -11,9 +11,11 @@ fn main() {
|
|||
fn setup(world: &mut World, resources: &mut Resources) {
|
||||
// load a texture
|
||||
let mut texture_storage = resources.get_mut::<AssetStorage<Texture>>().unwrap();
|
||||
let texture = Texture::load(TextureType::Png(
|
||||
concat!(env!("CARGO_MANIFEST_DIR"), "/assets/bevy_logo_dark_big.png").to_string(),
|
||||
));
|
||||
let texture_path = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/assets/branding/bevy_logo_dark_big.png"
|
||||
);
|
||||
let texture = Texture::load(TextureType::Png(texture_path.to_string()));
|
||||
let aspect = texture.height as f32 / texture.width as f32;
|
||||
let texture_handle = texture_storage.add(texture);
|
||||
|
|
@ -8,7 +8,4 @@ edition = "2018"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
bevy = { path = "../../../../bevy" }
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
bevy = { path = "../../../../../bevy" }
|
|
@ -1,7 +1,4 @@
|
|||
use bevy::{
|
||||
app::schedule_runner::{RunMode, ScheduleRunnerPlugin},
|
||||
prelude::*,
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
use std::time::Duration;
|
||||
|
||||
// This example disables the default plugins by not registering them during setup.
|
||||
|
@ -14,19 +11,13 @@ use std::time::Duration;
|
|||
fn main() {
|
||||
// this app runs once
|
||||
App::build()
|
||||
.add_plugin(ScheduleRunnerPlugin {
|
||||
run_mode: RunMode::Once,
|
||||
})
|
||||
.add_plugin(ScheduleRunnerPlugin::run_once())
|
||||
.add_system(hello_world_system.system())
|
||||
.run();
|
||||
|
||||
// this app loops forever at 60 fps
|
||||
App::build()
|
||||
.add_plugin(ScheduleRunnerPlugin {
|
||||
run_mode: RunMode::Loop {
|
||||
wait: Some(Duration::from_secs_f64(1.0 / 60.0)),
|
||||
},
|
||||
})
|
||||
.add_plugin(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(1.0 / 60.0)))
|
||||
.add_system(hello_world_system.system())
|
||||
.run();
|
||||
}
|
217
examples/ecs/ecs_guide.rs
Normal file
|
@ -0,0 +1,217 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
/// This is a guided introduction to Bevy's "Entity Component System" (ECS)
|
||||
/// All Bevy app logic is built using the ECS pattern, so definitely pay attention!
|
||||
///
|
||||
/// Why ECS?
|
||||
/// * Data oriented: Functionality is driven by data
|
||||
/// * Clean Architecture: Loose coupling of functionality / prevents deeply nested inheritance
|
||||
/// * High Performance: Massively parallel and cache friendly
|
||||
///
|
||||
/// ECS Definitions:
|
||||
///
|
||||
/// Component: just a normal Rust data type. generally scoped to a single piece of functionality
|
||||
/// Examples: position, velocity, health, color, name
|
||||
///
|
||||
/// Entity: a collection of components with a unique id
|
||||
/// Examples: Entity1 { Name("Alice"), Position(0, 0) }, Entity2 { Name("Bill"), Position(10, 5) }
|
||||
|
||||
/// Resource: a shared global piece of data
|
||||
/// Examples: asset_storage, events, system state
|
||||
///
|
||||
/// System: runs logic on entities, components, and resources
|
||||
/// Examples: move_system, damage_system
|
||||
///
|
||||
/// Now that you know a little bit about ECS, lets look at some Bevy code!
|
||||
|
||||
// Our Bevy app's entry point
|
||||
fn main() {
|
||||
// Bevy apps are created using the builder pattern. Here add our
|
||||
App::build()
|
||||
// This plugin runs our app's "system schedule" exactly once. Most apps will run on a loop,
|
||||
// but we don't want to spam your console with a bunch of example text :)
|
||||
.add_plugin(ScheduleRunnerPlugin::run_once())
|
||||
// Resources can be added to our app like this
|
||||
.add_resource(A { value: 1 })
|
||||
// Resources that implement the Default or FromResources trait can be added like this:
|
||||
.init_resource::<B>()
|
||||
.init_resource::<State>()
|
||||
// Systems can be added to our app like this
|
||||
// the system() call converts normal rust functions into ECS systems
|
||||
.add_system(empty_system.system())
|
||||
// Startup systems run exactly once BEFORE all other systems. These are generally used for
|
||||
// app initialization code (adding entities and resources)
|
||||
.add_startup_system(startup_system)
|
||||
// Systems that need resources to be constructed can be added like this
|
||||
.init_system(complex_system)
|
||||
// Here we just the rest of the example systems
|
||||
.add_system(resource_system.system())
|
||||
.add_system(for_each_entity_system.system())
|
||||
.add_system(resources_and_components_system.system())
|
||||
.add_system(command_buffer_system.system())
|
||||
.add_system(thread_local_system)
|
||||
.add_system(closure_system())
|
||||
.add_system(stateful_system.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
// RESOURCES: "global" state accessible by systems
|
||||
|
||||
struct A {
|
||||
value: usize,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct B {
|
||||
value: usize,
|
||||
}
|
||||
|
||||
struct C;
|
||||
|
||||
// COMPONENTS: pieces of functionality we add to entities
|
||||
|
||||
struct X {
|
||||
value: usize,
|
||||
}
|
||||
struct Y {
|
||||
value: usize,
|
||||
}
|
||||
|
||||
// SYSTEMS: logic that runs on entities, components, and resources
|
||||
|
||||
// This is the simplest system. It will run once each time our app updates:
|
||||
fn empty_system() {
|
||||
println!("hello!");
|
||||
}
|
||||
|
||||
// Systems can also read and modify resources:
|
||||
fn resource_system(a: Resource<A>, mut b: ResourceMut<B>) {
|
||||
b.value += 1;
|
||||
println!("resource_system: {} {}", a.value, b.value);
|
||||
}
|
||||
|
||||
// This system runs once for each entity with the X and Y component
|
||||
// NOTE: x is a read-only reference (Ref) whereas y can be modified (RefMut)
|
||||
fn for_each_entity_system(x: Ref<X>, mut y: RefMut<Y>) {
|
||||
y.value += 1;
|
||||
println!("for_each_entity_system: {} {}", x.value, y.value);
|
||||
}
|
||||
|
||||
// This system is the same as the above example, but it also accesses resource A
|
||||
// NOTE: resources must always come before components in system functions
|
||||
fn resources_and_components_system(a: Resource<A>, x: Ref<X>, mut y: RefMut<Y>) {
|
||||
y.value += 1;
|
||||
println!("resources_and_components:");
|
||||
println!(" components: {} {}", x.value, y.value);
|
||||
println!(" resource: {} ", a.value);
|
||||
}
|
||||
|
||||
// This is a "startup" system that runs once when the app starts up. The only thing that distinguishes a
|
||||
// startup" system from a "normal" system is how it is registered:
|
||||
// app.add_startup_system(startup_system)
|
||||
// app.add_system(normal_system)
|
||||
// With startup systems we can create resources and add entities to our world, which can then be used by
|
||||
// our other systems:
|
||||
fn startup_system(world: &mut World, resources: &mut Resources) {
|
||||
// We already added A and B when we built our App above, so we don't re-add them here
|
||||
resources.insert(C);
|
||||
|
||||
// Add some entities to our world
|
||||
world.insert(
|
||||
(),
|
||||
vec![
|
||||
(X { value: 0 }, Y { value: 1 }),
|
||||
(X { value: 2 }, Y { value: 3 }),
|
||||
],
|
||||
);
|
||||
|
||||
// Add some entities to our world
|
||||
world.insert(
|
||||
(),
|
||||
vec![
|
||||
(X { value: 0 }, Y { value: 1 }),
|
||||
(X { value: 2 }, Y { value: 3 }),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// This system uses a command buffer to create a new entity on each iteration
|
||||
// Normal systems cannot safely access the World instance because they run in parallel
|
||||
// Command buffers give us the ability to queue up changes to our World without directly accessing it
|
||||
// NOTE: Command buffers must always come before resources and components in system functions
|
||||
fn command_buffer_system(command_buffer: &mut CommandBuffer, a: Resource<A>) {
|
||||
// Creates a new entity with a value read from resource A
|
||||
command_buffer.insert((), vec![(X { value: a.value },)]);
|
||||
}
|
||||
|
||||
// If you really need full/immediate read/write access to the world or resources, you can use a "thread local system".
|
||||
// These run on the main app thread (hence the name "thread local")
|
||||
// WARNING: These will block all parallel execution of other systems until they finish, so they should generally be avoided
|
||||
// NOTE: You may notice that this looks exactly like the "setup" system above. Thats because they are both thread local!
|
||||
fn thread_local_system(world: &mut World, _resources: &mut Resources) {
|
||||
world.insert((), vec![(X { value: 1 },)]);
|
||||
}
|
||||
|
||||
// These are like normal systems, but they also "capture" variables, which they can use as local state.
|
||||
// This system captures the "counter" variable and uses it to maintain a count across executions
|
||||
// NOTE: This function returns a Box<dyn Schedulable> type. If you are new to rust don't worry! All you
|
||||
// need to know for now is that the Box contains our system AND the state it captured.
|
||||
// You may recognize the .system() call from when we added our system functions to our App in the main()
|
||||
// function above. Now you know that we are actually converting our functions into the Box<dyn Schedulable> type!
|
||||
fn closure_system() -> Box<dyn Schedulable> {
|
||||
let mut counter = 0;
|
||||
(move |x: Ref<X>, mut y: RefMut<Y>| {
|
||||
y.value += 1;
|
||||
println!("closure_system: {} {}", x.value, y.value);
|
||||
println!(" ran {} times: ", counter);
|
||||
counter += 1;
|
||||
})
|
||||
.system()
|
||||
}
|
||||
|
||||
// Closure systems should be avoided in general because they hide state from the ECS. This makes scenarios
|
||||
// like "saving", "networking/multiplayer", and "replays" much harder.
|
||||
// Instead you should use the "state" pattern whenever possible:
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
counter: usize,
|
||||
}
|
||||
|
||||
fn stateful_system(mut state: RefMut<State>, x: Ref<X>, mut y: RefMut<Y>) {
|
||||
y.value += 1;
|
||||
println!("stateful_system: {} {}", x.value, y.value);
|
||||
println!(" ran {} times: ", state.counter);
|
||||
state.counter += 1;
|
||||
}
|
||||
|
||||
// If you need more flexibility, you can define complex systems using "system builders".
|
||||
// SystemBuilder enables scenarios like "multiple queries" and "query filters"
|
||||
fn complex_system(_resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut counter = 0;
|
||||
SystemBuilder::new("complex_system")
|
||||
.read_resource::<A>()
|
||||
.write_resource::<B>()
|
||||
// this query is equivalent to the system we saw above: system(x: Ref<X>, y: RefMut<Y>)
|
||||
.with_query(<(Read<X>, Write<Y>)>::query())
|
||||
// this query only runs on entities with an X component that has changed since the last update
|
||||
.with_query(<Read<X>>::query().filter(changed::<X>()))
|
||||
.build(
|
||||
move |_command_buffer, world, (a, ref mut b), (x_y_query, x_changed_query)| {
|
||||
println!("complex_system:");
|
||||
println!(" resources: {} {}", a.value, b.value);
|
||||
for (x, mut y) in x_y_query.iter_mut(world) {
|
||||
y.value += 1;
|
||||
println!(
|
||||
" processed entity {} times: {} {}",
|
||||
counter, x.value, y.value
|
||||
);
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
for x in x_changed_query.iter(world) {
|
||||
println!(" x changed: {}", x.value);
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -5,7 +5,7 @@ fn main() {
|
|||
.add_default_plugins()
|
||||
.add_event::<MyEvent>()
|
||||
.add_resource(EventTriggerState::default())
|
||||
.add_resource_init::<EventListenerState>()
|
||||
.init_resource::<EventListenerState>()
|
||||
.add_system(event_trigger_system.system())
|
||||
.add_system(event_listener_system.system())
|
||||
.run();
|
||||
|
@ -29,7 +29,7 @@ fn event_trigger_system(
|
|||
state.elapsed += time.delta_seconds;
|
||||
if state.elapsed > 1.0 {
|
||||
my_events.send(MyEvent {
|
||||
message: "Hello World".to_string(),
|
||||
message: "MyEvent just happened!".to_string(),
|
||||
});
|
||||
|
||||
state.elapsed = 0.0;
|
22
examples/ecs/startup_system.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use bevy::{
|
||||
app::schedule_runner::ScheduleRunnerPlugin,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_plugin(ScheduleRunnerPlugin::run_once()) // only run the app once so the printed system order is clearer
|
||||
.add_startup_system(startup_system.system())
|
||||
.add_system(normal_system.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
/// Startup systems are run exactly once when the app starts up.
|
||||
/// They run right before "normal" systems run.
|
||||
fn startup_system() {
|
||||
println!("startup system ran first");
|
||||
}
|
||||
|
||||
fn normal_system() {
|
||||
println!("normal system ran second");
|
||||
}
|
|
@ -6,7 +6,7 @@ use bevy::{
|
|||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_resource_init::<State>()
|
||||
.init_resource::<State>()
|
||||
.add_system(collect_input_system.system())
|
||||
.add_system(move_system.system())
|
||||
.add_startup_system(setup)
|
|
@ -6,7 +6,7 @@ use bevy::{
|
|||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_resource_init::<State>()
|
||||
.init_resource::<State>()
|
||||
.add_system(mouse_input_system.system())
|
||||
.run();
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_startup_system(startup_system.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
/// Set up a simple scene using a "startup system".
|
||||
/// Startup systems are run exactly once when the app starts up.
|
||||
/// They run right before "normal" systems run.
|
||||
fn startup_system(
|
||||
command_buffer: &mut CommandBuffer,
|
||||
mut meshes: ResourceMut<AssetStorage<Mesh>>,
|
||||
mut materials: ResourceMut<AssetStorage<StandardMaterial>>,
|
||||
) {
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_material_handle = materials.add(StandardMaterial {
|
||||
albedo: Color::rgb(0.5, 0.4, 0.3),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
command_buffer
|
||||
.build()
|
||||
// cube
|
||||
.add_entity(MeshEntity {
|
||||
mesh: cube_handle,
|
||||
material: cube_material_handle,
|
||||
translation: Translation::new(0.0, 0.0, 0.0),
|
||||
..Default::default()
|
||||
})
|
||||
// light
|
||||
.add_entity(LightEntity {
|
||||
translation: Translation::new(4.0, -4.0, 5.0),
|
||||
..Default::default()
|
||||
})
|
||||
// camera
|
||||
.add_entity(CameraEntity {
|
||||
local_to_world: LocalToWorld(Mat4::look_at_rh(
|
||||
Vec3::new(3.0, 8.0, 5.0),
|
||||
Vec3::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, 1.0),
|
||||
)),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
/// Illustrates the different ways you can declare systems
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_event::<MyEvent>()
|
||||
.add_startup_system(setup_system)
|
||||
.add_system_init(built_system)
|
||||
.add_system(simple_system.system())
|
||||
.add_system(closure_system())
|
||||
.run();
|
||||
}
|
||||
|
||||
struct MyEvent(usize);
|
||||
|
||||
// resources
|
||||
struct A(usize);
|
||||
|
||||
// components
|
||||
struct X(usize);
|
||||
struct Y(usize);
|
||||
|
||||
// add our resources and entities
|
||||
fn setup_system(world: &mut World, resources: &mut Resources) {
|
||||
resources.insert(A(0));
|
||||
world.insert((), vec![(X(0), Y(1)), (X(2), Y(3))]);
|
||||
}
|
||||
|
||||
// runs once for each entity with the X and Y component
|
||||
fn simple_system(x: Ref<X>, mut y: RefMut<Y>) {
|
||||
y.0 += 1;
|
||||
println!("processed entity: {} {}", x.0, y.0);
|
||||
}
|
||||
|
||||
// does the same thing as the first system, but also captures the "counter" variable and uses it as internal state
|
||||
fn closure_system() -> Box<dyn Schedulable> {
|
||||
let mut counter = 0;
|
||||
(move |x: Ref<X>, mut y: RefMut<Y>| {
|
||||
y.0 += 1;
|
||||
println!("processed entity: {} {}", x.0, y.0);
|
||||
println!("ran {} times", counter);
|
||||
counter += 1;
|
||||
})
|
||||
.system()
|
||||
}
|
||||
|
||||
// if you need more flexibility, you can define complex systems using the system builder
|
||||
fn built_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut my_event_reader = resources.get_event_reader::<MyEvent>();
|
||||
SystemBuilder::new("example")
|
||||
.read_resource::<Events<MyEvent>>()
|
||||
.write_resource::<A>()
|
||||
.with_query(<(Read<X>, Write<Y>)>::query())
|
||||
.build(
|
||||
move |_command_buffer, world, (my_events, ref mut a), query| {
|
||||
for event in my_event_reader.iter(&my_events) {
|
||||
a.0 += event.0;
|
||||
println!("modified resource A with event: {}", event.0);
|
||||
}
|
||||
for (x, mut y) in query.iter_mut(world) {
|
||||
y.0 += 1;
|
||||
println!("processed entity: {} {}", x.0, y.0);
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -39,7 +39,7 @@ pub use crate::window::{Window, WindowDescriptor, WindowPlugin, Windows};
|
|||
pub use crate::{
|
||||
app::{
|
||||
stage, App, AppBuilder, AppPlugin, EntityArchetype, EventReader, Events, GetEventReader,
|
||||
System,
|
||||
System, schedule_runner::ScheduleRunnerPlugin
|
||||
},
|
||||
math::{self, Mat3, Mat4, Quat, Vec2, Vec3, Vec4},
|
||||
AddDefaultPlugins,
|
||||
|
|