public CrossFadeSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

            // Set the base value of the _animatedPosition. When the animations are stopped,
            // _animatedPosition will return to this value.
            _animatedPosition.Value = new Vector2(bounds.Center.X, bounds.Center.Y);

            // Create an oscillating horizontal animation.
            Vector2FromToByAnimation fromToAnimation = new Vector2FromToByAnimation
            {
                From           = new Vector2(200, bounds.Center.Y),
                To             = new Vector2(bounds.Right - 200, bounds.Center.Y),
                Duration       = TimeSpan.FromSeconds(2),
                EasingFunction = new CubicEase {
                    Mode = EasingMode.EaseInOut
                },
            };

            _horizontalAnimation = new AnimationClip <Vector2>(fromToAnimation)
            {
                LoopBehavior = LoopBehavior.Oscillate,
                Duration     = TimeSpan.MaxValue,
            };

            // Create an oscillating vertical animation.
            fromToAnimation = new Vector2FromToByAnimation
            {
                From           = new Vector2(bounds.Center.X, 100),
                To             = new Vector2(bounds.Center.X, bounds.Bottom - 100),
                Duration       = TimeSpan.FromSeconds(2),
                EasingFunction = new CubicEase {
                    Mode = EasingMode.EaseInOut
                },
            };

            _verticalAnimation = new AnimationClip <Vector2>(fromToAnimation)
            {
                LoopBehavior = LoopBehavior.Oscillate,
                Duration     = TimeSpan.MaxValue,
            };

            // Start the horizontal movement. AnimationService.StartAnimation() returns an
            // AnimationController. We keep this AnimationController because it is needed to fade-out
            // the animation.
            _state = 1;
            _currentAnimationController = AnimationService.StartAnimation(_horizontalAnimation, _animatedPosition);
            _currentAnimationController.UpdateAndApply();

            // When the animation is stopped, all intermediate animation objects should be recycled.
            _currentAnimationController.AutoRecycle();
        }
        public AdditiveAnimationSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

            // ----- Create and start the base animation.
            Vector2FromToByAnimation leftRightAnimation = new Vector2FromToByAnimation
            {
                TargetProperty = "Position",
                From           = new Vector2(bounds.Left + 100, bounds.Center.Y),
                To             = new Vector2(bounds.Right - 100, bounds.Center.Y),
                Duration       = TimeSpan.FromSeconds(2),
                EasingFunction = new HermiteEase {
                    Mode = EasingMode.EaseInOut
                },
            };
            AnimationClip <Vector2> baseAnimation = new AnimationClip <Vector2>(leftRightAnimation)
            {
                LoopBehavior = LoopBehavior.Oscillate,
                Duration     = TimeSpan.MaxValue,
            };

            _baseAnimationController = AnimationService.StartAnimation(baseAnimation, _animatablePosition);
            _baseAnimationController.UpdateAndApply();

            // ----- Create and start the additive animation.
            Vector2FromToByAnimation upDownAnimation = new Vector2FromToByAnimation
            {
                TargetProperty = "Position",
                From           = new Vector2(0, 50),
                To             = new Vector2(0, -50),
                Duration       = TimeSpan.FromSeconds(0.5),
                EasingFunction = new SineEase {
                    Mode = EasingMode.EaseInOut
                },

                // Set IsAdditive flag.
                IsAdditive = true,
            };
            AnimationClip <Vector2> additiveAnimation = new AnimationClip <Vector2>(upDownAnimation)
            {
                LoopBehavior = LoopBehavior.Oscillate,
                Duration     = TimeSpan.MaxValue,
            };

            // Start animation using "Compose".
            _additiveAnimationController = AnimationService.StartAnimation(
                additiveAnimation,
                _animatablePosition,
                AnimationTransitions.Compose());
            _additiveAnimationController.UpdateAndApply();
        }
