Beispiel #1
0
        /// <inheritdoc />
        /// <summary>
        ///     Ctor
        /// </summary>
        /// <param name="type"></param>
        /// <param name="processor"></param>
        internal HealthBar(HealthBarType type, ScoreProcessor processor) : base(SkinManager.Skin.HealthBarBackground)
        {
            Type      = type;
            Processor = processor;

            Size = new ScalableVector2(Frames.First().Width, Frames.First().Height);

            // Start animation
            StartLoop(Direction.Forward, 60);

            // Create the foreground bar (the one that'll serve as the gauge progress).
            ForegroundBar = new AnimatableSprite(SkinManager.Skin.HealthBarForeground)
            {
                Parent             = this,
                SpriteBatchOptions = new SpriteBatchOptions()
                {
                    SortMode          = SpriteSortMode.Deferred,
                    BlendState        = BlendState.NonPremultiplied,
                    SamplerState      = SamplerState.PointClamp,
                    DepthStencilState = DepthStencilState.Default,
                    RasterizerState   = RasterizerState.CullNone,
                    Shader            = new Shader(GameBase.Game.Resources.Get("Quaver.Resources/Shaders/semi-transparent.mgfxo"), new Dictionary <string, object>()
                    {
                        { "p_position", new Vector2() },
                        { "p_rectangle", new Vector2() },
                        { "p_dimensions", new Vector2() },
                        { "p_alpha", 0f }
                    })
                }
            };

            ForegroundBar.Size = new ScalableVector2(ForegroundBar.Frames.First().Width, ForegroundBar.Frames.First().Height);

            // Start animation.
            ForegroundBar.StartLoop(Direction.Forward, 60);

            switch (Type)
            {
            case HealthBarType.Horizontal:
                Alignment = Alignment.TopLeft;
                ForegroundBar.Alignment = Alignment.TopLeft;

                ForegroundBar.SpriteBatchOptions.Shader.SetParameter("p_position", new Vector2(ForegroundBar.Width, 0f), true);
                break;

            case HealthBarType.Vertical:
                Alignment = Alignment.BotLeft;
                ForegroundBar.Alignment = Alignment.TopLeft;

                ForegroundBar.SpriteBatchOptions.Shader.SetParameter("p_position", new Vector2(0, 0), true);
                break;

            default:
                throw new NotImplementedException();
            }

            // Set default shader params.
            ForegroundBar.SpriteBatchOptions.Shader.SetParameter("p_rectangle", new Vector2(Width, Height), true);
            ForegroundBar.SpriteBatchOptions.Shader.SetParameter("p_dimensions", new Vector2(Width, Height), true);
        }
Beispiel #2
0
        public override void onAddedToScene()
        {
            // TODO - this should happen automatically
            scale = new Vector2(5, 5);

            var gameScene           = (HandyScene)scene;
            var animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.SPACEMAN_SHIELD];

            var sprite = new AnimatableSprite(animationDefinition.SpriteDefinition.Subtextures);

            sprite.renderLayer = RenderLayers.PRIMARY;

            var animation = new AnimationComponent(sprite, animationDefinition, SpacemanAnimations.SHIELD);

            var collider = new BoxCollider(5 * 1.5f, 5 * 5.5f);

            collider.localOffset = new Vector2(5, 0);
            Flags.setFlagExclusive(ref collider.physicsLayer, PhysicsLayers.BACK_WALLS);
            Flags.setFlag(ref collider.collidesWithLayers, PhysicsLayers.BALL);

            var events = new EventComponent();

            events.SetTriggers(_triggers);

            addComponent(sprite);
            addComponent(animation);
            addComponent(events);
            addComponent(collider);

            position = new Vector2(position.X + 5 * 15, position.Y);
        }
