Skip to content

Commit

Permalink
feat: Add isFirstFrame and onStart event to SpriteAnimation (#1492
Browse files Browse the repository at this point in the history
)
  • Loading branch information
munsterlander committed Apr 23, 2022
1 parent 450927c commit 701d070
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 6 deletions.
22 changes: 22 additions & 0 deletions packages/flame/lib/src/sprite_animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ class SpriteAnimation {
/// to the first, or keeps returning the last when done.
bool loop = true;

/// Registered method to be triggered when the animation starts.
void Function()? onStart;

/// Registered method to be triggered when the animation frame updates.
void Function(int currentIndex)? onFrame;

/// Registered method to be triggered when the animation complete.
void Function()? onComplete;

Expand All @@ -239,6 +245,9 @@ class SpriteAnimation {
/// The current frame that should be displayed.
SpriteAnimationFrame get currentFrame => frames[currentIndex];

/// Returns whether the animation is on the first frame.
bool get isFirstFrame => currentIndex == 0;

/// Returns whether the animation is on the last frame.
bool get isLastFrame => currentIndex == frames.length - 1;

Expand Down Expand Up @@ -282,6 +291,7 @@ class SpriteAnimation {
elapsed = 0.0;
currentIndex = 0;
_done = false;
_started = false;
}

/// Sets this animation to be on the last frame.
Expand All @@ -308,6 +318,10 @@ class SpriteAnimation {
bool _done = false;
bool done() => _done;

/// Local flag to determine if the animation has started to prevent multiple
/// calls to [onStart].
bool _started = false;

/// Updates this animation, ticking the lifeTime by an amount [dt]
/// (in seconds).
void update(double dt) {
Expand All @@ -316,11 +330,18 @@ class SpriteAnimation {
if (_done) {
return;
}
if (!_started) {
onStart?.call();
onFrame?.call(currentIndex);
_started = true;
}

while (clock >= currentFrame.stepTime) {
if (isLastFrame) {
if (loop) {
clock -= currentFrame.stepTime;
currentIndex = 0;
onFrame?.call(currentIndex);
} else {
_done = true;
onComplete?.call();
Expand All @@ -330,6 +351,7 @@ class SpriteAnimation {
} else {
clock -= currentFrame.stepTime;
currentIndex++;
onFrame?.call(currentIndex);
}
}
}
Expand Down
72 changes: 66 additions & 6 deletions packages/flame/test/sprite_animation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,25 @@ void main() {
);
});

test('onComplete called for single-frame animation', () {
test('onStart called for single-frame animation', () {
var counter = 0;
final sprite = MockSprite();
final animation = SpriteAnimation.spriteList(
[sprite],
stepTime: 1,
loop: false,
)..onComplete = () => counter++;
final animation =
SpriteAnimation.spriteList([sprite], stepTime: 1, loop: false)
..onStart = () => counter++;
expect(counter, 0);
animation.update(0.5);
expect(counter, 1);
animation.update(1);
expect(counter, 1);
});

test('onComplete called for single-frame animation', () {
var counter = 0;
final sprite = MockSprite();
final animation =
SpriteAnimation.spriteList([sprite], stepTime: 1, loop: false)
..onComplete = () => counter++;
expect(counter, 0);
animation.update(0.5);
expect(counter, 0);
Expand All @@ -59,6 +69,56 @@ void main() {
expect(counter, 1);
});

test(
'verify call is being made at first of frame for multi-frame animation',
() {
var timePassed = 0.0;
const dt = 0.03;
var timesCalled = 0;
final sprite = MockSprite();
final spriteList = [sprite, sprite, sprite];
final animation =
SpriteAnimation.spriteList(spriteList, stepTime: 1, loop: false);
animation.onFrame = (index) {
expect(timePassed, closeTo(index * 1.0, dt));
timesCalled++;
};
while (timePassed <= spriteList.length) {
timePassed += dt;
animation.update(dt);
}
expect(timesCalled, spriteList.length);
});

test('test sequence of event lifecycle for an animation', () {
var animationStarted = false;
var animationRunning = false;
var animationComplete = false;
final sprite = MockSprite();
final animation =
SpriteAnimation.spriteList([sprite], stepTime: 1, loop: false);
animation.onStart = () {
expect(animationStarted, false);
expect(animationRunning, false);
expect(animationComplete, false);
animationStarted = true;
animationRunning = true;
};
animation.onFrame = (index) {
expect(animationStarted, true);
expect(animationRunning, true);
expect(animationComplete, false);
};
animation.onComplete = () {
expect(animationStarted, true);
expect(animationRunning, true);
expect(animationComplete, false);
animationComplete = true;
};
animation.update(1);
expect(animationComplete, true);
});

test('completed completes', () {
final sprite = MockSprite();
final animation = SpriteAnimation.spriteList(
Expand Down

0 comments on commit 701d070

Please sign in to comment.