Add condition_changed
and condition_became_true
to common_conditions
(#14917)
# Objective - I needed to run a system whenever a specific condition became true after being previously false. - Other users might also need to run a system when a condition changes, regardless of if it became true or false. ## Solution - This adds two systems to common_conditions: - `condition_changed` that changes whenever the inner condition changes - `condition_became_true` that returns true whenever the inner condition becomes true after previously being false ## Testing - I added a doctest for each function --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
This commit is contained in:
parent
23979b8160
commit
12f005a024
@ -490,16 +490,16 @@ mod sealed {
|
|||||||
|
|
||||||
/// A collection of [run conditions](Condition) that may be useful in any bevy app.
|
/// A collection of [run conditions](Condition) that may be useful in any bevy app.
|
||||||
pub mod common_conditions {
|
pub mod common_conditions {
|
||||||
use super::NotSystem;
|
use super::{Condition, NotSystem};
|
||||||
use crate::{
|
use crate::{
|
||||||
change_detection::DetectChanges,
|
change_detection::DetectChanges,
|
||||||
event::{Event, EventReader},
|
event::{Event, EventReader},
|
||||||
prelude::{Component, Query, With},
|
prelude::{Component, Query, With},
|
||||||
removal_detection::RemovedComponents,
|
removal_detection::RemovedComponents,
|
||||||
system::{IntoSystem, Local, Res, Resource, System},
|
system::{In, IntoSystem, Local, Res, Resource, System},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// on the first time the condition is run and false every time after.
|
/// on the first time the condition is run and false every time after.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -537,7 +537,7 @@ pub mod common_conditions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if the resource exists.
|
/// if the resource exists.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -572,7 +572,7 @@ pub mod common_conditions {
|
|||||||
res.is_some()
|
res.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
|
/// Generates a [`Condition`]-satisfying closure that returns `true`
|
||||||
/// if the resource is equal to `value`.
|
/// if the resource is equal to `value`.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
@ -612,7 +612,7 @@ pub mod common_conditions {
|
|||||||
move |res: Res<T>| *res == value
|
move |res: Res<T>| *res == value
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
|
/// Generates a [`Condition`]-satisfying closure that returns `true`
|
||||||
/// if the resource exists and is equal to `value`.
|
/// if the resource exists and is equal to `value`.
|
||||||
///
|
///
|
||||||
/// The condition will return `false` if the resource does not exist.
|
/// The condition will return `false` if the resource does not exist.
|
||||||
@ -657,7 +657,7 @@ pub mod common_conditions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if the resource of the given type has been added since the condition was last checked.
|
/// if the resource of the given type has been added since the condition was last checked.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -698,7 +698,7 @@ pub mod common_conditions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if the resource of the given type has had its value changed since the condition
|
/// if the resource of the given type has had its value changed since the condition
|
||||||
/// was last checked.
|
/// was last checked.
|
||||||
///
|
///
|
||||||
@ -752,7 +752,7 @@ pub mod common_conditions {
|
|||||||
res.is_changed()
|
res.is_changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if the resource of the given type has had its value changed since the condition
|
/// if the resource of the given type has had its value changed since the condition
|
||||||
/// was last checked.
|
/// was last checked.
|
||||||
///
|
///
|
||||||
@ -812,7 +812,7 @@ pub mod common_conditions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if the resource of the given type has had its value changed since the condition
|
/// if the resource of the given type has had its value changed since the condition
|
||||||
/// was last checked.
|
/// was last checked.
|
||||||
///
|
///
|
||||||
@ -889,7 +889,7 @@ pub mod common_conditions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if the resource of the given type has been removed since the condition was last checked.
|
/// if the resource of the given type has been removed since the condition was last checked.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -941,7 +941,7 @@ pub mod common_conditions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if there are any new events of the given type since it was last called.
|
/// if there are any new events of the given type since it was last called.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -985,7 +985,7 @@ pub mod common_conditions {
|
|||||||
reader.read().count() > 0
|
reader.read().count() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if there are any entities with the given component type.
|
/// if there are any entities with the given component type.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -1022,7 +1022,7 @@ pub mod common_conditions {
|
|||||||
!query.is_empty()
|
!query.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
|
/// A [`Condition`]-satisfying system that returns `true`
|
||||||
/// if there are any entity with a component of the given type removed.
|
/// if there are any entity with a component of the given type removed.
|
||||||
pub fn any_component_removed<T: Component>(mut removals: RemovedComponents<T>) -> bool {
|
pub fn any_component_removed<T: Component>(mut removals: RemovedComponents<T>) -> bool {
|
||||||
// `RemovedComponents` based on events and therefore events need to be consumed,
|
// `RemovedComponents` based on events and therefore events need to be consumed,
|
||||||
@ -1033,7 +1033,7 @@ pub mod common_conditions {
|
|||||||
removals.read().count() > 0
|
removals.read().count() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a [`Condition`](super::Condition) that inverses the result of passed one.
|
/// Generates a [`Condition`] that inverses the result of passed one.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
@ -1071,6 +1071,109 @@ pub mod common_conditions {
|
|||||||
let name = format!("!{}", condition.name());
|
let name = format!("!{}", condition.name());
|
||||||
NotSystem::new(super::NotMarker, condition, name.into())
|
NotSystem::new(super::NotMarker, condition, name.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a [`Condition`] that returns true when the passed one changes.
|
||||||
|
///
|
||||||
|
/// The first time this is called, the passed condition is assumed to have been previously false.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// # #[derive(Resource, Default)]
|
||||||
|
/// # struct Counter(u8);
|
||||||
|
/// # let mut app = Schedule::default();
|
||||||
|
/// # let mut world = World::new();
|
||||||
|
/// # world.init_resource::<Counter>();
|
||||||
|
/// app.add_systems(
|
||||||
|
/// my_system.run_if(condition_changed(resource_exists::<MyResource>)),
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// #[derive(Resource)]
|
||||||
|
/// struct MyResource;
|
||||||
|
///
|
||||||
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
||||||
|
/// counter.0 += 1;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // `MyResource` is initially there, the inner condition is true, the system runs once
|
||||||
|
/// world.insert_resource(MyResource);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
///
|
||||||
|
/// // We remove `MyResource`, the inner condition is now false, the system runs one more time.
|
||||||
|
/// world.remove_resource::<MyResource>();
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
/// ```
|
||||||
|
pub fn condition_changed<Marker, CIn, C: Condition<Marker, CIn>>(
|
||||||
|
condition: C,
|
||||||
|
) -> impl Condition<(), CIn> {
|
||||||
|
condition.pipe(|In(new): In<bool>, mut prev: Local<bool>| -> bool {
|
||||||
|
let changed = *prev != new;
|
||||||
|
*prev = new;
|
||||||
|
changed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a [`Condition`] that returns true when the result of
|
||||||
|
/// the passed one went from false to true since the last time this was called.
|
||||||
|
///
|
||||||
|
/// The first time this is called, the passed condition is assumed to have been previously false.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// # #[derive(Resource, Default)]
|
||||||
|
/// # struct Counter(u8);
|
||||||
|
/// # let mut app = Schedule::default();
|
||||||
|
/// # let mut world = World::new();
|
||||||
|
/// # world.init_resource::<Counter>();
|
||||||
|
/// app.add_systems(
|
||||||
|
/// my_system.run_if(condition_changed_to(true, resource_exists::<MyResource>)),
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// #[derive(Resource)]
|
||||||
|
/// struct MyResource;
|
||||||
|
///
|
||||||
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
||||||
|
/// counter.0 += 1;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // `MyResource` is initially there, the inner condition is true, the system runs once
|
||||||
|
/// world.insert_resource(MyResource);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
///
|
||||||
|
/// // We remove `MyResource`, the inner condition is now false, the system doesn't run.
|
||||||
|
/// world.remove_resource::<MyResource>();
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
///
|
||||||
|
/// // We reinsert `MyResource` again, so the system will run one more time
|
||||||
|
/// world.insert_resource(MyResource);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
/// app.run(&mut world);
|
||||||
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
/// ```
|
||||||
|
pub fn condition_changed_to<Marker, CIn, C: Condition<Marker, CIn>>(
|
||||||
|
to: bool,
|
||||||
|
condition: C,
|
||||||
|
) -> impl Condition<(), CIn> {
|
||||||
|
condition.pipe(move |In(new): In<bool>, mut prev: Local<bool>| -> bool {
|
||||||
|
let now_true = *prev != new && new == to;
|
||||||
|
*prev = new;
|
||||||
|
now_true
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes [`Not`] with the output of another system.
|
/// Invokes [`Not`] with the output of another system.
|
||||||
|
Loading…
Reference in New Issue
Block a user