Skip to content

merwaaan/bevy_spritesheet_animation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Crates.io Docs Build License

bevy_spritesheet_animation is a Bevy plugin for easily animating 2D and 3D sprites.

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

Tip

This crate supports the latest Bevy 0.17. Please check the compatibility table to see which versions of this crate work with older Bevy versions.

Note

This crate is under active development. Please regularly check the CHANGELOG for recent changes.

Features

Quick start

  1. Add the SpritesheetAnimationPlugin to your app
  2. Build animations with the Spritesheet API
  3. Add SpritesheetAnimation components to your entities
use bevy::prelude::*;
use bevy_spritesheet_animation::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
        // Add the plugin to enable animations
        //
        // This configures the app to play animations for entities with a SpritesheetAnimation component.
        // This also makes the Assets<Animation> resource available to your systems.
        .add_plugins(SpritesheetAnimationPlugin)
        .add_systems(Startup, create_animated_sprite)
        .run();
}

fn create_animated_sprite(
    mut commands: Commands,
    assets: Res<AssetServer>,
    mut animations: ResMut<Assets<Animation>>,
    mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
) {
    commands.spawn(Camera2d);

    // Create an animation from a row of an 8x8 spritesheet
    //
    // This is a simple animation made of 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.

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

    let spritesheet = Spritesheet::new(&image, 8, 8);

    let animation = spritesheet
        .create_animation()
        .add_row(3)
        .set_duration(AnimationDuration::PerFrame(100))
        .build();

    // Register the animation as an asset

    let animation_handle = animations.add(animation);

    // Create a regular Bevy sprite
    //
    // Here we use the spritesheet to automatically generate the animation-ready Bevy sprite.
    // This is optional and you may prefer to build the sprite manually.

    let sprite = spritesheet
        .with_size_hint(768, 768)
        .sprite(&mut atlas_layouts);

    // Spawn the sprite with a SpritesheetAnimation component that references our animation

    commands.spawn((
        // This is a regular Bevy sprite
        sprite,
        // This is the component that animates the sprite
        SpritesheetAnimation::new(animation_handle),
    ));
}

Overview

Animations

In its simplest form, an Animation is a sequence of cells extracted from a spritesheet image.

Use a Spritesheet to create an Animation.

For each animation, you can control its duration, repetitions, direction and easing.

// Here, we extract two animations from an 8x8 spritesheet image

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

let spritesheet = Spritesheet::new(&image, 8, 8)

// Let's create a looping animation from the first row

let run_animation = spritesheet
    .create_animation()
    .add_row(0)
    .set_duration(AnimationDuration::PerRepetition(1500))
    .set_repetitions(AnimationRepeat::Loop)
    .build();

// Let's create another animation from another row, with different playback parameters

let shoot_animation = spritesheet
    .create_animation()
    .add_row(3)
    .set_duration(AnimationDuration::PerFrame(120))
    .set_easing(Easing::In(EasingVariety::Quadratic))
    .build();

Clips

To create more sophisticated animations, you can leverage a lower-level construct: clips.

Think of clips as sub-animations that are chained together and have their own parameters (duration, repetitions, etc...).

let animation = Spritesheet::new(&image, 8, 8)
    .create_animation()

    // An animation starts with an implicit clip that you can edit right away
    //
    // Parameters set with set_clip_xxx() only apply to the current clip
    .add_row(2)
    .set_clip_duration(AnimationDuration::PerRepetition(2500))

    // Call start_clip() to add another clip
    //
    // Here the second clip uses the same frames but will play faster and repeat a few times
    .start_clip()
    .add_row(4)
    .set_clip_duration(AnimationDuration::PerRepetition(1000))
    .set_clip_repetitions(5)

    // Parameters set with set_xxx() apply to the whole animation
    .set_direction(AnimationDirection::PingPong)

    .build();

Animations are assets

Just like Bevy's images, materials or meshes, this crate's animations are assets.

After creating an animation, register it in Assets<Animation>.

This will give you a Handle<Animation> that you can assign to SpritesheetAnimation components.