Example #3
0
    public CrossFadeSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

      // Set the base value of the _animatedPosition. When the animations are stopped,
      // _animatedPosition will return to this value.
      _animatedPosition.Value = new Vector2(bounds.Center.X, bounds.Center.Y);

      // Create an oscillating horizontal animation.
      Vector2FromToByAnimation fromToAnimation = new Vector2FromToByAnimation
      {
        From = new Vector2(200, bounds.Center.Y),
        To = new Vector2(bounds.Right - 200, bounds.Center.Y),
        Duration = TimeSpan.FromSeconds(2),
        EasingFunction = new CubicEase { Mode = EasingMode.EaseInOut },
      };

      _horizontalAnimation = new AnimationClip<Vector2>(fromToAnimation)
      {
        LoopBehavior = LoopBehavior.Oscillate,
        Duration = TimeSpan.MaxValue,
      };

      // Create an oscillating vertical animation.
      fromToAnimation = new Vector2FromToByAnimation
      {
        From = new Vector2(bounds.Center.X, 100),
        To = new Vector2(bounds.Center.X, bounds.Bottom - 100),
        Duration = TimeSpan.FromSeconds(2),
        EasingFunction = new CubicEase { Mode = EasingMode.EaseInOut },
      };

      _verticalAnimation = new AnimationClip<Vector2>(fromToAnimation)
      {
        LoopBehavior = LoopBehavior.Oscillate,
        Duration = TimeSpan.MaxValue,
      };

      // Start the horizontal movement. AnimationService.StartAnimation() returns an
      // AnimationController. We keep this AnimationController because it is needed to fade-out
      // the animation.
      _state = 1;
      _currentAnimationController = AnimationService.StartAnimation(_horizontalAnimation, _animatedPosition);
      _currentAnimationController.UpdateAndApply();

      // When the animation is stopped, all intermediate animation objects should be recycled.
      _currentAnimationController.AutoRecycle();
    }
Example #4
0
    public AdditiveAnimationSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

      // ----- Create and start the base animation.
      Vector2FromToByAnimation leftRightAnimation = new Vector2FromToByAnimation
      {
        TargetProperty = "Position",
        From = new Vector2(bounds.Left + 100, bounds.Center.Y),
        To = new Vector2(bounds.Right - 100, bounds.Center.Y),
        Duration = TimeSpan.FromSeconds(2),
        EasingFunction = new HermiteEase { Mode = EasingMode.EaseInOut },
      };
      AnimationClip<Vector2> baseAnimation = new AnimationClip<Vector2>(leftRightAnimation)
      {
        LoopBehavior = LoopBehavior.Oscillate,
        Duration = TimeSpan.MaxValue,
      };
      _baseAnimationController = AnimationService.StartAnimation(baseAnimation, _animatablePosition);
      _baseAnimationController.UpdateAndApply();

      // ----- Create and start the additive animation.
      Vector2FromToByAnimation upDownAnimation = new Vector2FromToByAnimation
      {
        TargetProperty = "Position",
        From = new Vector2(0, 50),
        To = new Vector2(0, -50),
        Duration = TimeSpan.FromSeconds(0.5),
        EasingFunction = new SineEase { Mode = EasingMode.EaseInOut },

        // Set IsAdditive flag.
        IsAdditive = true,
      };
      AnimationClip<Vector2> additiveAnimation = new AnimationClip<Vector2>(upDownAnimation)
      {
        LoopBehavior = LoopBehavior.Oscillate,
        Duration = TimeSpan.MaxValue,
      };

      // Start animation using "Compose".
      _additiveAnimationController = AnimationService.StartAnimation(
        additiveAnimation,
        _animatablePosition,
        AnimationTransitions.Compose());
      _additiveAnimationController.UpdateAndApply();
    }
