#animation #bevy #easing #tweening #game-engine

bevy_tweening_captured

Bevy游戏引擎的缓动动画插件

1个不稳定版本

0.10.0 2024年5月5日

#628 in 游戏开发


用于 2 个crate(通过 lottie-renderer-bevy

MIT/Apache

1MB
3K SLoC

🍃 Bevy Tweening Captured

License: MIT/Apache Doc Crate Build Status Coverage Status Bevy tracking

Bevy游戏引擎的缓动动画插件。这是原始项目的分支,允许捕获自定义缓动函数

功能

  • 可以动画化任何组件或资产的任何字段,包括自定义字段。
  • 每个组件/资产可以并行运行多个缓动(动画)。
  • 链式多个缓动(动画)以实现复杂的动画。
  • 当缓动完成时,可以触发Bevy事件或调用回调。

用法

依赖项

添加到 Cargo.toml

[dependencies]
bevy_tweening = "0.10"

此crate支持以下功能

功能 默认 描述
bevy_asset 启用动画化Bevy资产(Asset),除了组件。
bevy_sprite 包含一些与 Sprite 相关组件的内置透镜。
bevy_ui 包含一些与UI相关组件的内置透镜。
bevy_text 包含一些与 Text 相关组件的内置透镜。

系统设置

TweeningPlugin 添加到您的应用

App::default()
    .add_plugins(DefaultPlugins)
    .add_plugins(TweeningPlugin)
    .run();

这为使用🍃 Bevy Tweening提供了基本设置。然而,根据您想要动画化的组件和资产,可能需要额外的设置

  • 为了确保组件 C 被动画化,必须每帧运行 component_animator_system::<C> 系统以及将 Animator::<C> 组件添加到与 C 相同的实体中。

  • 为确保资产 A 动画,必须运行 asset_animator_system::<A> 系统,并在任何实体上添加一个 AssetAnimator<A> 组件。动画资产还需要 bevy_asset 功能(默认启用)。

默认情况下,🍃 Bevy Tweening 采用最小化方法,TweeningPlugin 将仅添加系统以动画化由 🍃 Bevy Tweening 本身提供的 Lens 的组件和资产。这意味着任何其他 Bevy 组件或资产(无论是 Bevy 本身构建的内置组件还是自定义组件)都需要手动安排适当的系统。

组件或资产 TweeningPlugin 添加的动画系统?
Transform
Sprite 仅当启用 bevy_sprite 功能时
ColorMaterial 仅当启用 bevy_sprite 功能时
Style 仅当启用 bevy_ui 功能时
Text 仅当启用 bevy_text 功能时
所有其他组件

要为组件 C 添加系统,请使用

app.add_systems(Update, component_animator_system::<C>.in_set(AnimationSystem::AnimationUpdate));

类似地,为资产 A 使用

app.add_systems(Update, asset_animator_system::<A>.in_set(AnimationSystem::AnimationUpdate));

动画组件

通过为变换创建一个 Tween 动画来动画实体的变换位置,并添加一个带有该缓动的 Animator 组件

// Create a single animation (tween) to move an entity.
let tween = Tween::new(
    // Use a quadratic easing on both endpoints.
    EaseFunction::QuadraticInOut,
    // Animation time (one way only; for ping-pong it takes 2 seconds
    // to come back to start).
    Duration::from_secs(1),
    // The lens gives the Animator access to the Transform component,
    // to animate it. It also contains the start and end values associated
    // with the animation ratios 0. and 1.
    TransformPositionLens {
        start: Vec3::ZERO,
        end: Vec3::new(1., 2., -4.),
    },
)
// Repeat twice (one per way)
.with_repeat_count(RepeatCount::Finite(2))
// After each iteration, reverse direction (ping-pong)
.with_repeat_strategy(RepeatStrategy::MirroredRepeat);

commands.spawn((
    // Spawn a Sprite entity to animate the position of.
    SpriteBundle {
        sprite: Sprite {
            color: Color::RED,
            custom_size: Some(Vec2::new(size, size)),
            ..default()
        },
        ..default()
    },
    // Add an Animator component to control and execute the animation.
    Animator::new(tween),
));

动画链式调用

Bevy Tweening 支持多种类型的 tweenables,这些是构建块,可以组合成复杂的动画。tweenable 是实现 Tweenable<T> 特性的类型。

  • Tween - 两个值之间简单的缓动(缓动)动画。
  • Sequence - 一系列按顺序执行的单个 tweenable。
  • Tracks - 并行执行的 tweenable 集合。
  • Delay - 时间延迟。

大多数 tweenable 可以通过 then() 操作符进行链式调用

// Produce a sequence executing 'tween1' then 'tween2'
let tween1 = Tween { [...] }
let tween2 = Tween { [...] }
let seq = tween1.then(tween2);

预定义的镜头

一些预定义的镜头可用于最常见的用例,这些镜头也作为示例。强烈建议用户编写自己的镜头,以适应其特定的动画用例。

预定义镜头的命名方案为 "<TargetName><FieldName>Lens",其中 <TargetName> 是目标 Bevy 组件或资产类型的名称,该类型由内部动画系统查询以进行修改,而 <FieldName> 是通过镜头就地更改的字段。所有预定义镜头都修改单个字段。可以编写自定义镜头,以一次修改多个字段。

Bevy 组件

目标组件 动画字段 镜头 功能
Transform translation TransformPositionLens
rotation (Quat TransformRotationLens
rotation (angle)² TransformRotateXLens
rotation (angle)² TransformRotateYLens
rotation (angle)² TransformRotateZLens
rotation (angle)² TransformRotateAxisLens
scale TransformScaleLens
Sprite color SpriteColorLens bevy_sprite
Style position UiPositionLens bevy_ui
BackgroundColor UiBackgroundColorLens bevy_ui
Text TextStyle::color TextColorLens bevy_text

¹ 使用 Quat::slerp() 在两个旋转之间进行最短路径插值。

² 基于角度的插值,适用于超过半圈的旋转。

有关旋转透镜的详细比较,请参阅 旋转透镜比较

Bevy 资产

资产动画始终需要 bevy_asset 功能。

目标资产 动画字段 镜头 功能
ColorMaterial color ColorMaterialColorLens bevy_asset + bevy_sprite

自定义透镜

自定义透镜允许动画化 Bevy 组件或资产的任何字段或字段组。自定义透镜是实现了 Lens 特征的类型,该特征对组件或资产类型是泛型的。

struct MyXAxisLens {
    start: f32,
    end: f32,
}

impl Lens<Transform> for MyXAxisLens {
    fn lerp(&mut self, target: &mut Transform, ratio: f32) {
        let start = Vec3::new(self.start, 0., 0.);
        let end = Vec3::new(self.end, 0., 0.);
        target.translation = start + (end - start) * ratio;
    }
}

请注意,透镜始终以 线性 方式插值组件或资产的字段。应用缓动函数的类型会修改 ratio 参数演化的速率,并在调用 lerp() 函数之前应用。

lerp(线性插值)的基本公式可以是以下两种之一

  • 起始值+ (结束值-起始值) *标量
  • 起始值* (1.0 -标量) +结束值*标量

这两种公式在数学上是等价的,但根据插值的类型、可用的操作以及潜在的浮点精度错误,其中一种可能比另一种更适合。

自定义组件支持

自定义组件通过类似在 Bevy 组件 中描述的透镜进行动画化。

#[derive(Component)]
struct MyCustomComponent(f32);

struct MyCustomLens {
    start: f32,
    end: f32,
}

impl Lens<MyCustomComponent> for MyCustomLens {
    fn lerp(&mut self, target: &mut MyCustomComponent, ratio: f32) {
        target.0 = self.start + (self.end - self.start) * ratio;
    }
}

然后,此外,还需要将系统 component_animator_system::<CustomComponent> 添加到应用程序中,如 系统设置 中所述。此系统将提取每个帧所有具有相同实体的 CustomComponent 实例及其 Animator<CustomComponent>,并通过其动画器对组件进行动画化。

自定义资产支持

该过程与自定义组件类似,为自定义资产创建自定义透镜。需要添加的系统是 asset_animator_system::<CustomAsset>,如 系统设置 中所述。这需要 bevy_asset 功能(默认启用)。

示例

请参阅 examples/ 文件夹。

菜单

cargo run --example menu --features="bevy/bevy_winit"

menu

sprite_color

cargo run --example sprite_color --features="bevy/bevy_winit"

sprite_color

transform_rotation

cargo run --example transform_rotation --features="bevy/bevy_winit"

sprite_color

transform_translation

cargo run --example transform_translation --features="bevy/bevy_winit"

sprite_color

colormaterial_color

cargo run --example colormaterial_color --features="bevy/bevy_winit"

colormaterial_color

ui_position

cargo run --example ui_position --features="bevy/bevy_winit"

ui_position

sequence

cargo run --example sequence --features="bevy/bevy_winit"

sequence

缓动函数

提供了许多 缓动函数

  • 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 版本

main 分支与最新的 Bevy 版本兼容。

bevy_tweening 版本的兼容性

bevy_tweening bevy
0.10 0.13
0.9 0.12
0.8 0.11
0.7 0.10
0.6 0.9
0.5 0.8
0.4 0.7
0.2-0.3 0.6
0.1 0.5

由于Bevy快速发展的特性以及频繁的破坏性更改,以及维护🍃 Bevy Tweening的有限资源,主(未发布)Bevy分支不支持。然而,在每次新的bevy发布后不久,bevy_tweening库就会升级以支持新发布的版本。

bevy_easings的比较

bevy_tweening库最初是基于François Mocker的bevy_easings的一个分支,目标是

  • 探索一种基于透镜而不是泛型类型为每个缓动器/动画器设计的替代方案。这减少了所需泛型类型的数量,并可能减少代码大小以及执行插值所需的系统数量。
  • 改进资产插值以避免创建许多副本,如bevy_easings所做的那样,而是原地修改资产(以及相似地,组件)而不进行复制。原地修改还允许更优化的插值,仅修改感兴趣的字段,而不是在每一帧创建组件的新副本。

依赖关系

~19–58MB
~1M SLoC