1 unstable release
Uses new Rust 2024
new 0.1.0 | May 4, 2025 |
---|
#1 in #simultaneously
38KB
920 lines
WeirdBoi Tween
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
:
[dependencies]
weirdboi_tween = "0.1.0"
Basic Usage
- Setup
- Tweening Components
- Creating Tweenables
- Tween Modes
- Tween User Events
- Built in Events
Setup
Add the tweening plugin to your Bevy app:
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.
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.
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 stopsLoop
: 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.
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:
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:
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 positionTweenTransformScale
- Tweens a Transform's scaleTweenSpriteColor
- Tweens a Sprite's colorTweenImageNodeColour
- Tweens a Sprite's colorTweenTextColour
- Tweens a Sprite's color
Dependencies
~17–53MB
~1M SLoC