Example #5
0
        public AnimatableObjectSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

            // ----- Create three named AnimatableSprite instances.
            _animatableSpriteA = new AnimatableSprite("SpriteA", SpriteBatch, Logo)
            {
                Position = new Vector2(bounds.Center.X, bounds.Center.Y / 2.0f),
                Color    = Color.Red,
            };

            _animatableSpriteB = new AnimatableSprite("SpriteB", SpriteBatch, Logo)
            {
                Position = new Vector2(bounds.Center.X, bounds.Center.Y),
                Color    = Color.Green,
            };

            _animatableSpriteC = new AnimatableSprite("SpriteC", SpriteBatch, Logo)
            {
                Position = new Vector2(bounds.Center.X, 3.0f * bounds.Center.Y / 2.0f),
                Color    = Color.Blue,
            };

            // Create a looping color key-frame animation.
            ColorKeyFrameAnimation colorAnimation = new ColorKeyFrameAnimation
            {
                TargetProperty      = "Color",
                EnableInterpolation = true,
            };

            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(0.0), Color.Red));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(0.5), Color.Orange));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(1.0), Color.Yellow));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(1.5), Color.Green));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(2.0), Color.Blue));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(2.5), Color.Indigo));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(3.0), Color.Violet));
            colorAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(3.5), Color.Red));
            AnimationClip <Color> loopedColorAnimation = new AnimationClip <Color>(colorAnimation)
            {
                TargetObject = "SpriteB",
                LoopBehavior = LoopBehavior.Cycle,
                Duration     = TimeSpan.MaxValue,
            };

            // Create a oscillating from/to animation for the position.
            Vector2FromToByAnimation vector2Animation = new Vector2FromToByAnimation
            {
                TargetProperty = "Position",
                From           = new Vector2(bounds.Left + 100, _animatableSpriteC.Position.Y),
                To             = new Vector2(bounds.Right - 100, _animatableSpriteC.Position.Y),
                Duration       = TimeSpan.FromSeconds(2),
                EasingFunction = new HermiteEase {
                    Mode = EasingMode.EaseInOut
                },
            };
            AnimationClip <Vector2> oscillatingVector2Animation = new AnimationClip <Vector2>(vector2Animation)
            {
                LoopBehavior = LoopBehavior.Oscillate,
                Duration     = TimeSpan.MaxValue,
            };

            // Create a timeline group that contains both animations.
            TimelineGroup spriteCAnimation = new TimelineGroup {
                TargetObject = "SpriteC",
            };

            spriteCAnimation.Add(loopedColorAnimation);
            spriteCAnimation.Add(oscillatingVector2Animation);

            // Create a timeline group that contains the animations for SpriteB and SpriteC.
            TimelineGroup allSpriteAnimations = new TimelineGroup();

            allSpriteAnimations.Add(loopedColorAnimation);
            allSpriteAnimations.Add(spriteCAnimation);

            // There are several ways to apply animations to animatable objects and properties:
            //
            // Method 1: Apply to an IAnimatableProperty directly.
            // We either have direct access to a IAnimatableProperty or we can ask the IAnimatableObject
            // to give us a named IAnimatableProperty.
            // For example:
            //     AnimationService.StartAnimation(loopedColorAnimation, _animatableSpriteB.GetAnimatableProperty<Color>("Color"));
            //     AnimationService.StartAnimation(loopedColorAnimation, _animatableSpriteC.GetAnimatableProperty<Color>("Color"));
            //     AnimationService.StartAnimation(oscillatingLeftRightAnimation, _animatableSpriteC.GetAnimatableProperty<Vector2>("Position"));
            // In this case, the "TargetObject" and the "TargetProperty" values of the timelines/animations do not matter.
            //
            // Method 2: Apply to an IAnimatableObject directly.
            // For example:
            //     AnimationService.StartAnimation(loopedColorAnimation, _animatableSpriteB);
            //     AnimationService.StartAnimation(spriteCAnimation, _animatableSpriteC);
            // The animation service checks the TargetProperty value of the animations to see which
            // IAnimatabelProperty of the IAnimtableObjects should be animated by the animation.
            // The "TargetObject" values of the timelines are ignored.
            //
            // Method 3: Apply a timeline to a collection of IAnimatableObjects.
            // For example:
            var animationController = AnimationService.StartAnimation(allSpriteAnimations, new[] { _animatableSpriteA, _animatableSpriteB, _animatableSpriteC });

            // The "TargetObject" and "TargetProperty" values are used to check which objects and
            // properties must be animated by which animation.
            // combinedSpriteAnimation is a "tree" of timelines:
            //
            //                                  Type                         TargetObject   TargetProperty
            // --------------------------------------------------------------------------------------------------
            // allSpriteAnimations              TimelineGroup                -              -
            //   loopedColorAnimation           AnimationClip<Color>         "SpriteB"      -
            //     colorAnimation               ColorKeyFrameAnimation       -              "Color"
            //   spriteCAnimation               TimelineGroup                "SpriteC"      -
            //     loopedColorAnimation         AnimationClip<Color>         "SpriteB"      -
            //       colorAnimation             ColorKeyFrameAnimation       -             "Color"
            //     oscillatingVector2Animation  AnimationClip<Vector2>       -             -
            //       vector2Animation           FromToByAnimation            -             "Position"
            //
            // No animation specifies "SpriteA" as its TargetObject, therefore no animation
            // are applied to SpriteA.
            //
            // The first loopedColorAnimation is applied to "SpriteB". And the contained
            // colorAnimation is applied to the Color property of SpriteB.
            //
            // The spriteCAnimation is applied to "SpriteC". Therefore, all "children" of
            // spriteCAnimation are also applied to this object! The TargetObject property of
            // the second loopedColorAnimation is ignored! The second loopedColorAnimation is
            // applied to SpriteC!

            animationController.UpdateAndApply();
        }
