diff --git a/osu.Game/Storyboards/CommandLoop.cs b/osu.Game/Storyboards/CommandLoop.cs index a93903f4a9..02b5eb0122 100644 --- a/osu.Game/Storyboards/CommandLoop.cs +++ b/osu.Game/Storyboards/CommandLoop.cs @@ -1,8 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics; -using osu.Framework.Graphics.Transforms; +using System.Collections.Generic; namespace osu.Game.Storyboards { @@ -20,11 +19,15 @@ namespace osu.Game.Storyboards LoopCount = loopCount; } - public override void ApplyTransforms(Drawable drawable, double offset = 0) - => base.ApplyTransforms(drawable, offset + LoopStartTime); - - protected override void PostProcess(ICommand command, TransformSequence sequence) - => sequence.Loop(CommandsDuration - command.Duration, LoopCount); + public override IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0) + { + for (var loop = 0; loop < LoopCount; loop++) + { + var loopOffset = LoopStartTime + loop * CommandsDuration; + foreach (var command in base.GetCommands(timelineSelector, offset + loopOffset)) + yield return command; + } + } public override string ToString() => $"{LoopStartTime} x{LoopCount}"; diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index badd9a810a..a42aca7c28 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -3,14 +3,13 @@ using OpenTK; using OpenTK.Graphics; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Transforms; -using osu.Game.Storyboards.Drawables; using System.Collections.Generic; using System.Linq; namespace osu.Game.Storyboards { + public delegate CommandTimeline CommandTimelineSelector(CommandTimelineGroup commandTimelineGroup); + public class CommandTimelineGroup { public CommandTimeline X = new CommandTimeline(); @@ -49,63 +48,20 @@ namespace osu.Game.Storyboards public bool HasCommands => Timelines.Any(t => t.HasCommands); - public virtual void ApplyTransforms(Drawable drawable, double offset = 0) + public virtual IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0) { - if (X.HasCommands) drawable.X = X.StartValue; - foreach (var command in X.Commands) - using (drawable.BeginAbsoluteSequence(offset + command.StartTime)) - PostProcess(command, - drawable.MoveToX(command.StartValue) - .MoveToX(command.EndValue, command.Duration, command.Easing)); + if (offset != 0) + return timelineSelector(this).Commands.Select(command => + new CommandTimeline.TypedCommand + { + Easing = command.Easing, + StartTime = offset + command.StartTime, + EndTime = offset + command.EndTime, + StartValue = command.StartValue, + EndValue = command.EndValue, + }); - if (Y.HasCommands) drawable.Y = Y.StartValue; - foreach (var command in Y.Commands) - using (drawable.BeginAbsoluteSequence(offset + command.StartTime)) - PostProcess(command, - drawable.MoveToY(command.StartValue) - .MoveToY(command.EndValue, command.Duration, command.Easing)); - - if (Scale.HasCommands) drawable.Scale = Scale.StartValue; - foreach (var command in Scale.Commands) - using (drawable.BeginAbsoluteSequence(offset + command.StartTime)) - PostProcess(command, - drawable.ScaleTo(command.StartValue) - .ScaleTo(command.EndValue, command.Duration, command.Easing)); - - if (Rotation.HasCommands) drawable.Rotation = Rotation.StartValue; - foreach (var command in Rotation.Commands) - using (drawable.BeginAbsoluteSequence(offset + command.StartTime)) - PostProcess(command, - drawable.RotateTo(command.StartValue) - .RotateTo(command.EndValue, command.Duration, command.Easing)); - - if (Colour.HasCommands) drawable.Colour = Colour.StartValue; - foreach (var command in Colour.Commands) - using (drawable.BeginAbsoluteSequence(offset + command.StartTime)) - PostProcess(command, - drawable.FadeColour(command.StartValue) - .FadeColour(command.EndValue, command.Duration, command.Easing)); - - if (Alpha.HasCommands) drawable.Alpha = Alpha.StartValue; - foreach (var command in Alpha.Commands) - using (drawable.BeginAbsoluteSequence(offset + command.StartTime)) - PostProcess(command, - drawable.FadeTo(command.StartValue) - .FadeTo(command.EndValue, command.Duration, command.Easing)); - - if (Additive.HasCommands) - drawable.BlendingMode = BlendingMode.Additive; - - var flippable = drawable as IFlippable; - if (flippable != null) - { - flippable.FlipH = FlipH.HasCommands; - flippable.FlipV = FlipV.HasCommands; - } - } - - protected virtual void PostProcess(ICommand command, TransformSequence sequence) - { + return timelineSelector(this).Commands; } } } diff --git a/osu.Game/Storyboards/SpriteDefinition.cs b/osu.Game/Storyboards/SpriteDefinition.cs index 8529d66c7f..c1a3588960 100644 --- a/osu.Game/Storyboards/SpriteDefinition.cs +++ b/osu.Game/Storyboards/SpriteDefinition.cs @@ -4,6 +4,7 @@ using OpenTK; using osu.Framework.Graphics; using osu.Game.Storyboards.Drawables; +using System; using System.Collections.Generic; using System.Linq; @@ -18,6 +19,9 @@ namespace osu.Game.Storyboards private readonly List loops = new List(); private readonly List triggers = new List(); + private delegate void DrawablePropertyInitializer(Drawable drawable, T value); + private delegate void DrawableTransformer(Drawable drawable, T value, double duration, Easing easing); + public SpriteDefinition(string path, Anchor origin, Vector2 initialPosition) { Path = path; @@ -42,11 +46,60 @@ namespace osu.Game.Storyboards public virtual Drawable CreateDrawable() => new StoryboardSprite(this); - public override void ApplyTransforms(Drawable target, double offset = 0) + public override IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0) { - base.ApplyTransforms(target, offset); - foreach (var loop in loops.OrderBy(l => l.StartTime)) - loop.ApplyTransforms(target, offset); + var result = base.GetCommands(timelineSelector, offset); + foreach (var loop in loops) + result = result.Concat(loop.GetCommands(timelineSelector, offset)); + return result; + } + + public void ApplyTransforms(Drawable drawable, IEnumerable> triggeredGroups = null) + { + applyCommands(drawable, triggeredGroups, g => g.X, (d, value) => d.X = value, (d, value, duration, easing) => d.MoveToX(value, duration, easing)); + applyCommands(drawable, triggeredGroups, g => g.Y, (d, value) => d.Y = value, (d, value, duration, easing) => d.MoveToY(value, duration, easing)); + applyCommands(drawable, triggeredGroups, g => g.Scale, (d, value) => d.Scale = value, (d, value, duration, easing) => d.ScaleTo(value, duration, easing)); + applyCommands(drawable, triggeredGroups, g => g.Rotation, (d, value) => d.Rotation = value, (d, value, duration, easing) => d.RotateTo(value, duration, easing)); + applyCommands(drawable, triggeredGroups, g => g.Colour, (d, value) => d.Colour = value, (d, value, duration, easing) => d.FadeColour(value, duration, easing)); + applyCommands(drawable, triggeredGroups, g => g.Alpha, (d, value) => d.Alpha = value, (d, value, duration, easing) => d.FadeTo(value, duration, easing)); + + if (getAggregatedCommands(g => g.Additive, triggeredGroups).Any()) + drawable.BlendingMode = BlendingMode.Additive; + + var flippable = drawable as IFlippable; + if (flippable != null) + { + flippable.FlipH = getAggregatedCommands(g => g.FlipH, triggeredGroups).Any(); + flippable.FlipV = getAggregatedCommands(g => g.FlipV, triggeredGroups).Any(); + } + } + + private void applyCommands(Drawable drawable, IEnumerable> triggeredGroups, + CommandTimelineSelector timelineSelector, DrawablePropertyInitializer initializeProperty, DrawableTransformer transform) + { + var initialized = false; + foreach (var command in getAggregatedCommands(timelineSelector, triggeredGroups)) + { + if (!initialized) + { + initializeProperty(drawable, command.StartValue); + initialized = true; + } + using (drawable.BeginAbsoluteSequence(command.StartTime)) + { + transform(drawable, command.StartValue, 0, Easing.None); + transform(drawable, command.EndValue, command.Duration, command.Easing); + } + } + } + + private IEnumerable.TypedCommand> getAggregatedCommands(CommandTimelineSelector timelineSelector, IEnumerable> triggeredGroups) + { + var commands = GetCommands(timelineSelector); + if (triggeredGroups != null) + foreach (var pair in triggeredGroups) + commands = commands.Concat(pair.Item1.GetCommands(timelineSelector, pair.Item2)); + return commands.OrderBy(l => l.StartTime); } public override string ToString()