bevy_animation/animation_event.rs
1pub use bevy_animation_macros::AnimationEvent;
2
3use bevy_ecs::{
4 entity::Entity,
5 event::{trigger_entity_internal, Event, Trigger},
6 observer::{CachedObservers, TriggerContext},
7 world::DeferredWorld,
8};
9
10/// An [`Event`] that an [`AnimationPlayer`](crate::AnimationPlayer) or an [`AnimationTargetId`](crate::AnimationTargetId) can trigger when playing an [`AnimationClip`](crate::AnimationClip).
11///
12/// - If you used [`AnimationClip::add_event`](crate::AnimationClip::add_event), this will be triggered by the [`AnimationPlayer`](crate::AnimationPlayer).
13/// - If you used [`AnimationClip::add_event_to_target`](crate::AnimationClip::add_event_to_target), this will be triggered by the [`AnimationTargetId`](crate::AnimationTargetId).
14///
15/// This trait can be derived.
16pub trait AnimationEvent: Clone + for<'a> Event<Trigger<'a> = AnimationEventTrigger> {}
17
18/// The [`Trigger`] implementation for [`AnimationEvent`]. This passes in either the [`AnimationPlayer`](crate::AnimationPlayer) or the [`AnimationTargetId`](crate::AnimationTargetId)
19/// context, and uses that to run any observers that target that entity. See [`AnimationEvent`] for when which entity is used.
20#[derive(Debug)]
21pub struct AnimationEventTrigger {
22 /// The [`AnimationPlayer`](crate::AnimationPlayer) or the [`AnimationTargetId`](crate::AnimationTargetId) where this [`AnimationEvent`] occurred.
23 /// See [`AnimationEvent`] for when which entity is used.
24 pub target: Entity,
25}
26
27#[expect(
28 unsafe_code,
29 reason = "We must implement this trait to define a custom Trigger, which is required to be unsafe due to safety considerations within bevy_ecs."
30)]
31// SAFETY:
32// - `E`'s [`Event::Trigger`] is constrained to [`AnimationEventTrigger`]
33// - The implementation abides by the other safety constraints defined in [`Trigger`]
34unsafe impl<E: AnimationEvent + for<'a> Event<Trigger<'a> = AnimationEventTrigger>> Trigger<E>
35 for AnimationEventTrigger
36{
37 unsafe fn trigger(
38 &mut self,
39 world: DeferredWorld,
40 observers: &CachedObservers,
41 trigger_context: &TriggerContext,
42 event: &mut E,
43 ) {
44 let target = self.target;
45 // SAFETY:
46 // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
47 // - the passed in event pointer comes from `event`, which is an `Event`
48 // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
49 // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
50 // - this abides by the nuances defined in the `Trigger` safety docs
51 unsafe {
52 trigger_entity_internal(
53 world,
54 observers,
55 event.into(),
56 self.into(),
57 target,
58 trigger_context,
59 );
60 }
61 }
62}