Example #6
0
    public AnimatableObjectSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

      // ----- Create three named AnimatableSprite instances.
      _animatableSpriteA = new AnimatableSprite("SpriteA", SpriteBatch, Logo)
      {
        Position = new Vector2(bounds.Center.X, bounds.Center.Y / 2.0f),
        Color = Color.Red,
      };

      _animatableSpriteB = new AnimatableSprite("SpriteB", SpriteBatch, Logo)
      {
        Position = new Vector2(bounds.Center.X, bounds.Center.Y),
        Color = Color.Green,
      };

      _animatableSpriteC = new AnimatableSprite("SpriteC", SpriteBatch, Logo)
      {
        Position = new Vector2(bounds.Center.X, 3.0f * bounds.Center.Y / 2.0f),
        Color = Color.Blue,
      };

      // Create a looping color key-frame animation.
      ColorKeyFrameAnimation colorAnimation = new ColorKeyFrameAnimation
      {
        TargetProperty = "Color",
        EnableInterpolation = true,
      };
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(0.0), Color.Red));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(0.5), Color.Orange));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(1.0), Color.Yellow));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(1.5), Color.Green));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(2.0), Color.Blue));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(2.5), Color.Indigo));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(3.0), Color.Violet));
      colorAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(3.5), Color.Red));
      AnimationClip<Color> loopedColorAnimation = new AnimationClip<Color>(colorAnimation)
      {
        TargetObject = "SpriteB",
        LoopBehavior = LoopBehavior.Cycle,
        Duration = TimeSpan.MaxValue,
      };

      // Create a oscillating from/to animation for the position.
      Vector2FromToByAnimation vector2Animation = new Vector2FromToByAnimation
      {
        TargetProperty = "Position",
        From = new Vector2(bounds.Left + 100, _animatableSpriteC.Position.Y),
        To = new Vector2(bounds.Right - 100, _animatableSpriteC.Position.Y),
        Duration = TimeSpan.FromSeconds(2),
        EasingFunction = new HermiteEase { Mode = EasingMode.EaseInOut },
      };
      AnimationClip<Vector2> oscillatingVector2Animation = new AnimationClip<Vector2>(vector2Animation)
      {
        LoopBehavior = LoopBehavior.Oscillate,
        Duration = TimeSpan.MaxValue,
      };

      // Create a timeline group that contains both animations.
      TimelineGroup spriteCAnimation = new TimelineGroup { TargetObject = "SpriteC", };
      spriteCAnimation.Add(loopedColorAnimation);
      spriteCAnimation.Add(oscillatingVector2Animation);

      // Create a timeline group that contains the animations for SpriteB and SpriteC.
      TimelineGroup allSpriteAnimations = new TimelineGroup();
      allSpriteAnimations.Add(loopedColorAnimation);
      allSpriteAnimations.Add(spriteCAnimation);

      // There are several ways to apply animations to animatable objects and properties:
      //
      // Method 1: Apply to an IAnimatableProperty directly.
      // We either have direct access to a IAnimatableProperty or we can ask the IAnimatableObject
      // to give us a named IAnimatableProperty. 
      // For example:
      //     AnimationService.StartAnimation(loopedColorAnimation, _animatableSpriteB.GetAnimatableProperty<Color>("Color"));
      //     AnimationService.StartAnimation(loopedColorAnimation, _animatableSpriteC.GetAnimatableProperty<Color>("Color"));
      //     AnimationService.StartAnimation(oscillatingLeftRightAnimation, _animatableSpriteC.GetAnimatableProperty<Vector2>("Position"));
      // In this case, the "TargetObject" and the "TargetProperty" values of the timelines/animations do not matter. 
      //
      // Method 2: Apply to an IAnimatableObject directly.
      // For example: 
      //     AnimationService.StartAnimation(loopedColorAnimation, _animatableSpriteB);
      //     AnimationService.StartAnimation(spriteCAnimation, _animatableSpriteC);
      // The animation service checks the TargetProperty value of the animations to see which
      // IAnimatableProperty of the IAnimatableObjects should be animated by the animation.
      // The "TargetObject" values of the timelines are ignored.
      // 
      // Method 3: Apply a timeline to a collection of IAnimatableObjects.
      // For example: 
      var animationController = AnimationService.StartAnimation(allSpriteAnimations, new[] { _animatableSpriteA, _animatableSpriteB, _animatableSpriteC });
      // The "TargetObject" and "TargetProperty" values are used to check which objects and
      // properties must be animated by which animation.
      // combinedSpriteAnimation is a "tree" of timelines:
      // 
      //                                  Type                         TargetObject   TargetProperty
      // --------------------------------------------------------------------------------------------------
      // allSpriteAnimations              TimelineGroup                -              -
      //   loopedColorAnimation           AnimationClip<Color>         "SpriteB"      -
      //     colorAnimation               ColorKeyFrameAnimation       -              "Color"
      //   spriteCAnimation               TimelineGroup                "SpriteC"      -
      //     loopedColorAnimation         AnimationClip<Color>         "SpriteB"      - 
      //       colorAnimation             ColorKeyFrameAnimation       -             "Color"
      //     oscillatingVector2Animation  AnimationClip<Vector2>       -             -
      //       vector2Animation           FromToByAnimation            -             "Position"
      //
      // No animation specifies "SpriteA" as its TargetObject, therefore no animation
      // are applied to SpriteA.
      //
      // The first loopedColorAnimation is applied to "SpriteB". And the contained 
      // colorAnimation is applied to the Color property of SpriteB.
      //
      // The spriteCAnimation is applied to "SpriteC". Therefore, all "children" of 
      // spriteCAnimation are also applied to this object! The TargetObject property of
      // the second loopedColorAnimation is ignored! The second loopedColorAnimation is 
      // applied to SpriteC!

      animationController.UpdateAndApply();
    }
