Bevy Aseprite Ultra

repository·master·Indexed 41 days ago

https://github.com/lommix/bevy_aseprite_ultra

A high-performance Bevy plugin for loading spritesheets and animations directly from .aseprite binary files. Version 0.9.0 supports complex animations, tags, static slices, and hot reloading. It provides components like AseAnimation and AseSlice for use with Sprite and ImageNode render targets, and includes an optional asset processor for optimized formats.

Tokens
6.4K
Snippets
19
Records
28
Agent score
51%

What's inside Bevy Aseprite Ultra

  1. Overview of Bevy Aseprite Ultra

    master
    Bevy Aseprite Ultra is a plugin for the Bevy game engine that allows importing .aseprite files with full support for animations, tags, frame durations, layer visibility, and blend modes. It features robust hot reloading (requires Bevy's file_watcher feature) and supports importing static sprites from Aseprite atlas files using slices with functional pivot offsets. You can use Aseprite for all your icon and UI needs by leveraging its slice feature.
  2. Enable Asset Processing

    master

    To use the asset processor which converts .aseprite files into a custom optimized format, you must configure the AssetPlugin in your Bevy App and run with the asset_processing feature enabled.

    1. Configure AssetPlugin:
    App::new()
        .add_plugins(DefaultPlugins.set(AssetPlugin {
            mode: AssetMode::Processed,
            ..Default::default(),
        }))
        .run();
    1. Run with the feature:
    cargo run --features asset_processing
  3. Use Aseprite animations and slices in Bevy UI

    master

    To use Aseprite assets in Bevy UI, combine AseAnimation or AseSlice with an ImageNode component (which acts as the render target).

    Example: Animation in UI

    cmd.spawn((
            Button,
            ImageNode::default(),
            AseAnimation {
                aseprite: server.load("player.aseprite"),
                animation: Animation::tag("walk-right"),
            },
    ));

    Example: Slice in UI

    cmd.spawn((
            Node {
                width: Val::Px(100.),
                height: Val::Px(100.),
                border: UiRect::all(Val::Px(5.)),
                ..default()
            },
            ImageNode::default(),
            AseSlice {
                name: "ghost_red".into(),
                aseprite: server.load("ghost_slices.aseprite"),
            },
    ));
  4. Understand Aseprite TagMeta and AnimationDirection

    master

    Animation tags in Aseprite are mapped to TagMeta. This allows you to identify specific animation sequences (e.g., "Idle", "Run") and their properties.

    TagMeta Fields

    • direction: The AnimationDirection of the tag.
    • range: An inclusive range (std::ops::RangeInclusive<u16>) of frames covered by the tag.
    • repeat: The number of times the animation repeats.

    AnimationDirection

    Supported directions are:

    • Forward
    • Reverse
    • PingPong
    • PingPongReverse
    • Unknown(u8)
  5. Understand AnimationState and PlayDirection

    master

    The AnimationState component tracks the real-time progress of an animation. It is automatically managed by the plugin unless ManualTick is present.

    • current_frame: The absolute index of the frame in the Aseprite file.
    • relative_frame: The frame index relative to the start of the current animation tag.
    • current_direction: Tracks if the animation is currently playing Forward or Backward (used for PingPong modes).
  6. Enable Aseprite asset processing with AsepriteProcessorPlugin

    master

    To enable automatic processing of Aseprite files (converting them into optimized formats for runtime), add the AsepriteProcessorPlugin to your Bevy App.

    This plugin registers default asset processors for the .aseprite and .ase file extensions. It uses a pipeline that transforms the raw Aseprite data into a serialized MessagePack format combined with a QOI-encoded texture atlas, ensuring efficient loading during runtime.

    use bevy::prelude::*;
    use bevy_aseprite_ultra::AsepriteProcessorPlugin;
    
    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)
            .add_plugins(AsepriteProcessorPlugin)
            .run();
    }
  7. Use AseSlice to display Aseprite atlas slices

    master

    The AseSlice component is used to display a specific slice from an Aseprite atlas. To use it, attach the AseSlice component to a render target (such as a Sprite or ImageNode) and provide the name of the slice and a handle to the Aseprite asset.

    To enable slice rendering, you must add the AsepriteSlicePlugin to your Bevy app. This plugin automatically handles updating the render target's texture and atlas information whenever the AseSlice component or the underlying Aseprite asset changes. It also automatically updates the Anchor component if one is present on the entity, using the pivot information defined in the Aseprite slice.

    ```rust
    // Add the plugin to your app
    app.add_plugins(AsepriteSlicePlugin);
    
    // Spawn an entity with a Sprite and an AseSlice
    commands.spawn(( 
        SpriteBundle::default(),
        AseSlice {
            name: "my_slice_name".to_string(),
            aseprite: aseprite_handle,
        },
    ));
    ```埋
  8. Install and initialize the AsepriteLoaderPlugin

    master

    To use Aseprite files in Bevy, add the AsepriteLoaderPlugin to your app. This plugin initializes the Aseprite asset type and registers the AsepriteLoader to handle .aseprite and .ase file extensions.

    use bevy_aseprite_ultra::AsepriteLoaderPlugin;
    
    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)
            .add_plugins(AsepriteLoaderPlugin)
            .run();
    }
    app.add_plugins(AsepriteLoaderPlugin);
  9. Setup the AsepriteAnimationPlugin

    master

    To enable Aseprite animation support in your Bevy application, add the AsepriteAnimationPlugin to your app. This plugin handles animation ticking, event triggering (like AnimationEvents::Finished), and automatic rendering for Sprite and ImageNode components.

    app.add_plugins(AsepriteAnimationPlugin);
  10. Install and setup AsepriteUltraPlugin

    master

    To use bevy_aseprite_ultra, add the AsepriteUltraPlugin to your Bevy App. It is highly recommended to configure the ImagePlugin with a nearest sampler to preserve pixel art clarity.

    fn main() {
        App::new()
            .add_plugins(DefaultPlugins.set(ImagePlugin {
                default_sampler: bevy::render::texture::ImageSamplerDescriptor::nearest(),
            }))
            .add_plugins(AsepriteUltraPlugin)
            .add_systems(Startup, setup)
            .run();
    }
  11. Run project examples

    master

    The repository includes several examples to demonstrate different features. You can run them using cargo run --example <name>:

    • slices: Demonstrates static slices.
    • animations: Demonstrates animation playback.
    • ui: Demonstrates usage in Bevy UI.
    • asset_processing: Demonstrates the asset processor (requires --features asset_processing).
    • 3d: Demonstrates usage in 3D environments (requires --features 3d).
    cargo run --example slices
    cargo run --example animations
    cargo run --example ui
    cargo run --example asset_processing --features asset_processing
    cargo run --example 3d --features 3d
  12. Handle animation events and one-shot animations

    master

    The plugin emits AnimationEvents that you can listen to in a system. This is particularly useful for triggering logic when a one-shot animation (like an explosion) finishes.

    Supported events:

    • AnimationEvents::Finished(entity): Emitted when an animation reaches its end.
    • AnimationEvents::LoopCycleFinished(entity): Emitted when an animation completes a loop cycle.
    // animation events
    fn despawn_on_finish(mut events: EventReader<AnimationEvents>, mut cmd : Commands){
        for event in events.read() {
            match event {
                AnimationEvents::Finished(entity) => cmd.entity(*entity).despawn_recursive(),
                AnimationEvents::LoopCycleFinished(_entity) => (),
            };
        }
    }