bevy/crates/bevy_animation/derive/src/lib.rs
poopy d9190e4ff6
Add Support for Triggering Events via AnimationEvents (#15538)
# Objective

Add support for events that can be triggered from animation clips. This
is useful when you need something to happen at a specific time in an
animation. For example, playing a sound every time a characters feet
hits the ground when walking.

Closes #15494 

## Solution

Added a new field to `AnimationClip`: `events`, which contains a list of
`AnimationEvent`s. These are automatically triggered in
`animate_targets` and `trigger_untargeted_animation_events`.

## Testing

Added a couple of tests and example (`animation_events.rs`) to make sure
events are triggered when expected.

---

## Showcase

`Events` need to also implement `AnimationEvent` and `Reflect` to be
used with animations.

```rust
#[derive(Event, AnimationEvent, Reflect)]
struct SomeEvent;
```

Events can be added to an `AnimationClip` by specifying a time and
event.

```rust
// trigger an event after 1.0 second
animation_clip.add_event(1.0, SomeEvent);
```

And optionally, providing a target id.

```rust
let id = AnimationTargetId::from_iter(["shoulder", "arm", "hand"]);
animation_clip.add_event_to_target(id, 1.0, HandEvent);
```

I modified the `animated_fox` example to show off the feature.

![CleanShot 2024-10-05 at 02 41
57](https://github.com/user-attachments/assets/0bb47db7-24f9-4504-88f1-40e375b89b1b)

---------

Co-authored-by: Matty <weatherleymatthew@gmail.com>
Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-10-06 10:03:05 +00:00

30 lines
1.1 KiB
Rust

//! 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()
}