Example #7
0
    public BlendedAnimationSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

      // Create the animatable object.
      _animatableSprite = new AnimatableSprite("SpriteA", SpriteBatch, Logo)
      {
        Position = new Vector2(bounds.Center.X, bounds.Center.Y / 2.0f),
        Color = Color.Red,
      };

      Vector2FromToByAnimation slowLeftRightAnimation = new Vector2FromToByAnimation
      {
        TargetProperty = "Position",
        From = new Vector2(bounds.Left + 100, bounds.Top + 200),
        To = new Vector2(bounds.Right - 100, bounds.Top + 200),
        Duration = TimeSpan.FromSeconds(4),
        EasingFunction = new HermiteEase { Mode = EasingMode.EaseInOut },
      };

      ColorKeyFrameAnimation redGreenAnimation = new ColorKeyFrameAnimation
      {
        TargetProperty = "Color",
        EnableInterpolation = true,
      };
      redGreenAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(0), Color.Red));
      redGreenAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(4), Color.Green));

      TimelineGroup animationA = new TimelineGroup
      {
        slowLeftRightAnimation,
        redGreenAnimation,
      };

      Vector2FromToByAnimation fastLeftRightAnimation = new Vector2FromToByAnimation
      {
        TargetProperty = "Position",
        From = new Vector2(bounds.Left + 100, bounds.Bottom - 200),
        To = new Vector2(bounds.Right - 100, bounds.Bottom - 200),
        Duration = TimeSpan.FromSeconds(1),
        EasingFunction = new HermiteEase { Mode = EasingMode.EaseInOut },
      };

      ColorKeyFrameAnimation blackWhiteAnimation = new ColorKeyFrameAnimation
      {
        TargetProperty = "Color",
        EnableInterpolation = true,
      };
      blackWhiteAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(0), Color.Black));
      blackWhiteAnimation.KeyFrames.Add(new KeyFrame<Color>(TimeSpan.FromSeconds(1), Color.White));

      TimelineGroup animationB = new TimelineGroup
      {
        fastLeftRightAnimation,
        blackWhiteAnimation,
      };

      // Create a BlendGroup that blends animationA and animationB. 
      // The BlendGroup uses the TargetProperty values of the contained animations to 
      // to match the animations that should be blended:
      //   slowLeftRightAnimation with fastLeftRightAnimation
      //   redGreenAnimation with blackWhiteAnimation
      _blendedAnimation = new BlendGroup
      {
        LoopBehavior = LoopBehavior.Oscillate,
        Duration = TimeSpan.MaxValue,
      };
      _blendedAnimation.Add(animationA, 1);
      _blendedAnimation.Add(animationB, 0);
      _blendedAnimation.SynchronizeDurations();

      // Start blended animation.
      AnimationService.StartAnimation(_blendedAnimation, _animatableSprite).UpdateAndApply();
    }
        public BlendedAnimationSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            Rectangle bounds = GraphicsService.GraphicsDevice.Viewport.TitleSafeArea;

            // Create the animatable object.
            _animatableSprite = new AnimatableSprite("SpriteA", SpriteBatch, Logo)
            {
                Position = new Vector2(bounds.Center.X, bounds.Center.Y / 2.0f),
                Color    = Color.Red,
            };

            Vector2FromToByAnimation slowLeftRightAnimation = new Vector2FromToByAnimation
            {
                TargetProperty = "Position",
                From           = new Vector2(bounds.Left + 100, bounds.Top + 200),
                To             = new Vector2(bounds.Right - 100, bounds.Top + 200),
                Duration       = TimeSpan.FromSeconds(4),
                EasingFunction = new HermiteEase {
                    Mode = EasingMode.EaseInOut
                },
            };

            ColorKeyFrameAnimation redGreenAnimation = new ColorKeyFrameAnimation
            {
                TargetProperty      = "Color",
                EnableInterpolation = true,
            };

            redGreenAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(0), Color.Red));
            redGreenAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(4), Color.Green));

            TimelineGroup animationA = new TimelineGroup
            {
                slowLeftRightAnimation,
                redGreenAnimation,
            };

            Vector2FromToByAnimation fastLeftRightAnimation = new Vector2FromToByAnimation
            {
                TargetProperty = "Position",
                From           = new Vector2(bounds.Left + 100, bounds.Bottom - 200),
                To             = new Vector2(bounds.Right - 100, bounds.Bottom - 200),
                Duration       = TimeSpan.FromSeconds(1),
                EasingFunction = new HermiteEase {
                    Mode = EasingMode.EaseInOut
                },
            };

            ColorKeyFrameAnimation blackWhiteAnimation = new ColorKeyFrameAnimation
            {
                TargetProperty      = "Color",
                EnableInterpolation = true,
            };

            blackWhiteAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(0), Color.Black));
            blackWhiteAnimation.KeyFrames.Add(new KeyFrame <Color>(TimeSpan.FromSeconds(1), Color.White));

            TimelineGroup animationB = new TimelineGroup
            {
                fastLeftRightAnimation,
                blackWhiteAnimation,
            };

            // Create a BlendGroup that blends animationA and animationB.
            // The BlendGroup uses the TargetProperty values of the contained animations to
            // to match the animations that should be blended:
            //   slowLeftRightAnimation with fastLeftRightAnimation
            //   redGreenAnimation with blackWhiteAnimation
            _blendedAnimation = new BlendGroup
            {
                LoopBehavior = LoopBehavior.Oscillate,
                Duration     = TimeSpan.MaxValue,
            };
            _blendedAnimation.Add(animationA, 1);
            _blendedAnimation.Add(animationB, 0);
            _blendedAnimation.SynchronizeDurations();

            // Start blended animation.
            AnimationService.StartAnimation(_blendedAnimation, _animatableSprite).UpdateAndApply();
        }