Beispiel #3
0
        /// <summary>
        ///     Initialize HitObject Sprite used for Object Pooling. Only gets initialized once upon object creation.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ruleset"></param>
        private void InitializeSprites(GameplayRulesetKeys ruleset, int lane)
        {
            // Reference variables
            var playfield = (GameplayPlayfieldKeys)ruleset.Playfield;
            var posX      = playfield.Stage.Receptors[lane].X;

            // Create the base HitObjectSprite
            HitObjectSprite = new Sprite()
            {
                Alignment    = Alignment.TopLeft,
                Position     = new ScalableVector2(posX, 0),
                SpriteEffect = !GameplayRulesetKeys.IsDownscroll && SkinManager.Skin.Keys[MapManager.Selected.Value.Mode].FlipNoteImagesOnUpscroll
                                ? SpriteEffects.FlipVertically
                                : SpriteEffects.None,
                Image = UserInterface.BlankBox,
            };

            // Update hit body's size to match image ratio
            HitObjectSprite.Size = new ScalableVector2(playfield.LaneSize, playfield.LaneSize * HitObjectSprite.Image.Height / HitObjectSprite.Image.Width);
            LongNoteBodyOffset   = HitObjectSprite.Height / 2;

            // Create Hold Body
            var bodies = SkinManager.Skin.Keys[ruleset.Mode].NoteHoldBodies[lane];

            LongNoteBodySprite = new AnimatableSprite(bodies)
            {
                Alignment = Alignment.TopLeft,
                Size      = new ScalableVector2(playfield.LaneSize, 0),
                Position  = new ScalableVector2(posX, 0),
                Parent    = playfield.Stage.HitObjectContainer
            };

            // Create the Hold End
            LongNoteEndSprite = new Sprite()
            {
                Alignment    = Alignment.TopLeft,
                Position     = new ScalableVector2(posX, 0),
                Size         = new ScalableVector2(playfield.LaneSize, 0),
                Parent       = playfield.Stage.HitObjectContainer,
                SpriteEffect = !GameplayRulesetKeys.IsDownscroll && SkinManager.Skin.Keys[MapManager.Selected.Value.Mode].FlipNoteEndImagesOnUpscroll
                    ? SpriteEffects.FlipVertically
                    : SpriteEffects.None,
            };

            // Set long note end properties.
            LongNoteEndSprite.Image  = SkinManager.Skin.Keys[ruleset.Mode].NoteHoldEnds[lane];
            LongNoteEndSprite.Height = playfield.LaneSize * LongNoteEndSprite.Image.Height / LongNoteEndSprite.Image.Width;
            LongNoteEndOffset        = LongNoteEndSprite.Height / 2f;

            // We set the parent of the HitObjectSprite **AFTER** we create the long note
            // so that the body of the long note isn't drawn over the object.
            HitObjectSprite.Parent = playfield.Stage.HitObjectContainer;
        }
