When PingPong is set to true the animation can finish on the wrong frame if the elapsed time since last update is larger than the time to reach the end of the last frame.
To avoid this a code change is needed in the if (IsPingPong) block so that it sets the frameIndex to 0 if the animation is complete (setting it to zero works for both normal and reversed flags as IsReversed is dealt with further down in the algorithm).
Failing unit test:
[Theory]
[InlineData(0, 3f)]
[InlineData(0, 4f)]
[InlineData(0, 5f)]
public void PingPong_Non_Looping_SpriteSheetAnimation_Should_Return_Correct_Frame_And_Complete_When_AnimationDuration_Is_Reached(int expectedTextureRegionIndex, float time)
{
var textureRegion2D1 = new TextureRegion2D("Region 1", null, new Rectangle());
var textureRegion2D2 = new TextureRegion2D("Region 2", null, new Rectangle());
var textureRegions = new[] { textureRegion2D1, textureRegion2D2 };
var spriteSheetAnimationData = new SpriteSheetAnimationData(
new[] { 0, 1 },
1,
false,
false,
true
);
var spriteSheetAnimation = new SpriteSheetAnimation("Test", textureRegions, spriteSheetAnimationData);
var isCompleteFired = false;
spriteSheetAnimation.OnCompleted += () => isCompleteFired = true;
spriteSheetAnimation.Play();
var gameTime = new GameTime(TimeSpan.Zero, TimeSpan.FromSeconds(time));
spriteSheetAnimation.Update(gameTime);
Assert.Equal(textureRegions[expectedTextureRegionIndex], spriteSheetAnimation.CurrentFrame);
Assert.True(spriteSheetAnimation.IsComplete);
Assert.True(isCompleteFired);
}
When PingPong is set to true the animation can finish on the wrong frame if the elapsed time since last update is larger than the time to reach the end of the last frame.
To avoid this a code change is needed in the if (IsPingPong) block so that it sets the frameIndex to 0 if the animation is complete (setting it to zero works for both normal and reversed flags as IsReversed is dealt with further down in the algorithm).
Failing unit test: