diff --git a/crates/bevy_animation/Cargo.toml b/crates/bevy_animation/Cargo.toml index 6fb9fb9f59..a1d019ad1a 100644 --- a/crates/bevy_animation/Cargo.toml +++ b/crates/bevy_animation/Cargo.toml @@ -10,7 +10,6 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_animation_derive = { path = "derive", version = "0.15.0-dev" } bevy_app = { path = "../bevy_app", version = "0.15.0-dev" } bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" } bevy_color = { path = "../bevy_color", version = "0.15.0-dev" } diff --git a/crates/bevy_animation/derive/Cargo.toml b/crates/bevy_animation/derive/Cargo.toml deleted file mode 100644 index ad44a82b00..0000000000 --- a/crates/bevy_animation/derive/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "bevy_animation_derive" -version = "0.15.0-dev" -edition = "2021" -description = "Derive implementations for bevy_animation" -homepage = "https://bevyengine.org" -repository = "https://github.com/bevyengine/bevy" -license = "MIT OR Apache-2.0" -keywords = ["bevy"] - -[lib] -proc-macro = true - -[dependencies] -bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.15.0-dev" } -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "2.0", features = ["full"] } - -[lints] -workspace = true - -[package.metadata.docs.rs] -rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"] -all-features = true diff --git a/crates/bevy_animation/derive/src/lib.rs b/crates/bevy_animation/derive/src/lib.rs deleted file mode 100644 index 48bce1163e..0000000000 --- a/crates/bevy_animation/derive/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Derive macros for `bevy_animation`. - -extern crate proc_macro; - -use bevy_macro_utils::BevyManifest; -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput}; - -/// Used to derive `AnimationEvent` for a type. -#[proc_macro_derive(AnimationEvent)] -pub fn derive_animation_event(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - let name = ast.ident; - let manifest = BevyManifest::default(); - let bevy_animation_path = manifest.get_path("bevy_animation"); - let bevy_ecs_path = manifest.get_path("bevy_ecs"); - let animation_event_path = quote! { #bevy_animation_path::animation_event }; - let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - // TODO: This could derive Event as well. - quote! { - impl #impl_generics #animation_event_path::AnimationEvent for #name #ty_generics #where_clause { - fn trigger(&self, _time: f32, _weight: f32, entity: #bevy_ecs_path::entity::Entity, world: &mut #bevy_ecs_path::world::World) { - world.entity_mut(entity).trigger(Clone::clone(self)); - } - } - } - .into() -} diff --git a/crates/bevy_animation/src/animation_event.rs b/crates/bevy_animation/src/animation_event.rs deleted file mode 100644 index a2cf2da785..0000000000 --- a/crates/bevy_animation/src/animation_event.rs +++ /dev/null @@ -1,281 +0,0 @@ -//! Traits and types for triggering events from animations. - -use core::{any::Any, fmt::Debug}; - -use bevy_ecs::prelude::*; -use bevy_reflect::{ - prelude::*, utility::NonGenericTypeInfoCell, ApplyError, DynamicTupleStruct, FromType, - GetTypeRegistration, ReflectFromPtr, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, - TupleStructFieldIter, TupleStructInfo, TypeInfo, TypeRegistration, Typed, UnnamedField, -}; - -pub use bevy_animation_derive::AnimationEvent; - -pub(crate) fn trigger_animation_event( - entity: Entity, - time: f32, - weight: f32, - event: Box, -) -> impl Command { - move |world: &mut World| { - event.trigger(time, weight, entity, world); - } -} - -/// An event that can be used with animations. -/// It can be derived to trigger as an observer event, -/// if you need more complex behavior, consider -/// a manual implementation. -/// -/// # Example -/// -/// ```rust -/// # use bevy_animation::prelude::*; -/// # use bevy_ecs::prelude::*; -/// # use bevy_reflect::prelude::*; -/// # use bevy_asset::prelude::*; -/// # -/// #[derive(Event, AnimationEvent, Reflect, Clone)] -/// struct Say(String); -/// -/// fn on_say(trigger: Trigger) { -/// println!("{}", trigger.event().0); -/// } -/// -/// fn setup_animation( -/// mut commands: Commands, -/// mut animations: ResMut>, -/// mut graphs: ResMut>, -/// ) { -/// // Create a new animation and add an event at 1.0s. -/// let mut animation = AnimationClip::default(); -/// animation.add_event(1.0, Say("Hello".into())); -/// -/// // Create an animation graph. -/// let (graph, animation_index) = AnimationGraph::from_clip(animations.add(animation)); -/// -/// // Start playing the animation. -/// let mut player = AnimationPlayer::default(); -/// player.play(animation_index).repeat(); -/// -/// commands.spawn((AnimationGraphHandle(graphs.add(graph)), player)); -/// } -/// # -/// # bevy_ecs::system::assert_is_system(setup_animation); -/// ``` -#[reflect_trait] -pub trait AnimationEvent: CloneableAnimationEvent + Reflect + Send + Sync { - /// Trigger the event, targeting `entity`. - fn trigger(&self, time: f32, weight: f32, entity: Entity, world: &mut World); -} - -/// This trait exist so that manual implementors of [`AnimationEvent`] -/// do not have to implement `clone_value`. -#[diagnostic::on_unimplemented( - message = "`{Self}` does not implement `Clone`", - note = "consider annotating `{Self}` with `#[derive(Clone)]`" -)] -pub trait CloneableAnimationEvent { - /// Clone this value into a new `Box` - fn clone_value(&self) -> Box; -} - -impl CloneableAnimationEvent for T { - fn clone_value(&self) -> Box { - Box::new(self.clone()) - } -} - -/// The data that will be used to trigger an animation event. -#[derive(TypePath)] -pub(crate) struct AnimationEventData(pub(crate) Box); - -impl AnimationEventData { - pub(crate) fn new(event: impl AnimationEvent) -> Self { - Self(Box::new(event)) - } -} - -impl Debug for AnimationEventData { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str("AnimationEventData(")?; - PartialReflect::debug(self.0.as_ref(), f)?; - f.write_str(")")?; - Ok(()) - } -} - -impl Clone for AnimationEventData { - fn clone(&self) -> Self { - Self(CloneableAnimationEvent::clone_value(self.0.as_ref())) - } -} - -// We have to implement `GetTypeRegistration` manually because of the embedded -// `Box`, which can't be automatically derived yet. -impl GetTypeRegistration for AnimationEventData { - fn get_type_registration() -> TypeRegistration { - let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration - } -} - -// We have to implement `Typed` manually because of the embedded -// `Box`, which can't be automatically derived yet. -impl Typed for AnimationEventData { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| { - TypeInfo::TupleStruct(TupleStructInfo::new::(&[UnnamedField::new::<()>(0)])) - }) - } -} - -// We have to implement `TupleStruct` manually because of the embedded -// `Box`, which can't be automatically derived yet. -impl TupleStruct for AnimationEventData { - fn field(&self, index: usize) -> Option<&dyn PartialReflect> { - match index { - 0 => Some(self.0.as_partial_reflect()), - _ => None, - } - } - - fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> { - match index { - 0 => Some(self.0.as_partial_reflect_mut()), - _ => None, - } - } - - fn field_len(&self) -> usize { - 1 - } - - fn iter_fields(&self) -> TupleStructFieldIter { - TupleStructFieldIter::new(self) - } - - fn clone_dynamic(&self) -> DynamicTupleStruct { - DynamicTupleStruct::from_iter([PartialReflect::clone_value(&*self.0)]) - } -} - -// We have to implement `PartialReflect` manually because of the embedded -// `Box`, which can't be automatically derived yet. -impl PartialReflect for AnimationEventData { - #[inline] - fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { - Some(::type_info()) - } - - #[inline] - fn into_partial_reflect(self: Box) -> Box { - self - } - - #[inline] - fn as_partial_reflect(&self) -> &dyn PartialReflect { - self - } - - #[inline] - fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { - self - } - - fn try_into_reflect(self: Box) -> Result, Box> { - Ok(self) - } - - #[inline] - fn try_as_reflect(&self) -> Option<&dyn Reflect> { - Some(self) - } - - #[inline] - fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { - Some(self) - } - - fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { - if let ReflectRef::TupleStruct(struct_value) = value.reflect_ref() { - for (i, value) in struct_value.iter_fields().enumerate() { - if let Some(v) = self.field_mut(i) { - v.try_apply(value)?; - } - } - } else { - return Err(ApplyError::MismatchedKinds { - from_kind: value.reflect_kind(), - to_kind: ReflectKind::TupleStruct, - }); - } - Ok(()) - } - - fn reflect_ref(&self) -> ReflectRef { - ReflectRef::TupleStruct(self) - } - - fn reflect_mut(&mut self) -> ReflectMut { - ReflectMut::TupleStruct(self) - } - - fn reflect_owned(self: Box) -> ReflectOwned { - ReflectOwned::TupleStruct(self) - } - - fn clone_value(&self) -> Box { - Box::new(Clone::clone(self)) - } -} - -// We have to implement `Reflect` manually because of the embedded -// `Box`, which can't be automatically derived yet. -impl Reflect for AnimationEventData { - #[inline] - fn into_any(self: Box) -> Box { - self - } - - #[inline] - fn as_any(&self) -> &dyn Any { - self - } - - #[inline] - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - - #[inline] - fn into_reflect(self: Box) -> Box { - self - } - - #[inline] - fn as_reflect(&self) -> &dyn Reflect { - self - } - - #[inline] - fn as_reflect_mut(&mut self) -> &mut dyn Reflect { - self - } - - #[inline] - fn set(&mut self, value: Box) -> Result<(), Box> { - *self = value.take()?; - Ok(()) - } -} - -// We have to implement `FromReflect` manually because of the embedded -// `Box`, which can't be automatically derived yet. -impl FromReflect for AnimationEventData { - fn from_reflect(reflect: &dyn PartialReflect) -> Option { - Some(reflect.try_downcast_ref::()?.clone()) - } -} diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index 8d55cb7ea5..56c623ff86 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -11,13 +11,11 @@ extern crate alloc; pub mod animatable; pub mod animation_curves; -pub mod animation_event; pub mod gltf_curves; pub mod graph; pub mod transition; mod util; -use animation_event::{trigger_animation_event, AnimationEvent, AnimationEventData}; use core::{ any::{Any, TypeId}, cell::RefCell, @@ -30,7 +28,7 @@ use prelude::AnimationCurveEvaluator; use crate::graph::{AnimationGraphHandle, ThreadedAnimationGraphs}; -use bevy_app::{App, Plugin, PostUpdate}; +use bevy_app::{Animation, App, Plugin, PostUpdate}; use bevy_asset::{Asset, AssetApp, Assets}; use bevy_core::Name; use bevy_ecs::{ @@ -64,12 +62,8 @@ use uuid::Uuid; pub mod prelude { #[doc(hidden)] pub use crate::{ - animatable::*, - animation_curves::*, - animation_event::{AnimationEvent, ReflectAnimationEvent}, - graph::*, - transition::*, - AnimationClip, AnimationPlayer, AnimationPlugin, VariableCurve, + animatable::*, animation_curves::*, graph::*, transition::*, AnimationClip, + AnimationPlayer, AnimationPlugin, VariableCurve, }; } @@ -78,6 +72,7 @@ use crate::{ graph::{AnimationGraph, AnimationGraphAssetLoader, AnimationNodeIndex}, transition::{advance_transitions, expire_completed_transitions, AnimationTransitions}, }; +use alloc::sync::Arc; /// The [UUID namespace] of animation targets (e.g. bones). /// @@ -289,7 +284,34 @@ pub struct AnimationClip { #[derive(Reflect, Debug, Clone)] struct TimedAnimationEvent { time: f32, - event: AnimationEventData, + event: AnimationEvent, +} + +#[derive(Reflect, Debug, Clone)] +struct AnimationEvent { + #[reflect(ignore)] + trigger: AnimationEventFn, +} + +impl AnimationEvent { + fn trigger(&self, commands: &mut Commands, entity: Entity, time: f32, weight: f32) { + (self.trigger.0)(commands, entity, time, weight); + } +} + +#[derive(Reflect, Clone)] +struct AnimationEventFn(Arc); + +impl Default for AnimationEventFn { + fn default() -> Self { + Self(Arc::new(|_commands, _entity, _time, _weight| {})) + } +} + +impl Debug for AnimationEventFn { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("AnimationEventFn").finish() + } } #[derive(Reflect, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] @@ -472,9 +494,24 @@ impl AnimationClip { .push(variable_curve); } - /// Add an [`AnimationEvent`] to an [`AnimationTarget`] named by an [`AnimationTargetId`]. + /// Add a untargeted [`Event`] to this [`AnimationClip`]. /// - /// The `event` will trigger on the entity matching the target once the `time` (in seconds) + /// The `event` will be cloned and triggered on the [`AnimationPlayer`] entity once the `time` (in seconds) + /// is reached in the animation. + /// + /// See also [`add_event_to_target`](Self::add_event_to_target). + pub fn add_event(&mut self, time: f32, event: impl Event + Clone) { + self.add_event_fn( + time, + move |commands: &mut Commands, entity: Entity, _time: f32, _weight: f32| { + commands.entity(entity).trigger(event.clone()); + }, + ); + } + + /// Add an [`Event`] to an [`AnimationTarget`] named by an [`AnimationTargetId`]. + /// + /// The `event` will be cloned and triggered on the entity matching the target once the `time` (in seconds) /// is reached in the animation. /// /// Use [`add_event`](Self::add_event) instead if you don't have a specific target. @@ -482,26 +519,69 @@ impl AnimationClip { &mut self, target_id: AnimationTargetId, time: f32, - event: impl AnimationEvent, + event: impl Event + Clone, ) { - self.add_event_to_target_inner(AnimationEventTarget::Node(target_id), time, event); + self.add_event_fn_to_target( + target_id, + time, + move |commands: &mut Commands, entity: Entity, _time: f32, _weight: f32| { + commands.entity(entity).trigger(event.clone()); + }, + ); } - /// Add a untargeted [`AnimationEvent`] to this [`AnimationClip`]. + /// Add a untargeted event function to this [`AnimationClip`]. /// - /// The `event` will trigger on the [`AnimationPlayer`] entity once the `time` (in seconds) + /// The `func` will trigger on the [`AnimationPlayer`] entity once the `time` (in seconds) /// is reached in the animation. /// + /// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event`]. /// See also [`add_event_to_target`](Self::add_event_to_target). - pub fn add_event(&mut self, time: f32, event: impl AnimationEvent) { - self.add_event_to_target_inner(AnimationEventTarget::Root, time, event); + /// + /// ``` + /// # use bevy_animation::AnimationClip; + /// # let mut clip = AnimationClip::default(); + /// clip.add_event_fn(1.0, |commands, entity, time, weight| { + /// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}"); + /// }) + /// ``` + pub fn add_event_fn( + &mut self, + time: f32, + func: impl Fn(&mut Commands, Entity, f32, f32) + Send + Sync + 'static, + ) { + self.add_event_internal(AnimationEventTarget::Root, time, func); } - fn add_event_to_target_inner( + /// Add an event function to an [`AnimationTarget`] named by an [`AnimationTargetId`]. + /// + /// The `func` will trigger on the entity matching the target once the `time` (in seconds) + /// is reached in the animation. + /// + /// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event_to_target`]. + /// Use [`add_event`](Self::add_event) instead if you don't have a specific target. + /// + /// ``` + /// # use bevy_animation::{AnimationClip, AnimationTargetId}; + /// # let mut clip = AnimationClip::default(); + /// clip.add_event_fn_to_target(AnimationTargetId::from_iter(["Arm", "Hand"]), 1.0, |commands, entity, time, weight| { + /// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}"); + /// }) + /// ``` + pub fn add_event_fn_to_target( + &mut self, + target_id: AnimationTargetId, + time: f32, + func: impl Fn(&mut Commands, Entity, f32, f32) + Send + Sync + 'static, + ) { + self.add_event_internal(AnimationEventTarget::Node(target_id), time, func); + } + + fn add_event_internal( &mut self, target: AnimationEventTarget, time: f32, - event: impl AnimationEvent, + trigger_fn: impl Fn(&mut Commands, Entity, f32, f32) + Send + Sync + 'static, ) { self.duration = self.duration.max(time); let triggers = self.events.entry(target).or_default(); @@ -510,7 +590,9 @@ impl AnimationClip { index, TimedAnimationEvent { time, - event: AnimationEventData::new(event), + event: AnimationEvent { + trigger: AnimationEventFn(Arc::new(trigger_fn)), + }, }, ), } @@ -988,12 +1070,7 @@ fn trigger_untargeted_animation_events( }; for TimedAnimationEvent { time, event } in triggered_events.iter() { - commands.queue(trigger_animation_event( - entity, - *time, - active_animation.weight, - event.clone().0, - )); + event.trigger(&mut commands, entity, *time, active_animation.weight); } } } @@ -1195,12 +1272,12 @@ pub fn animate_targets( for TimedAnimationEvent { time, event } in triggered_events.iter() { - commands.queue(trigger_animation_event( + event.trigger( + &mut commands, entity, *time, active_animation.weight, - event.clone().0, - )); + ); } }); } @@ -1252,10 +1329,6 @@ pub fn animate_targets( }); } -/// Animation system set -#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] -pub struct Animation; - /// Adds animation support to an app #[derive(Default)] pub struct AnimationPlugin; @@ -1573,12 +1646,6 @@ mod tests { #[derive(Event, Reflect, Clone)] struct A; - impl AnimationEvent for A { - fn trigger(&self, _time: f32, _weight: f32, target: Entity, world: &mut World) { - world.entity_mut(target).trigger(self.clone()); - } - } - #[track_caller] fn assert_triggered_events_with( active_animation: &ActiveAnimation, diff --git a/crates/bevy_app/src/main_schedule.rs b/crates/bevy_app/src/main_schedule.rs index f2b5494437..834205cf53 100644 --- a/crates/bevy_app/src/main_schedule.rs +++ b/crates/bevy_app/src/main_schedule.rs @@ -181,6 +181,10 @@ pub struct PostUpdate; #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] pub struct Last; +/// Animation system set. This exists in [`PostUpdate`]. +#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] +pub struct Animation; + /// Defines the schedules to be run for the [`Main`] schedule, including /// their order. #[derive(Resource, Debug)] diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index 6b85675c94..cd5fba2ca4 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -71,7 +71,7 @@ pub mod prelude { }; } -use bevy_app::prelude::*; +use bevy_app::{prelude::*, Animation}; use bevy_asset::AssetApp; #[cfg(feature = "default_font")] use bevy_asset::{load_internal_binary_asset, Handle}; @@ -138,7 +138,8 @@ impl Plugin for TextPlugin { calculate_bounds_text2d.in_set(VisibilitySystems::CalculateBounds), ) .chain() - .in_set(Update2dText), + .in_set(Update2dText) + .after(Animation), ) .add_systems(Last, trim_cosmic_cache); diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index d3f456d63f..aaaf7cfbcc 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -25,7 +25,6 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [ "bevy", ] } bevy_render = { path = "../bevy_render", version = "0.15.0-dev" } -bevy_animation = { path = "../bevy_animation", version = "0.15.0-dev" } bevy_sprite = { path = "../bevy_sprite", version = "0.15.0-dev" } bevy_text = { path = "../bevy_text", version = "0.15.0-dev" } bevy_picking = { path = "../bevy_picking", version = "0.15.0-dev", optional = true } diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 9b8945f7b9..8f14b1365f 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -66,7 +66,7 @@ pub mod prelude { }; } -use bevy_app::prelude::*; +use bevy_app::{prelude::*, Animation}; use bevy_ecs::prelude::*; use bevy_input::InputSystem; use bevy_render::{ @@ -171,9 +171,7 @@ impl Plugin for UiPlugin { PostUpdate, ( CameraUpdateSystem, - UiSystem::Prepare - .before(UiSystem::Stack) - .after(bevy_animation::Animation), + UiSystem::Prepare.before(UiSystem::Stack).after(Animation), UiSystem::Layout, UiSystem::PostLayout, ) diff --git a/examples/animation/animated_fox.rs b/examples/animation/animated_fox.rs index db17bbecc0..c4b59d5fb5 100644 --- a/examples/animation/animated_fox.rs +++ b/examples/animation/animated_fox.rs @@ -34,8 +34,7 @@ struct Animations { graph: Handle, } -#[derive(Event, AnimationEvent, Reflect, Clone)] -#[reflect(AnimationEvent)] +#[derive(Event, Reflect, Clone)] struct OnStep; fn observe_on_step( diff --git a/examples/animation/animation_events.rs b/examples/animation/animation_events.rs index 60f1d8a7db..177fa2f47f 100644 --- a/examples/animation/animation_events.rs +++ b/examples/animation/animation_events.rs @@ -11,39 +11,27 @@ fn main() { .add_plugins(DefaultPlugins) .add_event::() .add_systems(Startup, setup) - .add_systems(PreUpdate, (animate_text_opacity, edit_message)) + .add_systems(Update, animate_text_opacity) + .add_observer(edit_message) .run(); } #[derive(Component)] struct MessageText; -#[derive(Event, Reflect, Clone)] -#[reflect(AnimationEvent)] +#[derive(Event, Clone)] struct MessageEvent { value: String, color: Color, } -// AnimationEvent can also be derived, but doing so will -// trigger it as an observer event which is triggered in PostUpdate. -// We need to set the message text before that so it is -// updated before rendering without a one frame delay. -impl AnimationEvent for MessageEvent { - fn trigger(&self, _time: f32, _weight: f32, _entity: Entity, world: &mut World) { - world.send_event(self.clone()); - } -} - fn edit_message( - mut event_reader: EventReader, + trigger: Trigger, text: Single<(&mut Text2d, &mut TextColor), With>, ) { let (mut text, mut color) = text.into_inner(); - for event in event_reader.read() { - text.0 = event.value.clone(); - color.0 = event.color; - } + text.0 = trigger.event().value.clone(); + color.0 = trigger.event().color; } fn setup( diff --git a/tools/publish.sh b/tools/publish.sh index 20eb0c13c4..6576430791 100644 --- a/tools/publish.sh +++ b/tools/publish.sh @@ -34,7 +34,6 @@ crates=( bevy_core_pipeline bevy_input bevy_gilrs - bevy_animation/derive bevy_animation bevy_pbr bevy_gltf