Beispiel #4
0
        public override void onAddedToScene()
        {
            var gameScene = (HandyScene)scene;

            foreach (var character in _stateComponent.State.CharacterOrder)
            {
                // not moving this to shared code
                // as we may decide we want different sprites/animations for the choice menu
                // e.g. "them posing and looking dope" or whatever
                AnimationDefinition animationDefinition;
                AnimatableSprite    sprite;
                switch (character)
                {
                case Gameplay.Character.KNIGHT:
                    animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.KNIGHT];
                    sprite = new AnimatableSprite(animationDefinition.SpriteDefinition.Subtextures);
                    CharacterChoiceSprites.Add(character, sprite);
                    CharacterChoiceAnimations.Add(character, new AnimationComponent(sprite, animationDefinition, KnightAnimations.WALK_FORWARD));
                    break;

                case Gameplay.Character.WIZARD:
                    animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.WIZARD];
                    sprite = new AnimatableSprite(animationDefinition.SpriteDefinition.Subtextures);
                    CharacterChoiceSprites.Add(character, sprite);
                    CharacterChoiceAnimations.Add(character, new AnimationComponent(sprite, animationDefinition, WizardAnimations.WALK_DOWN));
                    break;

                case Gameplay.Character.SPACEMAN:
                    animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.SPACEMAN];
                    sprite = new AnimatableSprite(animationDefinition.SpriteDefinition.Subtextures);
                    CharacterChoiceSprites.Add(character, sprite);
                    CharacterChoiceAnimations.Add(character, new AnimationComponent(sprite, animationDefinition, SpacemanAnimations.WALK_DOWN));
                    break;

                case Gameplay.Character.ALIEN:
                    throw new NotImplementedException();

                case Gameplay.Character.PIRATE:
                    throw new NotImplementedException();

                case Gameplay.Character.SKELETON:
                    throw new NotImplementedException();

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            CharacterChoiceSprites.Values.ToList().ForEach(s => addComponent(s));
            CharacterChoiceSprites.Values.ToList().ForEach(s => s.renderLayer = RenderLayers.PRIMARY);
            CharacterChoiceAnimations.Values.ToList().ForEach(a => addComponent(a));
        }
        /// <summary>
        ///     Initialize HitObject Sprite used for Object Pooling. Only gets initialized once upon object creation.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ruleset"></param>
        private void InitializeSprites(GameplayRulesetKeys ruleset, int lane, ScrollDirection direction)
        {
            // Reference variables
            var playfield    = (GameplayPlayfieldKeys)ruleset.Playfield;
            var posX         = playfield.Stage.Receptors[lane].X;
            var flipNoteBody = direction.Equals(ScrollDirection.Up) && SkinManager.Skin.Keys[MapManager.Selected.Value.Mode].FlipNoteImagesOnUpscroll;
            var flipNoteEnd  = direction.Equals(ScrollDirection.Up) && SkinManager.Skin.Keys[MapManager.Selected.Value.Mode].FlipNoteEndImagesOnUpscroll;

            ScrollDirection = direction;

            // Create the base HitObjectSprite
            HitObjectSprite = new Sprite()
            {
                Alignment    = Alignment.TopLeft,
                Position     = new ScalableVector2(posX, 0),
                SpriteEffect = flipNoteBody ? SpriteEffects.FlipVertically : SpriteEffects.None
            };

            // Create Hold Body
            var bodies = SkinManager.Skin.Keys[ruleset.Mode].NoteHoldBodies[lane];

            LongNoteBodySprite = new AnimatableSprite(bodies)
            {
                Alignment = Alignment.TopLeft,
                Size      = new ScalableVector2(playfield.LaneSize, 0),
                Position  = new ScalableVector2(posX, 0),
                Parent    = playfield.Stage.HitObjectContainer
            };

            // Create the Hold End
            LongNoteEndSprite = new Sprite()
            {
                Alignment    = Alignment.TopLeft,
                Position     = new ScalableVector2(posX, 0),
                Size         = new ScalableVector2(playfield.LaneSize, 0),
                Parent       = playfield.Stage.HitObjectContainer,
                SpriteEffect = flipNoteEnd ? SpriteEffects.FlipVertically : SpriteEffects.None
            };

            // Set long note end properties.
            LongNoteEndSprite.Image  = SkinManager.Skin.Keys[ruleset.Mode].NoteHoldEnds[lane];
            LongNoteEndSprite.Height = playfield.LaneSize * LongNoteEndSprite.Image.Height / LongNoteEndSprite.Image.Width;
            LongNoteEndOffset        = LongNoteEndSprite.Height / 2f;

            // We set the parent of the HitObjectSprite **AFTER** we create the long note
            // so that the body of the long note isn't drawn over the object.
            HitObjectSprite.Parent = playfield.Stage.HitObjectContainer;
        }
Beispiel #6
0
        public override void onAddedToScene()
        {
            var gameScene           = (Handy.Scene)scene;
            var animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.HIT_EFFECT];

            var sprite = new AnimatableSprite(animationDefinition.SpriteDefinition.Subtextures);

            sprite.renderLayer = RenderLayers.FOREGROUND;
            var animationComponent = new AnimationComponent(sprite, animationDefinition, "DEFAULT");
            var eventComponent     = new EventComponent();

            eventComponent.AddEvent("DEFAULT", 3, "END");

            addComponent(sprite);
            addComponent(animationComponent);
            addComponent(eventComponent);
            addComponent(new HitEffectComponent());
        }
