bevy_easings 0.19.0

Easing plugin for Bevy
Documentation
# Bevy Easings

![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)
[![Doc](https://docs.rs/bevy_easings/badge.svg)](https://docs.rs/bevy_easings)
[![Crate](https://img.shields.io/crates/v/bevy_easings.svg)](https://crates.io/crates/bevy_easings)
[![Bevy Tracking](https://img.shields.io/badge/Bevy%20tracking-main-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking)
[![CI](https://github.com/vleue/bevy_easings/actions/workflows/ci.yml/badge.svg)](https://github.com/vleue/bevy_easings/actions/workflows/ci.yml)

Easings on Bevy components using [interpolation](https://crates.io/crates/interpolation).

![menu example](https://raw.githubusercontent.com/vleue/bevy_easings/main/examples/menu.webp)

## Usage

### System setup

Add the plugin to your app:

```rust
use bevy::prelude::*;
use bevy_easings::EasingsPlugin;

fn main() {
    App::new()
        .add_plugins(EasingsPlugin::default());
}
```

### Easing a component to a new value

And then just ease your components to their new state!

```rust
use bevy::prelude::*;
use bevy_easings::Ease;

fn my_system(mut commands: Commands){
    commands
        .spawn((
            Sprite {
                ..Default::default()
            },
            Sprite {
                custom_size: Some(Vec2::new(10., 10.)),
                ..Default::default()
            }
            .ease_to(
                Sprite {
                    custom_size: Some(Vec2::new(100., 100.)),
                    ..Default::default()
                },
                bevy_easings::EaseFunction::QuadraticIn,
                bevy_easings::EasingType::PingPong {
                    duration: std::time::Duration::from_secs(1),
                    pause: Some(std::time::Duration::from_millis(500)),
                },
            ),
        ));
}
```

If the component being eased is not already a component of the entity, the component should first be inserted for the target entity.

### Easing to a function-generated target

You can also ease to a target that is generated dynamically from the previous value using a function:

```rust
use bevy::prelude::*;
use bevy_easings::Ease;

fn my_system(mut commands: Commands){
    commands
        .spawn((
            Transform::from_scale(Vec3::new(0.1, 0.1, 1.0))
            .ease_to_fn(
                |start| Transform {
                    scale: start.scale * 10.0,
                    ..*start
                },
                bevy_easings::EaseFunction::QuadraticIn,
                bevy_easings::EasingType::PingPong {
                    duration: std::time::Duration::from_secs(1),
                    pause: Some(std::time::Duration::from_millis(500)),
                },
            )
            .ease_to_fn(
                |prev| Transform {
                    scale: prev.scale * 0.5,
                    ..*prev
                },
                bevy_easings::EaseFunction::CubicInOut,
                bevy_easings::EasingType::Once {
                    duration: std::time::Duration::from_secs(2),
                },
            ).with_original_value(),
        ));
}
```

This is particularly useful to rescue you from repeatly writing initialize code for start status, or chaining animation without worrying about maintaining interior status.

### Easing using EaseMethod

The EaseMethod enum can be used to provide easing methods that are not avaliable in EaseFunction.

```rust,ignore
pub enum EaseMethod {
    /// Follow `EaseFunction`
    EaseFunction(EaseFunction),
    /// Linear interpolation, with no function
    Linear,
    /// Discrete interpolation, eased value will jump from start to end
    Discrete,
    /// Use a custom function to interpolate the value
    CustomFunction(fn(f32) -> f32),
}
```

This is shown below

```rust
use bevy::prelude::*;
use bevy_easings::Ease;

fn my_system(mut commands: Commands){
    commands
        .spawn((
            Sprite {
                ..Default::default()
            },
            Sprite {
                custom_size: Some(Vec2::new(10., 10.)),
                ..Default::default()
            }
            .ease_to(
                Sprite {
                    custom_size: Some(Vec2::new(100., 100.)),
                    ..Default::default()
                },
                bevy_easings::EaseMethod::Linear,
                bevy_easings::EasingType::PingPong {
                    duration: std::time::Duration::from_secs(1),
                    pause: Some(std::time::Duration::from_millis(500)),
                },
            ),
        ));
}
```

### Chaining easing

You can chain easings, if they are not set to repeat they will happen in sequence.

```rust
use bevy::prelude::*;
use bevy_easings::Ease;

fn my_system(mut commands: Commands){
    commands
        .spawn((
            Sprite {
                ..Default::default()
            },
            Sprite {
                custom_size: Some(Vec2::new(10., 10.)),
                ..Default::default()
            }
            .ease_to(
                Sprite {
                    custom_size: Some(Vec2::new(300., 300.)),
                    ..Default::default()
                },
                bevy_easings::EaseFunction::QuadraticIn,
                bevy_easings::EasingType::Once {
                    duration: std::time::Duration::from_secs(1),
                },
            )
            .ease_to(
                Sprite {
                    custom_size: Some(Vec2::new(350., 350.)),
                    ..Default::default()
                },
                bevy_easings::EaseFunction::QuadraticIn,
                bevy_easings::EasingType::PingPong {
                    duration: std::time::Duration::from_millis(500),
                    pause: Some(std::time::Duration::from_millis(200)),
                },
            ),
        ));
}
```

## Custom component support

To be able to ease a component, it needs to implement the traits `Default` and [`Lerp`](https://docs.rs/interpolation/0.2.0/interpolation/trait.Lerp.html). This trait is re-exported by `beavy_easings`.

```rust
use bevy::prelude::*;
use bevy_easings::*;

#[derive(Default, Component)]
struct CustomComponent(f32);
impl Lerp for CustomComponent {
    type Scalar = f32;

    fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self {
        CustomComponent(interpolation::lerp(&self.0, &other.0, scalar))
    }
}
```

The basic formula for lerp (linear interpolation) is `self + (other - self) * scalar`.

Then, the system `custom_ease_system::<CustomComponent>` needs to be added to the application.

## Examples

See [examples](https://github.com/vleue/bevy_easings/tree/main/examples)

### Choosing the ease function

![easing on size](https://raw.githubusercontent.com/vleue/bevy_easings/main/examples/lerping-sizes.webp)

![easing on color](https://raw.githubusercontent.com/vleue/bevy_easings/main/examples/lerping-color.webp)

When easing colors, pay attention on the color space you are using

![color spaces](https://raw.githubusercontent.com/vleue/bevy_easings/main/examples/lerping-color-spaces.webp)

## Ease Functions

Many [ease functions](https://docs.rs/interpolation/0.2.0/interpolation/enum.EaseFunction.html) are available:

- 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

## Bevy supported version

| Bevy | bevy_easings |
| ---- | ------------ |
| main | main         |
| 0.19 | 0.19         |
| 0.18 | 0.18         |
| 0.17 | 0.17         |
| 0.16 | 0.16         |
| 0.15 | 0.15         |
| 0.14 | 0.14         |
| 0.13 | 0.14         |
| 0.12 | 0.12         |
| 0.11 | 0.11         |
| 0.10 | 0.10         |
| 0.9  | 0.9          |
| 0.8  | 0.8          |
| 0.7  | 0.7          |
| 0.6  | 0.6          |
| 0.5  | 0.4          |