fn create_animated_sprite(
    mut commands: Commands,
    mut animations: ResMut<Assets<Animation>>,
) {
    // ... omitted: create an animation

    let animation_handle = animations.add(animation);

    commands.spawn((
        // ... omitted: your entity's other components

        SpritesheetAnimation::new(animation_handle),
    ));
}

Warning

An animation should be created only once and then assigned to as many sprites as you need. Creating identical animations gives more work to the plugin and may degrade performance!

Interaction with Bevy's built-in components

To animate an entity, you just have to give it:

  • a regular Sprite component (provided by Bevy)
  • a SpritesheetAnimation component (provided by this crate)

This crate provides a few helpers to make the creation of such entities more concise.

In the simplest case, you can use Spritesheet::sprite() to get an animation-ready sprite with the correct image and texture atlas:

commands.spawn((
    spritesheet.sprite(&mut atlas_layouts),
    SpritesheetAnimation::new(animation_handle),
));

If you need more control, for instance to set some sprite attributes like its color, you might prefer to construct the sprite yourself.

In that case, you can spell out the entity creation and use Spritesheet::atlas() to retrieve the texture atlas that matches your spritesheet.

commands.spawn((
    Sprite {
        image: your_image,
        texture_atlas: spritesheet.atlas(&mut atlas_layouts),
        color: LinearRGBA::RED,
        ..default()
    },
    SpritesheetAnimation::new(animation_handle),
));

3D sprites

A dozen of 3D sprites moving in 3D space

This crate also makes it easy to integrate 3D sprites into your games, which is not supported by Bevy out of the box.

Animating a 3D sprite is the same as animating 2D sprites: simply spawn a Sprite3d instead of Bevy's built-in Sprite and attach a SpritesheetAnimation component to the entity.

Like for 2D sprites, Spritesheet provides a helper that creates an animation-ready 3D sprite:

let sprite3d = spritesheet
    .with_size_hint(600, 400)
    .sprite3d(&mut atlas_layouts)
    .with_color(LinearRgba::RED)
    .with_flip(false, true);

commands.spawn((
    sprite3d,
    SpritesheetAnimation::new(animation_handle),
));

UI images

This crate also animates UI images with the same workflow.

Please check out the complete example.

fn create_animated_ui_image(
    mut commands: Commands,
    assets: Res<AssetServer>,
    images: Res<Assets<Image>>,
    mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>
) {
    // ... omitted: create a spritesheet and an animation

    let image_node = spritesheet
        .with_loaded_image(&images)
        .expect("the image is not loaded")
        .image_node(&mut atlas_layouts);

    commands.spawn((
        image_node,
        SpritesheetAnimation::new(animation),
    ));
}

Cursors

This crate also animates cursors with the same workflow.

Please check out the complete example.

fn create_animated_cursor(
    window: Single<Entity, With<Window>>,
    mut commands: Commands,
    assets: Res<AssetServer>,
    images: Res<Assets<Image>>,
    mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>
) {
    // ... omitted: create a spritesheet and an animation

    let cursor_icon = spritesheet
        .with_loaded_image(&images)
        .expect("the image is not loaded")
        .cursor_icon(&mut atlas_layouts);

    commands.entity(*window).insert((
        cursor_icon,
        SpritesheetAnimation::new(animation),
    ));
}

More examples

For more examples, browse the examples/ directory.

Example Description
basic Shows how to create a simple animated sprite
composition Shows how to create an animation with multiple clips
progress Shows how to query/control the progress of an animation
parameters Shows the effect of each animation parameter
character Shows how to create a controllable character with multiple animations
events Shows how to handle animation events
3d Shows how to create 3D sprites
cursor Shows how to create an animated cursor
ui Shows how to create an animated UI image
headless Shows how to run animations in a headless Bevy app without rendering
stress Stress test with thousands of animated sprites (either 2D or 3D)

Compatibility

bevy bevy_spritesheet_animation
0.17 4.0.0
0.16 3.0.0
0.15 2.0.0
0.14 0.2.0
0.13 0.1.0

Credits

About

A Bevy plugin for easily animating 2D and 3D sprites

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 7

Languages