Beispiel #7
0
        public override void onAddedToScene()
        {
            var gameScene = (HandyScene)scene;

            /*
             * SPRITE AND ANIMATION
             */
            var subtextures = Util.ExtractSubtextures(gameScene.Textures[Constants.BallSprites.DEFAULT], 1, 1);

            _sprite             = new AnimatableSprite(subtextures);
            _sprite.renderLayer = RenderLayers.PRIMARY;

            /*
             * COLLISIONS AND KINEMATICS
             */
            // must generate collider after we create the sprite,
            // otherwise the collider doesn't know how big it is (that's how it default works)
            _collider = new CircleCollider(9);
            Flags.setFlagExclusive(ref _collider.collidesWithLayers, PhysicsLayers.BACK_WALLS);
            Flags.setFlag(ref _collider.collidesWithLayers, PhysicsLayers.SIDE_WALLS);
            _kinematic.CollisionType = KinematicComponent.ECollisionType.Bounce;

            /*
             * STATE
             */
            _ballStateComponent = new BallStateComponent();

            /*
             * PARTICLES
             */

            _particleEmitter              = new ParticleEmitterComponent(generateParticleEmitterConfig(gameScene.Textures[BallSprites.DEFAULT]));
            _particleEmitter._active      = true;
            _particleEmitter.renderLayer  = RenderLayers.PRIMARY;
            _particleEmitter.renderOffset = -1;

            addComponent(_kinematic);
            addComponent(_sprite);
            addComponent(_collider);
            addComponent(_ballStateComponent);
            addComponent(_particleEmitter);

            scale = new Vector2(3, 3);
        }
