Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
merwaaan committed Aug 26, 2024
1 parent 4b2f721 commit c878e88
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 203 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.4.0 - 2024-??-??

### Added

- Animation progress can be accessed and mutated directly in the SpritesheetAnimation component

## 0.3.0 - 2024-08-26

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_spritesheet_animation"
version = "0.3.0"
version = "0.4.0"
description = "A Bevy plugin for animating sprites"
repository = "https://github.com/merwaaan/bevy_spritesheet_animation"
readme="README.md"
Expand Down
4 changes: 3 additions & 1 deletion examples/composition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
pub mod common;

use bevy::prelude::*;
use bevy_spritesheet_animation::prelude::*;
use bevy_spritesheet_animation::{
components::spritesheet_animation::AnimationProgress, prelude::*,
};

fn main() {
App::new()
Expand Down
91 changes: 91 additions & 0 deletions examples/control.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// This example illustrates how to control the state of an animated sprite.

#[path = "./common/mod.rs"]
pub mod common;

use bevy::prelude::*;
use bevy_spritesheet_animation::{
components::spritesheet_animation::AnimationProgress, prelude::*,
};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(SpritesheetAnimationPlugin)
.add_systems(Startup, setup)
.add_systems(Update, update)
.run();
}

fn setup(
mut commands: Commands,
mut library: ResMut<SpritesheetLibrary>,
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
assets: Res<AssetServer>,
) {
commands.spawn(Camera2dBundle::default());

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

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

let clip_id = library.new_clip(|clip| {
clip.push_frame_indices(Spritesheet::new(8, 8).positions([(0, 1), (0, 3), (0, 5), (0, 7)]))
.set_default_duration(AnimationDuration::PerFrame(3_000));
});

let animation_id = library.new_animation(|animation| {
animation
.add_stage(clip_id.into())
.set_repeat(AnimationRepeat::Cycles(1));
});

commands.spawn((
SpriteBundle {
texture,
..default()
},
TextureAtlas {
layout,
..default()
},
SpritesheetAnimation::from_id(animation_id),
));
}

fn update(keyboard: Res<ButtonInput<KeyCode>>, mut sprites: Query<&mut SpritesheetAnimation>) {
for mut sprite in &mut sprites {
// Play/Pause

if keyboard.just_pressed(KeyCode::KeyP) {
sprite.playing = !sprite.playing;
}

// Reset

if keyboard.just_pressed(KeyCode::KeyR) {
sprite.reset();
}

// Switch to specific frames

static KEYS: [KeyCode; 4] = [
KeyCode::Numpad0,
KeyCode::Numpad1,
KeyCode::Numpad2,
KeyCode::Numpad3,
];

for (frame, key) in KEYS.iter().enumerate() {
if keyboard.just_pressed(*key) {
sprite.progress.frame = frame;
}
}
}
}
38 changes: 26 additions & 12 deletions src/animator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ use bevy::{
use std::{collections::HashMap, sync::Arc};

use crate::{
animation::AnimationId, components::spritesheet_animation::SpritesheetAnimation,
events::AnimationEvent, library::SpritesheetLibrary,
animation::AnimationId,
components::spritesheet_animation::{AnimationProgress, SpritesheetAnimation},
events::AnimationEvent,
library::SpritesheetLibrary,
systems::spritesheet_animation::ActualTime,
};

Expand All @@ -30,6 +32,10 @@ struct AnimationInstance {
current_stage_index: usize,
accumulated_time: u32,

/// The previous animation progress.
/// To detect when users manually changed it.
last_progress: AnimationProgress,

/// Marks when the animation has ended to emit end events only once
ended: bool,
}
Expand Down Expand Up @@ -73,23 +79,19 @@ impl SpritesheetAnimator {
// Create a new animation instance if:
// - the entity is new OR
// - it switched animation OR
// - a reset has been requested
// - progress has been manually controlled

let needs_new_animation_instance = match self.animation_instances.get(&entity) {
// The entity has an animation instance already but it switched animation
// The entity has an animation instance already but it switched animation/was manually controlled
Some(instance) => {
instance.animation_id != entity_animation.animation_id
|| entity_animation.reset_requested
|| instance.last_progress != entity_animation.progress
}
// The entity has no animation instance yet
None => true,
};

if needs_new_animation_instance {
// Clear any reset request

entity_animation.reset_requested = false;

// Retrieve the cached animation data (create it if needed)

let cache = self
Expand All @@ -101,8 +103,11 @@ impl SpritesheetAnimator {

// Create a new iterator for this animation

let mut iterator =
AnimationIterator::new(entity_animation.animation_id, cache.clone());
let mut iterator = AnimationIterator::new(
entity_animation.animation_id,
entity_animation.progress,
cache.clone()
);

// Immediatly assign the first frame to kicktart the animation

Expand All @@ -111,6 +116,10 @@ impl SpritesheetAnimator {
if let Some(first_frame) = &maybe_first_frame {
entity_atlas.index = first_frame.atlas_index;

// Update the animation progress

entity_animation.progress = ;

// Emit events for the first frame

let events = SpritesheetAnimator::promote_events(&first_frame.events, &entity);
Expand All @@ -132,6 +141,7 @@ impl SpritesheetAnimator {
current_frame_duration: first_frame_duration,
current_stage_index: first_stage_index,
accumulated_time: 0,
last_progress: AnimationProgress::default(),
ended: false,
},
);
Expand All @@ -141,7 +151,7 @@ impl SpritesheetAnimator {

// Skip the update if the animation is paused
//
// (skipped AFTER the setup above so that the first frame is assigned, even if paused)
// (skipped AFTER the previous steps so that the first/manual frame is assigned, even if paused)

if !entity_animation.playing {
continue;
Expand All @@ -164,6 +174,10 @@ impl SpritesheetAnimator {

entity_atlas.index = next_frame.atlas_index;

// Update the animation progress

entity_animation.progress = ;

// Store this frame's data

animation_instance.current_frame_duration = next_frame.duration;
Expand Down
Loading

0 comments on commit c878e88

Please sign in to comment.