#animation #bevy-plugin #sprite #bevy

bevy_spritesheet_animation

一个用于动画精灵的Bevy插件

4个版本

0.2.0 2024年7月6日
0.1.0 2024年4月10日
0.1.0-beta.12024年4月8日
0.1.0-beta.02024年4月7日

#395 in 游戏开发

Download history 14/week @ 2024-05-20 11/week @ 2024-06-03 8/week @ 2024-06-10 30/week @ 2024-06-24 180/week @ 2024-07-01 35/week @ 2024-07-08 16/week @ 2024-07-15 50/week @ 2024-07-22 28/week @ 2024-07-29 20/week @ 2024-08-05

117每月下载量

MIT授权

145KB
1.5K SLoC

Crates.io Docs Build License

bevy_spritesheet_animation是一个用于动画精灵的Bevy插件,这些精灵由精灵图集支持。

An animated character walking from the left to the right and shooting their gun

功能

  • 一个用于添加到实体以播放动画的Bevy组件component
  • 可调节参数:duration(持续时间),repetitions(重复次数),direction(方向),easing(缓动)。
  • 由多个剪辑组成的可组合动画。
  • 用于响应动画结束或到达特定点的事件
  • 用于在精灵图集中选择帧的方便的API

快速开始

  1. SpritesheetAnimationPlugin添加到您的应用程序
  2. 使用SpritesheetLibrary资源来创建新的剪辑和动画
  3. SpritesheetAnimation组件添加到您的实体
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        // Add the plugin to enable animations.
        // This makes the SpritesheetLibrary resource available to your systems.
        .add_plugins(SpritesheetAnimationPlugin)
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    mut library: ResMut<SpritesheetLibrary>,
    mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
    assets: Res<AssetServer>,
) {
    // Create an animation

    let clip_id = library.new_clip(|clip| {
        // You can configure this clip here (duration, number of repetitions, etc...)

        // This clip will use all the frames in row 3 of the spritesheet
        clip.push_frame_indices(Spritesheet::new(8, 8).row(3));
    });

    let animation_id = library.new_animation(|animation| {
        // You can configure this animation here (duration, number of repetitions, etc...)

        animation.add_stage(clip_id.into());

        // This is a simple animation with a single clip but we can create more sophisticated
        // animations with multiple clips, each one having different parameters.
        //
        // See the `composition` example for more details.
    });

    // Spawn a sprite using Bevy's built-in SpriteSheetBundle

    let texture = assets.load("character.png");

    let layout = atlas_layouts.add(TextureAtlasLayout::from_grid(
        UVec2::new(96, 96),
        8,
        8,
        None,
        None,
    ));

    commands.spawn((
        SpriteSheetBundle {
            texture,
            atlas: TextureAtlas {
                layout,
                ..default()
            },
            ..default()
        },
        // Add a SpritesheetAnimation component that references our newly created animation
        SpritesheetAnimation::from_id(animation_id),
    ));

    commands.spawn(Camera2dBundle::default());
}

概述

动画剪辑

动画剪辑是一系列可重复使用的帧。

它是创建动画的最基本构建块。

使用SpritesheetLibrary资源来创建和配置一个新的剪辑。

然后可以在任何数量的动画中引用此剪辑。

fn setup(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {

    // Create a clip that uses some frames from a spritesheet

    let clip_id = library.new_clip(|clip| {
        clip
            .push_frame_indices(Spritesheet::new(8, 8).column(2))
            .set_default_duration(AnimationDuration::PerCycle(1500))
            .set_default_repeat(5);
    });

    // Add this clip to an animation

    let animation_id = library.new_animation(|animation| {
        animation.add_stage(clip_id.into());
    });

    // ... Assign the animation to an entity with the SpritesheetAnimation component ...
}

动画

在其最简单形式中,动画由一个无限循环的单个剪辑组成。

然而,您可以通过链接多个剪辑并调整动画参数来创建更复杂的动画。

使用 SpritesheetLibrary 资源创建一个新的动画。

然后,您可以在任意数量的 SpritesheetAnimation 组件中引用此动画。

fn setup(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {

    // ...

    let animation_id = library.new_animation(|animation| {
        let mut stage1 = AnimationStage::from_clip(some_clip_id);
        stage1
            .set_repeat(5)
            .set_easing(Easing::InOut(EasingVariety::Quadratic));

        let mut stage2 = AnimationStage::from_clip(another_clip_id);
        stage2
            .set_duration(AnimationDuration::PerFrame(120))
            .set_direction(Animation::Direction::Backwards);

        animation
            .add_stage(stage1)
            .add_stage(stage2)
            .set_duration(AnimationDuration::PerCycle(1000))
            .set_direction(Animation::Direction::PingPong);
    });

    // ... Assign the animation to an entity with the SpritesheetAnimation component ...
}

将剪辑和动画视为资产!

剪辑和动画应该只创建一次。然后,您可以将其分配给许多实体。

❌ 错误

您不应该为每个播放的实体创建相同的剪辑/动画。

fn spawn_enemies(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {

    // Creating identical animations gives more work to the plugin and degrades performance!

    for _ in 0..100 {
        let clip_id = library.new_clip(|clip| { /* ... */ });

        let animation_id = library.new_animation(|animation| { /* ... */ });

        commands.spawn((
            SpriteSheetBundle { /* .... */ },
            SpritesheetAnimation::from_id(animation_id),
        ));
    }
}

👍 正确

相反,一次性创建剪辑/动画,然后在需要时引用它们。

例如,您可以在设置系统中创建所有动画,给它们唯一的名称,然后在稍后的阶段将它们分配给实体。

fn create_animation(mut library: ResMut<SpritesheetLibrary>) {

    let clip_id = library.new_clip(|clip| { /* ... */ });

    let animation_id = library.new_animation(|animation| { /* ... */ });

    // Here, we name the animation to make it easy to retrieve it in other systems.
    //
    // Alternatively, you may prefer to store the animation ID yourself.
    // For instance, in a Bevy Resource that contains the IDs of all your clips/animations.
    // Something like:
    //
    // #[derive(Resource)]
    // struct GameAnimations {
    //     enemy_running: Option<AnimationId>,
    //     enemy_firing: Option<AnimationId>,
    //     ... and so on ...
    // }

    library.name_animation(animation_id, "enemy running");
}

fn spawn_enemies(mut commands: Commands, library: Res<SpritesheetLibrary>) {

    // Retrieve our animation and assign it to many entities

    if let Some(animation_id) = libray.animation_with_name("enemy running") {
        for _ in 0..100 {
            commands.spawn((
                SpriteSheetBundle { /* .... */ },
                SpritesheetAnimation::from_id(animation_id),
            ));
        }
    }
}

更多示例

有关更多示例,请浏览 examples/ 目录。

示例 描述
基本 最小示例,展示如何创建一个动画精灵
组合 高级示例,展示如何创建具有多个阶段的动画
参数 显示每个参数的效果
角色 展示如何创建具有多个动画的可控角色
事件 展示如何使用事件对动画到达感兴趣点做出反应
压力测试 数千个动画精灵的压力测试

兼容性

bevy bevy_spritesheet_animation
0.14 0.2.0
0.13 0.1.0

鸣谢

依赖项

~35–72MB
~1.5M SLoC