Beispiel #8
0
        public override void onAddedToScene()
        {
            var gameScene = (HandyScene)scene;
            AnimationDefinition animationDefinition;

            Vector2[] lightPoints;
            Vector2[] heavyPoints;
            switch (Settings.Character)
            {
            case Gameplay.Character.KNIGHT:
                _state = new KnightStateMachineComponent(new KnightState());
                _events.SetTriggers(_knightEventTriggers);
                animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.KNIGHT];
                lightPoints         = scene.content.Load <Polygon>(Hitboxes.KNIGHT_HITBOX_LIGHT).points;
                heavyPoints         = scene.content.Load <Polygon>(Hitboxes.KNIGHT_HITBOX_HEAVY).points;
                break;

            case Gameplay.Character.WIZARD:
                _state = new WizardStateMachineComponent(new WizardState());
                _events.SetTriggers(_wizardEventTriggers);
                animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.WIZARD];
                lightPoints         = scene.content.Load <Polygon>(Hitboxes.WIZARD_HITBOX_LIGHT).points;
                heavyPoints         = scene.content.Load <Polygon>(Hitboxes.WIZARD_HITBOX_HEAVY).points;

                break;

            case Gameplay.Character.SPACEMAN:
                _state = new SpacemanStateMachineComponent(new SpacemanState());
                _events.SetTriggers(_spacemanEventTriggers);
                animationDefinition = gameScene.AnimationDefinitions[AsepriteFiles.SPACEMAN];
                lightPoints         = scene.content.Load <Polygon>(Hitboxes.KNIGHT_HITBOX_LIGHT).points;
                heavyPoints         = scene.content.Load <Polygon>(Hitboxes.KNIGHT_HITBOX_HEAVY).points;

                break;

            case Gameplay.Character.ALIEN:
                throw new NotImplementedException();

            case Gameplay.Character.PIRATE:
                throw new NotImplementedException();

            case Gameplay.Character.SKELETON:
                throw new NotImplementedException();

            default:
                throw new ArgumentOutOfRangeException();
            }
            _mainPlayerBodySprite             = new AnimatableSprite(animationDefinition.SpriteDefinition.Subtextures);
            _mainPlayerBodySprite.renderLayer = RenderLayers.PRIMARY;
            _mainBodyAnimation = new AnimationComponent(_mainPlayerBodySprite, animationDefinition, KnightAnimations.IDLE_HORIZONTAL);
            // must generate collider after we create the sprite,
            // otherwise the collider doesn't know how big it is (that's how it default works)
            _collider      = new BoxCollider(15, 10);
            _collider.name = ComponentNames.PLAYER_COLLIDER;
            Flags.setFlagExclusive(ref _collider.physicsLayer, PhysicsLayers.PLAYER);
            _collider.collidesWithLayers = 0;
            Flags.setFlag(ref _collider.collidesWithLayers, PhysicsLayers.BACK_WALLS);
            Flags.setFlag(ref _collider.collidesWithLayers, PhysicsLayers.SIDE_WALLS);
            Flags.setFlag(ref _collider.collidesWithLayers, PhysicsLayers.ENVIRONMENT);
            Flags.setFlag(ref _collider.collidesWithLayers, PhysicsLayers.NET);


            // Aim Indicator
            var aimIndicator = new AimIndicator(this);

            scene.addEntity(aimIndicator);

            addComponent(_state);
            // _hitbox = new PolygonCollider([]);
            addComponent(_mainPlayerBodySprite);
            addComponent(_mainBodyAnimation);

            addComponent(_collider);
            if (_stateComponent.side == Gameplay.Side.RIGHT)
            {
                _mainPlayerBodySprite.flipX = true;
                // TODO - this is horrible but it's the only solution that worked
                Vector2 lightOffset = new Vector2();
                Vector2 heavyOffset = new Vector2();
                switch (Settings.Character)
                {
                case Gameplay.Character.KNIGHT:
                    lightOffset = new Vector2(-8.5f, -1.5f);
                    heavyOffset = new Vector2(-25, 2.5f);
                    break;

                case Gameplay.Character.WIZARD:
                    lightOffset = new Vector2(0.333f, 1f);
                    heavyOffset = new Vector2(-.286f, 0.429f);
                    break;

                case Gameplay.Character.SPACEMAN:
                    break;

                case Gameplay.Character.ALIEN:
                    break;

                case Gameplay.Character.PIRATE:
                    break;

                case Gameplay.Character.SKELETON:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                lightPoints = lightPoints.Reverse().Select(point => new Vector2(-point.X + lightOffset.X, point.Y + lightOffset.Y)).ToArray();
                heavyPoints = heavyPoints.Reverse().Select(point => new Vector2(-point.X + heavyOffset.X, point.Y + heavyOffset.Y)).ToArray();
            }
            _lightHitbox           = new PolygonCollider(lightPoints);
            _lightHitbox.isTrigger = true;
            _lightHitbox.name      = ComponentNames.HITBOX_COLLIDER_LIGHT;
            addComponent(_lightHitbox);
            _heavyHitbox           = new PolygonCollider(heavyPoints);
            _heavyHitbox.isTrigger = true;
            _heavyHitbox.name      = ComponentNames.HITBOX_COLLIDER_HEAVY;
            addComponent(_heavyHitbox);

            // Circle and cooldowns
            var subtextures = Util.ExtractSubtextures(gameScene.Textures[Sprites.CHARACTER_CIRCLE], 1, 1);
            var circle      = new SpritesheetComponent(subtextures);

            circle.name         = ComponentNames.CHARACTER_CIRCLE;
            circle.renderLayer  = RenderLayers.BACKGROUND;
            circle.localOffset  = new Vector2(0, 15);
            circle.renderOffset = 1;
            addComponent(circle);

            subtextures = Util.ExtractSubtextures(gameScene.Textures[Sprites.LEFT_COOLDOWN], 1, 15);
            var left = new SpritesheetComponent(subtextures);

            left.name         = ComponentNames.LEFT_COOLDOWN;
            left.renderLayer  = RenderLayers.BACKGROUND;
            left.localOffset  = new Vector2(0, 15);
            left.renderOffset = 1;
            addComponent(left);

            subtextures = Util.ExtractSubtextures(gameScene.Textures[Sprites.RIGHT_COOLDOWN], 1, 15);
            var right = new SpritesheetComponent(subtextures);

            right.name         = ComponentNames.RIGHT_COOLDOWN;
            right.renderLayer  = RenderLayers.BACKGROUND;
            right.localOffset  = new Vector2(0, 15);
            right.renderOffset = 1;
            addComponent(right);

            addComponent(new SpriteDepthComponent {
                BaseRenderLayer = RenderLayers.PRIMARY
            });

            SetupSound();
        }
        /// <inheritdoc />
        /// <summary>
        /// </summary>
        /// <param name="screen"></param>
        public TestDrawingSpritesScreenView(Screen screen) : base(screen)
        {
            #region GREEN_BOX
            GreenBox = new Sprite()
            {
                Parent    = Container,
                Size      = new ScalableVector2(50, 50),
                Tint      = Color.Green,
                Position  = new ScalableVector2(0, 10),
                Alignment = Alignment.TopCenter
            };

            GreenBox.AddBorder(Color.White, 2);
            #endregion

            #region HELLO_WORLD_TEXT
            HelloWorldText = new SpriteText("exo2-bold", "Hello, World!", 18)
            {
                Parent    = Container,
                Alignment = Alignment.TopCenter,
                Y         = GreenBox.Height + GreenBox.Y + 40
            };
            #endregion

            #region CLICK_ME_BUTTON
            ClickMeButton = new TextButton(WobbleAssets.WhiteBox, "exo2-bold", "Click me!", 18, (sender, args) =>
            {
                // Click event handler method goes here.
                // Choose a random background color!
                BackgroundColor = new Color(Rng.Next(0, 255), Rng.Next(0, 255), Rng.Next(0, 255));
            })
            {
                Parent    = Container,
                Size      = new ScalableVector2(150, 50),
                Tint      = Color.White,
                Text      = { Tint = Color.Black },
                Alignment = Alignment.TopCenter,
                Y         = HelloWorldText.Y + 40
            };
            #endregion

            #region ANIMATING_LIGHTING
            AnimatingLighting = new AnimatableSprite(Textures.TestSpritesheet)
            {
                Parent    = Container,
                Size      = new ScalableVector2(200, 200),
                Alignment = Alignment.MidRight,
                X         = -20,
                // Here we will create new custom SpriteBatchOptions for this sprite.
                // This overrides SpriteBatch.Begin() to include these new SpriteBatchOptions ONLY for this sprite and any
                // sprites drawn after it that specify `UsePreviousSpriteBatchOptions`
                //
                // IMPORTANT!
                // Any sprites you want to have these same SpriteBatch.Begin options for WITHOUT creating a new SpriteBatch,
                // you must set `UsePreviousSpriteBatchOptions` to true.
                SpriteBatchOptions = new SpriteBatchOptions {
                    BlendState = BlendState.Additive
                },
            };

            // Start the animation loop forwards at 60FPS infinitely.
            AnimatingLighting.StartLoop(Direction.Forward, 60);
            #endregion

            #region SPRITE_WITH_SHADER
            SpriteWithShader = new Sprite
            {
                Image              = WobbleAssets.WhiteBox,
                Size               = new ScalableVector2(200, 200),
                Alignment          = Alignment.TopCenter,
                Parent             = Container,
                Tint               = Color.Orange,
                Y                  = ClickMeButton.Y + ClickMeButton.Height + 40,
                SpriteBatchOptions = new SpriteBatchOptions
                {
                    SortMode          = SpriteSortMode.Deferred,
                    BlendState        = BlendState.NonPremultiplied,
                    SamplerState      = SamplerState.PointClamp,
                    DepthStencilState = DepthStencilState.Default,
                    RasterizerState   = RasterizerState.CullNone,
                    // The shader attached is to make the sprite semi transparent
                    // Shader created by "Vortex-" (https://github.com/VortexCoyote)
                    Shader = new Shader(GameBase.Game.Resources.Get("Wobble.Tests.Resources/Shaders/semi-transparent.mgfxo"),
                                        new Dictionary <string, object>
                    {
                        { "p_dimensions", new Vector2(200, 200) },
                        { "p_position", new Vector2(0, 0) },
                        { "p_rectangle", new Vector2(100, 100) },
                        { "p_alpha", 0f }
                    })
                }
            };
            #endregion
        }
Beispiel #10
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();
    }
Beispiel #11
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();
    }