mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
95c0d99e45
# Objective - Make running animation fluid skipping 'idle' frame. ## Solution - Loop through the specified indices instead of through the whole sprite sheet. The example is correct, is just the feeling that the animation loop is not seamless. Based on the solution suggested by @mockersf in #5429.
65 lines
2 KiB
Rust
65 lines
2 KiB
Rust
//! Renders an animated sprite by loading all animation frames from a single image (a sprite sheet)
|
|
//! into a texture atlas, and changing the displayed image periodically.
|
|
|
|
use bevy::prelude::*;
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) // prevents blurry sprites
|
|
.add_startup_system(setup)
|
|
.add_system(animate_sprite)
|
|
.run();
|
|
}
|
|
|
|
#[derive(Component)]
|
|
struct AnimationIndices {
|
|
first: usize,
|
|
last: usize,
|
|
}
|
|
|
|
#[derive(Component, Deref, DerefMut)]
|
|
struct AnimationTimer(Timer);
|
|
|
|
fn animate_sprite(
|
|
time: Res<Time>,
|
|
mut query: Query<(
|
|
&AnimationIndices,
|
|
&mut AnimationTimer,
|
|
&mut TextureAtlasSprite,
|
|
)>,
|
|
) {
|
|
for (indices, mut timer, mut sprite) in &mut query {
|
|
timer.tick(time.delta());
|
|
if timer.just_finished() {
|
|
sprite.index = if sprite.index == indices.last {
|
|
indices.first
|
|
} else {
|
|
sprite.index + 1
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
|
) {
|
|
let texture_handle = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
|
|
let texture_atlas =
|
|
TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1, None, None);
|
|
let texture_atlas_handle = texture_atlases.add(texture_atlas);
|
|
// Use only the subset of sprites in the sheet that make up the run animation
|
|
let animation_indices = AnimationIndices { first: 1, last: 6 };
|
|
commands.spawn(Camera2dBundle::default());
|
|
commands.spawn((
|
|
SpriteSheetBundle {
|
|
texture_atlas: texture_atlas_handle,
|
|
sprite: TextureAtlasSprite::new(animation_indices.first),
|
|
transform: Transform::from_scale(Vec3::splat(6.0)),
|
|
..default()
|
|
},
|
|
animation_indices,
|
|
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
|
|
));
|
|
}
|