forked from cart/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5c435be
commit 366a085
Showing
6 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
use super::event::{EventReader, Events}; | ||
use bevy_ecs::{Stage, World, Resources, System, IntoSystem, Local, Res, ShouldRun, SystemStage, IntoChainSystem}; | ||
use std::marker::PhantomData; | ||
|
||
pub struct AnyEventStage<T> { | ||
inner: SystemStage, | ||
_marker: PhantomData<T> | ||
} | ||
|
||
impl<A, B, C> Default for AnyEventStage<(A, B, C)> | ||
where | ||
A: Clone + Send + Sync + 'static, | ||
B: Clone + Send + Sync + 'static, | ||
C: Clone + Send + Sync + 'static, | ||
{ | ||
fn default() -> Self { | ||
Self::parallel() | ||
} | ||
} | ||
|
||
impl<A, B, C> AnyEventStage<(A, B, C)> | ||
where | ||
A: Clone + Send + Sync + 'static, | ||
B: Clone + Send + Sync + 'static, | ||
C: Clone + Send + Sync + 'static, | ||
{ | ||
pub fn new(system_stage: SystemStage) -> Self { | ||
let inner = system_stage | ||
.with_run_criteria(any_event_stage_run_criteria::<A, B, C>); | ||
|
||
Self { | ||
inner, | ||
_marker: PhantomData | ||
} | ||
} | ||
|
||
pub fn serial() -> Self { | ||
Self::new(SystemStage::serial()) | ||
} | ||
|
||
pub fn parallel() -> Self { | ||
Self::new(SystemStage::parallel()) | ||
} | ||
|
||
pub fn with_system<S, Params, IntoS>(mut self, system: IntoS) -> Self | ||
where | ||
S: System<Input = (Option<A>, Option<B>, Option<C>), Output = ()>, | ||
IntoS: IntoSystem<Params, S>, | ||
{ | ||
self.inner.add_system_boxed(Box::new(any_event_system.chain(system))); | ||
self | ||
} | ||
|
||
pub fn add_system<S, Params, IntoS>(&mut self, system: IntoS) -> &mut Self | ||
where | ||
S: System<Input = (Option<A>, Option<B>, Option<C>), Output = ()>, | ||
IntoS: IntoSystem<Params, S>, | ||
{ | ||
self.inner.add_system_boxed(Box::new(any_event_system.chain(system))); | ||
self | ||
} | ||
} | ||
|
||
impl<A, B, C> Stage for AnyEventStage<(A, B, C)> | ||
where | ||
A: Clone + Send + Sync + 'static, | ||
B: Clone + Send + Sync + 'static, | ||
C: Clone + Send + Sync + 'static, | ||
{ | ||
fn run(&mut self, world: &mut World, resources: &mut Resources) { | ||
self.inner.run(world, resources) | ||
} | ||
} | ||
|
||
/// Execute systems if there exists an event to consume. | ||
fn any_event_stage_run_criteria<A, B, C>( | ||
mut reader_a: Local<EventReader<A>>, | ||
events_a: Res<Events<A>>, | ||
mut reader_b: Local<EventReader<B>>, | ||
events_b: Res<Events<B>>, | ||
mut reader_c: Local<EventReader<C>>, | ||
events_c: Res<Events<C>>, | ||
) -> ShouldRun | ||
where | ||
A: Clone + Send + Sync + 'static, | ||
B: Clone + Send + Sync + 'static, | ||
C: Clone + Send + Sync + 'static, | ||
{ | ||
let a = reader_a.earliest(&events_a); | ||
let b = reader_b.earliest(&events_b); | ||
let c = reader_c.earliest(&events_c); | ||
|
||
if a.is_some() || b.is_some() || c.is_some() { | ||
ShouldRun::YesAndLoop | ||
} else { | ||
ShouldRun::No | ||
} | ||
} | ||
|
||
fn any_event_system<A, B, C>( | ||
mut reader_a: Local<EventReader<A>>, | ||
events_a: Res<Events<A>>, | ||
mut reader_b: Local<EventReader<B>>, | ||
events_b: Res<Events<B>>, | ||
mut reader_c: Local<EventReader<C>>, | ||
events_c: Res<Events<C>>, | ||
) -> (Option<A>, Option<B>, Option<C>) | ||
where | ||
A: Clone + Send + Sync + 'static, | ||
B: Clone + Send + Sync + 'static, | ||
C: Clone + Send + Sync + 'static, | ||
{ | ||
let a: Option<A> = reader_a.earliest(&events_a).map(|e| e.clone()); | ||
let b: Option<B> = reader_b.earliest(&events_b).map(|e| e.clone()); | ||
let c: Option<C> = reader_c.earliest(&events_c).map(|e| e.clone()); | ||
|
||
(a, b, c) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use super::event::{EventReader, Events}; | ||
use bevy_ecs::{Stage, World, Resources, System, IntoSystem, Local, Res, ShouldRun, SystemStage, IntoChainSystem}; | ||
use std::marker::PhantomData; | ||
|
||
|
||
pub struct EventStage<T> { | ||
inner: SystemStage, | ||
_marker: PhantomData<T> | ||
} | ||
|
||
impl<T> Default for EventStage<T> | ||
where | ||
T: Clone + Send + Sync + 'static | ||
{ | ||
fn default() -> Self { | ||
Self::parallel() | ||
} | ||
} | ||
|
||
impl<T> EventStage<T> | ||
where | ||
T: Clone + Send + Sync + 'static | ||
{ | ||
pub fn new(system_stage: SystemStage) -> Self { | ||
let inner = system_stage | ||
.with_run_criteria(event_stage_run_criteria::<T>); | ||
|
||
Self { | ||
inner, | ||
_marker: PhantomData | ||
} | ||
} | ||
|
||
pub fn serial() -> Self { | ||
Self::new(SystemStage::serial()) | ||
} | ||
|
||
pub fn parallel() -> Self { | ||
Self::new(SystemStage::parallel()) | ||
} | ||
|
||
pub fn with_system<S, Params, IntoS>(mut self, system: IntoS) -> Self | ||
where | ||
S: System<Input = T, Output = ()>, | ||
IntoS: IntoSystem<Params, S>, | ||
{ | ||
self.inner.add_system_boxed(Box::new(next_event_system.chain(system))); | ||
self | ||
} | ||
|
||
pub fn add_system<S, Params, IntoS>(&mut self, system: IntoS) -> &mut Self | ||
where | ||
S: System<Input = T, Output = ()>, | ||
IntoS: IntoSystem<Params, S>, | ||
{ | ||
self.inner.add_system_boxed(Box::new(next_event_system.chain(system))); | ||
self | ||
} | ||
} | ||
|
||
impl<T> Stage for EventStage<T> | ||
where | ||
T: Clone + Send + Sync + 'static | ||
{ | ||
fn run(&mut self, world: &mut World, resources: &mut Resources) { | ||
self.inner.run(world, resources) | ||
} | ||
} | ||
|
||
/// Execute systems if there exists an event to consume. | ||
fn event_stage_run_criteria<T: Send + Sync + 'static>( | ||
mut reader: Local<EventReader<T>>, | ||
events: Res<Events<T>> | ||
) -> ShouldRun { | ||
if reader.earliest(&events).is_some() { | ||
ShouldRun::YesAndLoop | ||
} else { | ||
ShouldRun::No | ||
} | ||
} | ||
|
||
/// Fetch the next event and return it. This system is chained into all systems added to EventStage. | ||
/// | ||
/// Unwrap is okay here because this system will only be run if there exists an event to consume | ||
fn next_event_system<T: Clone + Send + Sync + 'static>( | ||
mut reader: Local<EventReader<T>>, | ||
events: Res<Events<T>> | ||
) -> T { | ||
reader.earliest(&events).unwrap().clone() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
use bevy::prelude::*; | ||
use bevy::app::AnyEventStage; | ||
|
||
/// This example creates a three new events & demonstrates a system that runs when any of those | ||
/// events have fired. | ||
fn main() { | ||
App::build() | ||
.add_plugins(DefaultPlugins) | ||
.add_event::<EventA>() | ||
.add_event::<EventB>() | ||
.add_event::<EventC>() | ||
.init_resource::<EventTriggerState>() | ||
.add_system(event_trigger_system) | ||
.add_stage_after( | ||
stage::UPDATE, | ||
"event_handlers", | ||
AnyEventStage::<(EventA, EventB, EventC)>::default().with_system(event_listener_system) | ||
) | ||
.run(); | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
struct EventA; | ||
|
||
#[derive(Clone, Debug)] | ||
struct EventB; | ||
|
||
#[derive(Clone, Debug)] | ||
struct EventC; | ||
|
||
struct EventTriggerState { | ||
event_timer_a: Timer, | ||
event_timer_b: Timer, | ||
event_timer_c: Timer, | ||
} | ||
|
||
impl Default for EventTriggerState { | ||
fn default() -> Self { | ||
EventTriggerState { | ||
event_timer_a: Timer::from_seconds(1.0, true), | ||
event_timer_b: Timer::from_seconds(0.5, true), | ||
event_timer_c: Timer::from_seconds(0.8, true), | ||
} | ||
} | ||
} | ||
|
||
// sends EventA every second, EventB every 0.5 seconds, and EventC every 0.8 seconds | ||
fn event_trigger_system( | ||
time: Res<Time>, | ||
mut state: ResMut<EventTriggerState>, | ||
mut events_a: ResMut<Events<EventA>>, | ||
mut events_b: ResMut<Events<EventB>>, | ||
mut events_c: ResMut<Events<EventC>>, | ||
) { | ||
if state.event_timer_a.tick(time.delta_seconds()).finished() { | ||
events_a.send(EventA); | ||
} | ||
|
||
if state.event_timer_b.tick(time.delta_seconds()).finished() { | ||
events_b.send(EventB); | ||
} | ||
|
||
if state.event_timer_c.tick(time.delta_seconds()).finished() { | ||
events_c.send(EventC); | ||
} | ||
} | ||
|
||
// prints events as they come in | ||
fn event_listener_system(In((a, b, c)): In<(Option<EventA>, Option<EventB>, Option<EventC>)>) { | ||
println!("Received Events A: {:?} | B: {:?} | C: {:?}", a, b, c); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use bevy::prelude::*; | ||
|
||
/// This example creates a new event, a system that triggers the event once per second, | ||
/// and a system that prints a message whenever the event is received. | ||
fn main() { | ||
App::build() | ||
.add_plugins(DefaultPlugins) | ||
.add_event::<MyEvent>() | ||
.init_resource::<EventTriggerState>() | ||
.add_system(event_trigger_system) | ||
.add_stage_after( | ||
stage::UPDATE, | ||
"event_handlers", | ||
EventStage::<MyEvent>::default().with_system(event_listener_system) | ||
) | ||
.run(); | ||
} | ||
|
||
#[derive(Clone)] | ||
struct MyEvent { | ||
pub message: String, | ||
} | ||
|
||
struct EventTriggerState { | ||
event_timer: Timer, | ||
} | ||
|
||
impl Default for EventTriggerState { | ||
fn default() -> Self { | ||
EventTriggerState { | ||
event_timer: Timer::from_seconds(1.0, true), | ||
} | ||
} | ||
} | ||
|
||
// sends MyEvent every second | ||
fn event_trigger_system( | ||
time: Res<Time>, | ||
mut state: ResMut<EventTriggerState>, | ||
mut my_events: ResMut<Events<MyEvent>>, | ||
) { | ||
if state.event_timer.tick(time.delta_seconds()).finished() { | ||
my_events.send(MyEvent { | ||
message: "MyEvent just happened!".to_string(), | ||
}); | ||
} | ||
} | ||
|
||
// prints events as they come in | ||
fn event_listener_system(In(my_event): In<MyEvent>) { | ||
println!("{}", my_event.message); | ||
} |