# WeirdBoi Tween [](https://crates.io/crates/weirdboi_tween) [](LICENSE) A component value tweening library for Bevy. Tweens become first class entities, working via the new relationships system. ## Features - Relationship-based tweening system - Tween any value of any component - Apply multiple tweens of the same type simultaneously - Support for tween iteration (Once, Loop, PingPong) - User data events for looping & completion ## Installation Add the following to your `Cargo.toml`: ```toml [dependencies] weirdboi_tween = "0.1.0" ``` ## Basic Usage 1. Setup 2. Tweening Components 3. Creating Tweenables 4. Tween Modes 5. Tween User Events 6. Built in Events ### Setup Add the tweening plugin to your Bevy app: ```rust use bevy::prelude::*; use weirdboi_tween::TweenPlugin; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(TweenPlugin) // Other plugins and systems .run(); } ``` ### Tweening Component Properties Since tweens are relationship based entities, they can take advantage of all of the relationship machinery to work with them. This means using the `Tweens` collection to spawn related entities for a target entity, or by creating a Tween independently and inserting a `TweenTarget` component. ```rust fn spawn_animated_sprite(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(( Sprite::from_image(asset_server.load("sprite.png")), Tweens::spawn(&[( TweenSpriteColour::tween( Duration::from_millis(250), Color::WHITE.into(), Color::BLACK.into(), EaseTween::Linear, ), TweenTransformTranslation::tween( Duration::from_millis(250), Vec3::splat(0.0), Vec3::new(20.0, 50.0, 0.0), EaseTween::Linear, ), )]) )); } ``` ### Creating custom Tweenables The tween system requires the implementation of `Tweenable` meta types, so named because they exist at the type level. A `Tweenable` is associated with one component type, and one data type. The data type represents some facet of the component that can have an easing applied to it - this also means the data type does not need to match the type of the component property being tweened. Once you have a type implementing `Tweenable`, you need to register it with the application in order to set up the required systems. ```rust struct TileOffset(Vec2); struct TweenTileOffset; impl Tweenable for TweenTileOffset { type Comp = TileOffset; type Data = Vec2; fn current_value(cmp: &Self::Comp) -> Self::Data { cmp.0 } fn update_component(cmp: &mut Self::Comp, value: Self::Data) { cmp.0 = value; } } // .. Then register in a plugin fn TileTweenPlugin(app: &mut App) { app.register_tweenable::<TweenTileOffset>(); } // .. Then you can spawn the tween fn tween_player_offset(mut commands: Commands, marked_entity: Single<Entity, With<Player>>) { commands.spawn(( TweenTarget(*marked_entity), TweenTileOffset::tween( Duration::from_millis(200), Vec2::splat(0.0), Vec2::new(50., 50.), TweenEasing::Linear, ), )) } ``` ### Tween Modes By default a tween will run once, complete, and then despawn. This behaviour can be controlled by including a `TweenMode` component alongside a tween. `TweenMode` has three variants: - `Once`: Default behaviour, tween runs from start to end and stops - `Loop`: The tween runs from start to end, and then resets to continue running from start to end indefinitely. E.g. `1, 2, 3, loop, 1, 2, 3, loop, 1, 2, 3` - `PingPong`: The tween runs from start to end, and the flips values to run from end to start indefinitely. E.g. `1, 2, 3, loop, 3, 2, 1, loop, 1, 2, 3` ### Tween Events Any tween can have an arbitrary `u32` value associated with it, which will cause an event to be fired in one of two situations, depending on the mode. When attaching user data to a one shot tween (`TweenMode::Once`, the default), a `TweenComplete` event is fired once the tween completes. This can either be responded to with another system taking an `EventReader<TweenComplete>` parameter, or by directly attaching an observer to the _target_ entity that takes a `Trigger<TweenComplete>` When attaching user data to a looping tween (`TweenMode::PingPong` or `TweenMode::Loop`), a `TweenLooped` event is fired each time the tween iterates. Much like the `TweenComplete` event, either an `EventReader<TweenLooped>` system or `Trigger<TweenLooped>` observer can be used to respond to this action. ```rust fn handle_tween_complete(mut events: EventReader<TweenComplete>) { for event in events.read() { println!("Tween completed for entity: {:?}", event.entity); if event.user_data == MY_CUSTOM_EVENT_ID { // Handle specific tween completion } } } ``` ### Automatic Despawn There are two utility events built in for the common case of animating throwaway entities. While the tween entity will always despawn when complete, using the `DESPAWN_ON_TWEEN_COMPLETE_EVENT` user data will also cause the tween's target to despawn when the tween completes: ```rust fn spawn_a_tweenable(mut commands: Commands) { commands.spawn(( Transform::default(), Sprite::default(), TweenSpriteColour::tween( Duration::from_millis(200), Color::WHITE.into(), Color::WHITE.with_alpha(0.0).into(), TweenEasing::Linear ) .with_user_data(DESPAWN_ON_TWEEN_COMPLETE_EVENT) .spawn() )); } ``` While less common, it can also be useful to despawn an entire hierarchy (above and below) when the tween completes (e.g. fading out a UI element that is not a UI root due to styling constraints). This can be achieved with the `DESPAWN_ANCESTORS_ON_TWEEN_COMPLETE_EVENT` user data: ```rust fn spawn_a_tweenable_leaf(mut commands: Commands) { commands.spawn(( Node { // Some styling ..default() }, children![( Text::new("My label"), TextColor::from(Color::WHITE), TweenTextColour::tween( Duration::from_millis(200), Color::WHITE.into(), Color::WHITE.with_alpha(0.0).into(), TweenEasing::Linear ) .with_user_data(DESPAWN_ANCESTORS_ON_TWEEN_COMPLETE_EVENT) .spawn() )] )); } ``` ## Available Easing Functions WeirdBoi Tween provides a variety of easing functions, forked from `bevy_math`, made available under the `TweenEasing` enum: - Linear - QuadraticIn, QuadraticOut, QuadraticInOut - CubicIn, CubicOut, CubicInOut - QuarticIn, QuarticOut, QuarticInOut - QuinticIn, QuinticOut, QuinticInOut - SineIn, SineOut, SineInOut - CircularIn, CircularOut, CircularInOut - ExponentialIn, ExponentialOut, ExponentialInOut - ElasticIn, ElasticOut, ElasticInOut - BackIn, BackOut, BackInOut - BounceIn, BounceOut, BounceInOut ## Built-in Tweenable Types By enabling the `bevy_defaults` feature, you get access to the - `TweenTransformTranslation` - Tweens a Transform's position - `TweenTransformScale` - Tweens a Transform's scale - `TweenSpriteColor` - Tweens a Sprite's color - `TweenImageNodeColour` - Tweens a Sprite's color - `TweenTextColour` - Tweens a Sprite's color