craftworkgames / MonoGame.Extended

Extensions to make MonoGame more awesome
http://www.monogameextended.net/
Other
1.44k stars 325 forks source link

SpriteSheetAnimation.PingPong = true finishes on the wrong frame if the elapsed time since last update was large #805

Closed DavidFidge closed 1 year ago

DavidFidge commented 1 year ago

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);
        }
DavidFidge commented 1 year ago

Proposed fix in pull request #806