mirror of
https://github.com/ppy/osu.git
synced 2024-12-13 03:42:57 +08:00
Apply major refactor to the storyboard commands flow structrure
This commit is contained in:
parent
07392a4d3e
commit
585ab59768
@ -175,7 +175,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
var layer = storyboard.GetLayer("Background");
|
||||
|
||||
var sprite = new StoryboardSprite(lookupName, origin, initialPosition);
|
||||
sprite.AddLoop(Time.Current, 100).Alpha.Add(Easing.None, 0, 10000, 1, 1);
|
||||
var loop = sprite.AddLoopingGroup(Time.Current, 100);
|
||||
loop.AddAlpha(0, 10000, 1, 1, Easing.None);
|
||||
|
||||
layer.Elements.Clear();
|
||||
layer.Add(sprite);
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
||||
|
||||
sprite.TimelineGroup.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1);
|
||||
sprite.Group.AddAlpha(firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1, Easing.None);
|
||||
|
||||
storyboard.GetLayer("Background").Add(sprite);
|
||||
|
||||
@ -73,17 +73,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
||||
|
||||
// these should be ignored as we have an alpha visibility blocker proceeding this command.
|
||||
sprite.TimelineGroup.Scale.Add(Easing.None, loop_start_time, -18000, Vector2.Zero, Vector2.One);
|
||||
var loopGroup = sprite.AddLoop(loop_start_time, 50);
|
||||
loopGroup.Scale.Add(Easing.None, loop_start_time, -18000, Vector2.Zero, Vector2.One);
|
||||
sprite.Group.AddScale(loop_start_time, -18000, 0, 1, Easing.None);
|
||||
var loopGroup = sprite.AddLoopingGroup(loop_start_time, 50);
|
||||
loopGroup.AddScale(loop_start_time, -18000, 0, 1, Easing.None);
|
||||
|
||||
var target = addEventToLoop ? loopGroup : sprite.TimelineGroup;
|
||||
var target = addEventToLoop ? loopGroup : sprite.Group;
|
||||
double loopRelativeOffset = addEventToLoop ? -loop_start_time : 0;
|
||||
target.Alpha.Add(Easing.None, loopRelativeOffset + firstStoryboardEvent, loopRelativeOffset + firstStoryboardEvent + 500, 0, 1);
|
||||
target.AddAlpha(loopRelativeOffset + firstStoryboardEvent, loopRelativeOffset + firstStoryboardEvent + 500, 0, 1, Easing.None);
|
||||
|
||||
// these should be ignored due to being in the future.
|
||||
sprite.TimelineGroup.Alpha.Add(Easing.None, 18000, 20000, 0, 1);
|
||||
loopGroup.Alpha.Add(Easing.None, 38000, 40000, 0, 1);
|
||||
sprite.Group.AddAlpha(18000, 20000, 0, 1, Easing.None);
|
||||
loopGroup.AddAlpha(38000, 40000, 0, 1, Easing.None);
|
||||
|
||||
storyboard.GetLayer("Background").Add(sprite);
|
||||
|
||||
|
@ -216,7 +216,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
var storyboard = new Storyboard();
|
||||
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
||||
sprite.TimelineGroup.Alpha.Add(Easing.None, 0, duration, 1, 0);
|
||||
sprite.Group.AddAlpha(0, duration, 1, 0, Easing.None);
|
||||
storyboard.GetLayer("Background").Add(sprite);
|
||||
return storyboard;
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
public void TestIntroStoryboardElement() => testLeadIn(b =>
|
||||
{
|
||||
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
||||
sprite.TimelineGroup.Alpha.Add(Easing.None, -2000, 0, 0, 1);
|
||||
sprite.Group.AddAlpha(-2000, 0, 0, 1, Easing.None);
|
||||
b.Storyboard.GetLayer("Background").Add(sprite);
|
||||
});
|
||||
|
||||
|
@ -10,6 +10,7 @@ using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Storyboards.Commands;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -17,8 +18,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
public class LegacyStoryboardDecoder : LegacyDecoder<Storyboard>
|
||||
{
|
||||
private StoryboardElementWithDuration? storyboardSprite;
|
||||
private CommandTimelineGroup? timelineGroup;
|
||||
private StoryboardSprite? storyboardSprite;
|
||||
private StoryboardCommandGroup? currentGroup;
|
||||
|
||||
private Storyboard storyboard = null!;
|
||||
|
||||
@ -165,7 +166,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
else
|
||||
{
|
||||
if (depth < 2)
|
||||
timelineGroup = storyboardSprite?.TimelineGroup;
|
||||
currentGroup = storyboardSprite?.Group;
|
||||
|
||||
string commandType = split[0];
|
||||
|
||||
@ -177,7 +178,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
double startTime = split.Length > 2 ? Parsing.ParseDouble(split[2]) : double.MinValue;
|
||||
double endTime = split.Length > 3 ? Parsing.ParseDouble(split[3]) : double.MaxValue;
|
||||
int groupNumber = split.Length > 4 ? Parsing.ParseInt(split[4]) : 0;
|
||||
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
|
||||
currentGroup = storyboardSprite?.AddTriggerGroup(triggerName, startTime, endTime, groupNumber);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -185,7 +186,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
double startTime = Parsing.ParseDouble(split[1]);
|
||||
int repeatCount = Parsing.ParseInt(split[2]);
|
||||
timelineGroup = storyboardSprite?.AddLoop(startTime, Math.Max(0, repeatCount - 1));
|
||||
currentGroup = storyboardSprite?.AddLoopingGroup(startTime, Math.Max(0, repeatCount - 1));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -204,7 +205,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
float startValue = Parsing.ParseFloat(split[4]);
|
||||
float endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
|
||||
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
|
||||
currentGroup?.AddAlpha(startTime, endTime, startValue, endValue, easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -212,7 +213,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
float startValue = Parsing.ParseFloat(split[4]);
|
||||
float endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
|
||||
timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue));
|
||||
currentGroup?.AddScale(startTime, endTime, startValue, endValue, easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -222,7 +223,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
float startY = Parsing.ParseFloat(split[5]);
|
||||
float endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
|
||||
float endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
|
||||
timelineGroup?.VectorScale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
|
||||
currentGroup?.AddVectorScale(startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY), easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -230,7 +231,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
float startValue = Parsing.ParseFloat(split[4]);
|
||||
float endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
|
||||
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue));
|
||||
currentGroup?.AddRotation(startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue), easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -240,8 +241,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
float startY = Parsing.ParseFloat(split[5]);
|
||||
float endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
|
||||
float endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
|
||||
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
|
||||
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
|
||||
currentGroup?.AddX(startTime, endTime, startX, endX, easing);
|
||||
currentGroup?.AddY(startTime, endTime, startY, endY, easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -249,7 +250,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
float startValue = Parsing.ParseFloat(split[4]);
|
||||
float endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
|
||||
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
|
||||
currentGroup?.AddX(startTime, endTime, startValue, endValue, easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -257,7 +258,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
float startValue = Parsing.ParseFloat(split[4]);
|
||||
float endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
|
||||
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
|
||||
currentGroup?.AddY(startTime, endTime, startValue, endValue, easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -269,9 +270,9 @@ namespace osu.Game.Beatmaps.Formats
|
||||
float endRed = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startRed;
|
||||
float endGreen = split.Length > 8 ? Parsing.ParseFloat(split[8]) : startGreen;
|
||||
float endBlue = split.Length > 9 ? Parsing.ParseFloat(split[9]) : startBlue;
|
||||
timelineGroup?.Colour.Add(easing, startTime, endTime,
|
||||
currentGroup?.AddColour(startTime, endTime,
|
||||
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
|
||||
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));
|
||||
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1), easing);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -282,16 +283,16 @@ namespace osu.Game.Beatmaps.Formats
|
||||
switch (type)
|
||||
{
|
||||
case "A":
|
||||
timelineGroup?.BlendingParameters.Add(easing, startTime, endTime, BlendingParameters.Additive,
|
||||
startTime == endTime ? BlendingParameters.Additive : BlendingParameters.Inherit);
|
||||
currentGroup?.AddBlendingParameters(startTime, endTime, BlendingParameters.Additive,
|
||||
startTime == endTime ? BlendingParameters.Additive : BlendingParameters.Inherit, easing);
|
||||
break;
|
||||
|
||||
case "H":
|
||||
timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime);
|
||||
currentGroup?.AddFlipH(startTime, endTime, true, startTime == endTime, easing);
|
||||
break;
|
||||
|
||||
case "V":
|
||||
timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime);
|
||||
currentGroup?.AddFlipV(startTime, endTime, true, startTime == endTime, easing);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,63 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public class CommandLoop : CommandTimelineGroup
|
||||
{
|
||||
public double LoopStartTime;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of times this loop is played back. Always greater than zero.
|
||||
/// </summary>
|
||||
public readonly int TotalIterations;
|
||||
|
||||
public override double StartTime => LoopStartTime + CommandsStartTime;
|
||||
|
||||
public override double EndTime =>
|
||||
// In an ideal world, we would multiply the command duration by TotalIterations here.
|
||||
// Unfortunately this would clash with how stable handled end times, and results in some storyboards playing outro
|
||||
// sequences for minutes or hours.
|
||||
StartTime + CommandsDuration;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new command loop.
|
||||
/// </summary>
|
||||
/// <param name="startTime">The start time of the loop.</param>
|
||||
/// <param name="repeatCount">The number of times the loop should repeat. Should be greater than zero. Zero means a single playback.</param>
|
||||
public CommandLoop(double startTime, int repeatCount)
|
||||
{
|
||||
if (repeatCount < 0) throw new ArgumentException("Repeat count must be zero or above.", nameof(repeatCount));
|
||||
|
||||
LoopStartTime = startTime;
|
||||
TotalIterations = repeatCount + 1;
|
||||
}
|
||||
|
||||
public override IEnumerable<CommandTimeline<T>.TypedCommand> GetCommands<T>(CommandTimelineSelector<T> timelineSelector, double offset = 0)
|
||||
{
|
||||
double fullLoopDuration = CommandsEndTime - CommandsStartTime;
|
||||
|
||||
foreach (var command in timelineSelector(this).Commands)
|
||||
{
|
||||
yield return new CommandTimeline<T>.TypedCommand
|
||||
{
|
||||
Easing = command.Easing,
|
||||
StartTime = offset + LoopStartTime + command.StartTime,
|
||||
EndTime = offset + LoopStartTime + command.EndTime,
|
||||
StartValue = command.StartValue,
|
||||
EndValue = command.EndValue,
|
||||
PropertyName = command.PropertyName,
|
||||
IsParameterCommand = command.IsParameterCommand,
|
||||
LoopCount = TotalIterations,
|
||||
Delay = fullLoopDuration - command.EndTime + command.StartTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"{LoopStartTime} x{TotalIterations}";
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public class CommandTimeline<T> : ICommandTimeline
|
||||
{
|
||||
private readonly List<TypedCommand> commands = new List<TypedCommand>();
|
||||
|
||||
public IEnumerable<TypedCommand> Commands => commands.OrderBy(c => c.StartTime);
|
||||
|
||||
public bool HasCommands => commands.Count > 0;
|
||||
|
||||
public double StartTime { get; private set; } = double.MaxValue;
|
||||
public double EndTime { get; private set; } = double.MinValue;
|
||||
|
||||
public T StartValue { get; private set; }
|
||||
public T EndValue { get; private set; }
|
||||
|
||||
public string PropertyName { get; }
|
||||
public bool IsParameterTimeline { get; set; }
|
||||
|
||||
public CommandTimeline(string propertyName)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
}
|
||||
|
||||
public void Add(Easing easing, double startTime, double endTime, T startValue, T endValue)
|
||||
{
|
||||
if (endTime < startTime)
|
||||
{
|
||||
endTime = startTime;
|
||||
}
|
||||
|
||||
commands.Add(new TypedCommand { Easing = easing, StartTime = startTime, EndTime = endTime, StartValue = startValue, EndValue = endValue, PropertyName = PropertyName, IsParameterCommand = IsParameterTimeline });
|
||||
|
||||
if (startTime < StartTime)
|
||||
{
|
||||
StartValue = startValue;
|
||||
StartTime = startTime;
|
||||
}
|
||||
|
||||
if (endTime > EndTime)
|
||||
{
|
||||
EndValue = endValue;
|
||||
EndTime = endTime;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"{commands.Count} command(s)";
|
||||
|
||||
public class TypedCommand : ICommand
|
||||
{
|
||||
public Easing Easing { get; set; }
|
||||
public double StartTime { get; set; }
|
||||
public double EndTime { get; set; }
|
||||
public double Duration => EndTime - StartTime;
|
||||
public string PropertyName { get; set; }
|
||||
public int LoopCount { get; set; }
|
||||
public double Delay { get; set; }
|
||||
public bool IsParameterCommand { get; set; }
|
||||
|
||||
public T StartValue;
|
||||
public T EndValue;
|
||||
|
||||
public int CompareTo(ICommand other)
|
||||
{
|
||||
int result = StartTime.CompareTo(other.StartTime);
|
||||
if (result != 0) return result;
|
||||
|
||||
return EndTime.CompareTo(other.EndTime);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"{StartTime} -> {EndTime}, {StartValue} -> {EndValue} {Easing}";
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICommandTimeline
|
||||
{
|
||||
double StartTime { get; }
|
||||
double EndTime { get; }
|
||||
bool HasCommands { get; }
|
||||
}
|
||||
|
||||
public interface ICommand : IComparable<ICommand>
|
||||
{
|
||||
Easing Easing { get; set; }
|
||||
double StartTime { get; set; }
|
||||
double EndTime { get; set; }
|
||||
double Duration { get; }
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public delegate CommandTimeline<T> CommandTimelineSelector<T>(CommandTimelineGroup commandTimelineGroup);
|
||||
|
||||
public class CommandTimelineGroup
|
||||
{
|
||||
public CommandTimeline<float> X = new CommandTimeline<float>("X");
|
||||
public CommandTimeline<float> Y = new CommandTimeline<float>("Y");
|
||||
public CommandTimeline<Vector2> Scale = new CommandTimeline<Vector2>("Scale");
|
||||
public CommandTimeline<Vector2> VectorScale = new CommandTimeline<Vector2>("VectorScale");
|
||||
public CommandTimeline<float> Rotation = new CommandTimeline<float>("Rotation");
|
||||
public CommandTimeline<ColourInfo> Colour = new CommandTimeline<ColourInfo>("Colour");
|
||||
public CommandTimeline<float> Alpha = new CommandTimeline<float>("Alpha");
|
||||
public CommandTimeline<BlendingParameters> BlendingParameters = new CommandTimeline<BlendingParameters>("Blending") { IsParameterTimeline = true };
|
||||
public CommandTimeline<bool> FlipH = new CommandTimeline<bool>("FlipH") { IsParameterTimeline = true };
|
||||
public CommandTimeline<bool> FlipV = new CommandTimeline<bool>("FlipV") { IsParameterTimeline = true };
|
||||
|
||||
private readonly ICommandTimeline[] timelines;
|
||||
|
||||
public CommandTimelineGroup()
|
||||
{
|
||||
timelines = new ICommandTimeline[]
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Scale,
|
||||
VectorScale,
|
||||
Rotation,
|
||||
Colour,
|
||||
Alpha,
|
||||
BlendingParameters,
|
||||
FlipH,
|
||||
FlipV
|
||||
};
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public double CommandsStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
double min = double.MaxValue;
|
||||
|
||||
for (int i = 0; i < timelines.Length; i++)
|
||||
min = Math.Min(min, timelines[i].StartTime);
|
||||
|
||||
return min;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public double CommandsEndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
double max = double.MinValue;
|
||||
|
||||
for (int i = 0; i < timelines.Length; i++)
|
||||
max = Math.Max(max, timelines[i].EndTime);
|
||||
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public double CommandsDuration => CommandsEndTime - CommandsStartTime;
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual double StartTime => CommandsStartTime;
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual double EndTime => CommandsEndTime;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < timelines.Length; i++)
|
||||
{
|
||||
if (timelines[i].HasCommands)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<CommandTimeline<T>.TypedCommand> GetCommands<T>(CommandTimelineSelector<T> timelineSelector, double offset = 0)
|
||||
{
|
||||
if (offset != 0)
|
||||
{
|
||||
return timelineSelector(this).Commands.Select(command =>
|
||||
new CommandTimeline<T>.TypedCommand
|
||||
{
|
||||
Easing = command.Easing,
|
||||
StartTime = offset + command.StartTime,
|
||||
EndTime = offset + command.EndTime,
|
||||
StartValue = command.StartValue,
|
||||
EndValue = command.EndValue,
|
||||
PropertyName = command.PropertyName,
|
||||
IsParameterCommand = command.IsParameterCommand
|
||||
});
|
||||
}
|
||||
|
||||
return timelineSelector(this).Commands;
|
||||
}
|
||||
}
|
||||
}
|
28
osu.Game/Storyboards/Commands/IStoryboardCommand.cs
Normal file
28
osu.Game/Storyboards/Commands/IStoryboardCommand.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public interface IStoryboardCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// The start time of the storyboard command.
|
||||
/// </summary>
|
||||
double StartTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The end time of the storyboard command.
|
||||
/// </summary>
|
||||
double EndTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the transforms described by this storyboard command to the target drawable.
|
||||
/// </summary>
|
||||
/// <param name="d">The target drawable.</param>
|
||||
/// <returns>The sequence of transforms applied to the target drawable.</returns>
|
||||
TransformSequence<Drawable> ApplyTransform(Drawable d);
|
||||
}
|
||||
}
|
19
osu.Game/Storyboards/Commands/StoryboardAlphaCommand.cs
Normal file
19
osu.Game/Storyboards/Commands/StoryboardAlphaCommand.cs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardAlphaCommand : StoryboardCommand<float>
|
||||
{
|
||||
public StoryboardAlphaCommand(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.Alpha = StartValue;
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d) => d.FadeTo(StartValue).Then().FadeTo(EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardBlendingParametersCommand : StoryboardCommand<BlendingParameters>
|
||||
{
|
||||
public StoryboardBlendingParametersCommand(double startTime, double endTime, BlendingParameters startValue, BlendingParameters endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.Blending = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.TransformTo(nameof(d.Blending), StartValue).Delay(Duration).TransformTo(nameof(d.Blending), EndValue);
|
||||
}
|
||||
}
|
20
osu.Game/Storyboards/Commands/StoryboardColourCommand.cs
Normal file
20
osu.Game/Storyboards/Commands/StoryboardColourCommand.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardColourCommand : StoryboardCommand<Color4>
|
||||
{
|
||||
public StoryboardColourCommand(double startTime, double endTime, Color4 startValue, Color4 endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.Colour = StartValue;
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d) => d.FadeColour(StartValue).Then().FadeColour(EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
54
osu.Game/Storyboards/Commands/StoryboardCommand.cs
Normal file
54
osu.Game/Storyboards/Commands/StoryboardCommand.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public abstract class StoryboardCommand<T> : IStoryboardCommand
|
||||
{
|
||||
public double StartTime { get; }
|
||||
public double EndTime { get; }
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
protected StoryboardCommand(double startTime, double endTime, T startValue, T endValue, Easing easing)
|
||||
{
|
||||
if (endTime < startTime)
|
||||
endTime = startTime;
|
||||
|
||||
StartTime = startTime;
|
||||
StartValue = startValue;
|
||||
EndTime = endTime;
|
||||
EndValue = endValue;
|
||||
Easing = easing;
|
||||
}
|
||||
|
||||
public Easing Easing { get; set; }
|
||||
public int LoopCount { get; set; }
|
||||
public double Delay { get; set; }
|
||||
|
||||
public T StartValue;
|
||||
public T EndValue;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the corresponding property in <see cref="Drawable"/> to the start value of this command.
|
||||
/// </summary>
|
||||
public abstract void SetInitialValue(Drawable d);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a corresponding property in <see cref="Drawable"/> that corresponds to this command group with the specified parameters.
|
||||
/// </summary>
|
||||
public abstract TransformSequence<Drawable> ApplyTransform(Drawable d);
|
||||
|
||||
public int CompareTo(IStoryboardCommand other)
|
||||
{
|
||||
int result = StartTime.CompareTo(other.StartTime);
|
||||
if (result != 0) return result;
|
||||
|
||||
return EndTime.CompareTo(other.EndTime);
|
||||
}
|
||||
|
||||
public override string ToString() => $"{StartTime} -> {EndTime}, {StartValue} -> {EndValue} {Easing}";
|
||||
}
|
||||
}
|
115
osu.Game/Storyboards/Commands/StoryboardCommandGroup.cs
Normal file
115
osu.Game/Storyboards/Commands/StoryboardCommandGroup.cs
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Lists;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardCommandGroup
|
||||
{
|
||||
public SortedList<StoryboardCommand<float>> X;
|
||||
public SortedList<StoryboardCommand<float>> Y;
|
||||
public SortedList<StoryboardCommand<float>> Scale;
|
||||
public SortedList<StoryboardCommand<Vector2>> VectorScale;
|
||||
public SortedList<StoryboardCommand<float>> Rotation;
|
||||
public SortedList<StoryboardCommand<Color4>> Colour;
|
||||
public SortedList<StoryboardCommand<float>> Alpha;
|
||||
public SortedList<StoryboardCommand<BlendingParameters>> BlendingParameters;
|
||||
public SortedList<StoryboardCommand<bool>> FlipH;
|
||||
public SortedList<StoryboardCommand<bool>> FlipV;
|
||||
|
||||
private readonly IReadOnlyList<IStoryboardCommand>[] lists;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the earliest start time of the commands added to this group.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public double StartTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the latest end time of the commands added to this group.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public double EndTime { get; private set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasCommands { get; private set; }
|
||||
|
||||
public StoryboardCommandGroup()
|
||||
{
|
||||
lists = new IReadOnlyList<IStoryboardCommand>[]
|
||||
{
|
||||
X = new SortedList<StoryboardCommand<float>>(),
|
||||
Y = new SortedList<StoryboardCommand<float>>(),
|
||||
Scale = new SortedList<StoryboardCommand<float>>(),
|
||||
VectorScale = new SortedList<StoryboardCommand<Vector2>>(),
|
||||
Rotation = new SortedList<StoryboardCommand<float>>(),
|
||||
Colour = new SortedList<StoryboardCommand<Color4>>(),
|
||||
Alpha = new SortedList<StoryboardCommand<float>>(),
|
||||
BlendingParameters = new SortedList<StoryboardCommand<BlendingParameters>>(),
|
||||
FlipH = new SortedList<StoryboardCommand<bool>>(),
|
||||
FlipV = new SortedList<StoryboardCommand<bool>>()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all commands contained by this group unsorted.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<IStoryboardCommand> GetAllCommands() => lists.SelectMany(l => l);
|
||||
|
||||
public void AddX(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
=> AddCommand(X, new StoryboardXCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddY(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
=> AddCommand(Y, new StoryboardYCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddScale(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
=> AddCommand(Scale, new StoryboardScaleCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddVectorScale(double startTime, double endTime, Vector2 startValue, Vector2 endValue, Easing easing)
|
||||
=> AddCommand(VectorScale, new StoryboardVectorScaleCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddRotation(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
=> AddCommand(Rotation, new StoryboardRotationCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddColour(double startTime, double endTime, Color4 startValue, Color4 endValue, Easing easing)
|
||||
=> AddCommand(Colour, new StoryboardColourCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddAlpha(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
=> AddCommand(Alpha, new StoryboardAlphaCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddBlendingParameters(double startTime, double endTime, BlendingParameters startValue, BlendingParameters endValue, Easing easing)
|
||||
=> AddCommand(BlendingParameters, new StoryboardBlendingParametersCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddFlipH(double startTime, double endTime, bool startValue, bool endValue, Easing easing)
|
||||
=> AddCommand(FlipH, new StoryboardFlipHCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
public void AddFlipV(double startTime, double endTime, bool startValue, bool endValue, Easing easing)
|
||||
=> AddCommand(FlipV, new StoryboardFlipVCommand(startTime, endTime, startValue, endValue, easing));
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given storyboard <paramref name="command"/> to the target <paramref name="list"/>.
|
||||
/// Can be overriden to apply custom effects to the given command before adding it to the list (e.g. looping or time offsets).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The value type of the target property affected by this storyboard command.</typeparam>
|
||||
protected virtual void AddCommand<T>(ICollection<StoryboardCommand<T>> list, StoryboardCommand<T> command)
|
||||
{
|
||||
list.Add(command);
|
||||
|
||||
if (command.StartTime < StartTime)
|
||||
StartTime = command.StartTime;
|
||||
|
||||
if (command.EndTime > EndTime)
|
||||
EndTime = command.EndTime;
|
||||
}
|
||||
}
|
||||
}
|
41
osu.Game/Storyboards/Commands/StoryboardCommandList.cs
Normal file
41
osu.Game/Storyboards/Commands/StoryboardCommandList.cs
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
// public class StoryboardCommandList<T> : IStoryboardCommandList
|
||||
// {
|
||||
// // todo: change to sorted list and avoid enumerable type on exposed properties?
|
||||
// private readonly List<StoryboardCommand<T>> commands = new List<StoryboardCommand<T>>();
|
||||
//
|
||||
// public IEnumerable<StoryboardCommand<T>> Commands => commands.OrderBy(c => c.StartTime);
|
||||
//
|
||||
// IEnumerable<IStoryboardCommand> IStoryboardCommandList.Commands => Commands;
|
||||
// public bool HasCommands => commands.Count > 0;
|
||||
//
|
||||
// public double StartTime { get; private set; } = double.MaxValue;
|
||||
// public double EndTime { get; private set; } = double.MinValue;
|
||||
//
|
||||
// public T? StartValue { get; private set; }
|
||||
// public T? EndValue { get; private set; }
|
||||
//
|
||||
// public void Add(StoryboardCommand<T> command)
|
||||
// {
|
||||
// commands.Add(command);
|
||||
//
|
||||
// if (command.StartTime < StartTime)
|
||||
// {
|
||||
// StartValue = command.StartValue;
|
||||
// StartTime = command.StartTime;
|
||||
// }
|
||||
//
|
||||
// if (command.EndTime > EndTime)
|
||||
// {
|
||||
// EndValue = command.EndValue;
|
||||
// EndTime = command.EndTime;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public override string ToString() => $"{commands.Count} command(s)";
|
||||
// }
|
||||
}
|
23
osu.Game/Storyboards/Commands/StoryboardFlipHCommand.cs
Normal file
23
osu.Game/Storyboards/Commands/StoryboardFlipHCommand.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardFlipHCommand : StoryboardCommand<bool>
|
||||
{
|
||||
public StoryboardFlipHCommand(double startTime, double endTime, bool startValue, bool endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => ((IDrawableStoryboardElement)d).FlipH = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.TransformTo(nameof(IDrawableStoryboardElement.FlipH), StartValue).Delay(Duration)
|
||||
.TransformTo(nameof(IDrawableStoryboardElement.FlipH), EndValue);
|
||||
}
|
||||
}
|
23
osu.Game/Storyboards/Commands/StoryboardFlipVCommand.cs
Normal file
23
osu.Game/Storyboards/Commands/StoryboardFlipVCommand.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardFlipVCommand : StoryboardCommand<bool>
|
||||
{
|
||||
public StoryboardFlipVCommand(double startTime, double endTime, bool startValue, bool endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => ((IDrawableStoryboardElement)d).FlipV = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.TransformTo(nameof(IDrawableStoryboardElement.FlipV), StartValue).Delay(Duration)
|
||||
.TransformTo(nameof(IDrawableStoryboardElement.FlipV), EndValue);
|
||||
}
|
||||
}
|
71
osu.Game/Storyboards/Commands/StoryboardLoopingGroup.cs
Normal file
71
osu.Game/Storyboards/Commands/StoryboardLoopingGroup.cs
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardLoopingGroup : StoryboardCommandGroup
|
||||
{
|
||||
public double LoopStartTime;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of times this loop is played back. Always greater than zero.
|
||||
/// </summary>
|
||||
public readonly int TotalIterations;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new command loop.
|
||||
/// </summary>
|
||||
/// <param name="startTime">The start time of the loop.</param>
|
||||
/// <param name="repeatCount">The number of times the loop should repeat. Should be greater than zero. Zero means a single playback.</param>
|
||||
public StoryboardLoopingGroup(double startTime, int repeatCount)
|
||||
{
|
||||
if (repeatCount < 0) throw new ArgumentException("Repeat count must be zero or above.", nameof(repeatCount));
|
||||
|
||||
LoopStartTime = startTime;
|
||||
TotalIterations = repeatCount + 1;
|
||||
}
|
||||
|
||||
protected override void AddCommand<T>(ICollection<StoryboardCommand<T>> list, StoryboardCommand<T> command)
|
||||
{
|
||||
// todo: this is broke!
|
||||
double fullLoopDuration = EndTime - StartTime;
|
||||
double loopDelay = fullLoopDuration - command.EndTime + command.StartTime;
|
||||
base.AddCommand(list, new StoryboardLoopingCommand<T>(command, LoopStartTime, TotalIterations, loopDelay));
|
||||
}
|
||||
|
||||
public override string ToString() => $"{LoopStartTime} x{TotalIterations}";
|
||||
|
||||
private class StoryboardLoopingCommand<T> : StoryboardCommand<T>
|
||||
{
|
||||
private readonly StoryboardCommand<T> command;
|
||||
private readonly int loopCount;
|
||||
private readonly double loopDelay;
|
||||
|
||||
public StoryboardLoopingCommand(StoryboardCommand<T> command, double loopStartTime, int loopCount, double loopDelay)
|
||||
// In an ideal world, we would multiply the command duration by TotalIterations in command end time.
|
||||
// Unfortunately this would clash with how stable handled end times, and results in some storyboards playing outro
|
||||
// sequences for minutes or hours.
|
||||
: base(loopStartTime + command.StartTime, loopStartTime + command.EndTime, command.StartValue, command.EndValue, command.Easing)
|
||||
{
|
||||
this.command = command;
|
||||
this.loopCount = loopCount;
|
||||
this.loopDelay = loopDelay;
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => command.SetInitialValue(d);
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
{
|
||||
if (loopCount == 0)
|
||||
return command.ApplyTransform(d);
|
||||
|
||||
return command.ApplyTransform(d).Loop(loopDelay, loopCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
osu.Game/Storyboards/Commands/StoryboardRotationCommand.cs
Normal file
21
osu.Game/Storyboards/Commands/StoryboardRotationCommand.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardRotationCommand : StoryboardCommand<float>
|
||||
{
|
||||
public StoryboardRotationCommand(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.Rotation = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.RotateTo(StartValue).Then().RotateTo(EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
22
osu.Game/Storyboards/Commands/StoryboardScaleCommand.cs
Normal file
22
osu.Game/Storyboards/Commands/StoryboardScaleCommand.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardScaleCommand : StoryboardCommand<float>
|
||||
{
|
||||
public StoryboardScaleCommand(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.Scale = new Vector2(StartValue);
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.ScaleTo(StartValue).Then().ScaleTo(EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class CommandTrigger : CommandTimelineGroup
|
||||
// todo: this is not implemented and has never been, keep that in mind.
|
||||
public class StoryboardTriggerGroup : StoryboardCommandGroup
|
||||
{
|
||||
public string TriggerName;
|
||||
public double TriggerStartTime;
|
||||
public double TriggerEndTime;
|
||||
public int GroupNumber;
|
||||
|
||||
public CommandTrigger(string triggerName, double startTime, double endTime, int groupNumber)
|
||||
public StoryboardTriggerGroup(string triggerName, double startTime, double endTime, int groupNumber)
|
||||
{
|
||||
TriggerName = triggerName;
|
||||
TriggerStartTime = startTime;
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardVectorScaleCommand : StoryboardCommand<Vector2>
|
||||
{
|
||||
public StoryboardVectorScaleCommand(double startTime, double endTime, Vector2 startValue, Vector2 endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => ((IDrawableStoryboardElement)d).VectorScale = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.TransformTo(nameof(IDrawableStoryboardElement.VectorScale), StartValue).Then()
|
||||
.TransformTo(nameof(IDrawableStoryboardElement.VectorScale), EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
21
osu.Game/Storyboards/Commands/StoryboardXCommand.cs
Normal file
21
osu.Game/Storyboards/Commands/StoryboardXCommand.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardXCommand : StoryboardCommand<float>
|
||||
{
|
||||
public StoryboardXCommand(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.X = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.MoveToX(StartValue).Then().MoveToX(EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
21
osu.Game/Storyboards/Commands/StoryboardYCommand.cs
Normal file
21
osu.Game/Storyboards/Commands/StoryboardYCommand.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Storyboards.Commands
|
||||
{
|
||||
public class StoryboardYCommand : StoryboardCommand<float>
|
||||
{
|
||||
public StoryboardYCommand(double startTime, double endTime, float startValue, float endValue, Easing easing)
|
||||
: base(startTime, endTime, startValue, endValue, easing)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetInitialValue(Drawable d) => d.Y = StartValue;
|
||||
|
||||
public override TransformSequence<Drawable> ApplyTransform(Drawable d)
|
||||
=> d.MoveToY(StartValue).Then().MoveToY(EndValue, Duration, Easing);
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Storyboards.Drawables
|
||||
{
|
||||
public interface IDrawableStoryboardElement : ITransformable
|
||||
public interface IDrawableStoryboardElement : IDrawable
|
||||
{
|
||||
bool FlipH { get; set; }
|
||||
bool FlipV { get; set; }
|
||||
|
@ -7,7 +7,7 @@ using osu.Game.Storyboards.Drawables;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public class StoryboardAnimation : StoryboardElementWithDuration<DrawableStoryboardAnimation>
|
||||
public class StoryboardAnimation : StoryboardSprite
|
||||
{
|
||||
public int FrameCount;
|
||||
public double FrameDelay;
|
||||
@ -21,7 +21,7 @@ namespace osu.Game.Storyboards
|
||||
LoopType = loopType;
|
||||
}
|
||||
|
||||
public override DrawableStoryboardAnimation CreateStoryboardDrawable() => new DrawableStoryboardAnimation(this);
|
||||
public override Drawable CreateDrawable() => new DrawableStoryboardAnimation(this);
|
||||
}
|
||||
|
||||
public enum AnimationLoopType
|
||||
|
@ -1,236 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public abstract class StoryboardElementWithDuration : IStoryboardElementWithDuration
|
||||
{
|
||||
protected readonly List<CommandLoop> Loops = new List<CommandLoop>();
|
||||
private readonly List<CommandTrigger> triggers = new List<CommandTrigger>();
|
||||
|
||||
public string Path { get; }
|
||||
public bool IsDrawable => HasCommands;
|
||||
|
||||
public Anchor Origin;
|
||||
public Vector2 InitialPosition;
|
||||
|
||||
public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup();
|
||||
|
||||
public double StartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
// To get the initial start time, we need to check whether the first alpha command to exist (across all loops) has a StartValue of zero.
|
||||
// A StartValue of zero governs, above all else, the first valid display time of a sprite.
|
||||
//
|
||||
// You can imagine that the first command of each type decides that type's start value, so if the initial alpha is zero,
|
||||
// anything before that point can be ignored (the sprite is not visible after all).
|
||||
var alphaCommands = new List<(double startTime, bool isZeroStartValue)>();
|
||||
|
||||
var command = TimelineGroup.Alpha.Commands.FirstOrDefault();
|
||||
if (command != null) alphaCommands.Add((command.StartTime, command.StartValue == 0));
|
||||
|
||||
foreach (var loop in Loops)
|
||||
{
|
||||
command = loop.Alpha.Commands.FirstOrDefault();
|
||||
if (command != null) alphaCommands.Add((command.StartTime + loop.LoopStartTime, command.StartValue == 0));
|
||||
}
|
||||
|
||||
if (alphaCommands.Count > 0)
|
||||
{
|
||||
var firstAlpha = alphaCommands.MinBy(t => t.startTime);
|
||||
|
||||
if (firstAlpha.isZeroStartValue)
|
||||
return firstAlpha.startTime;
|
||||
}
|
||||
|
||||
return EarliestTransformTime;
|
||||
}
|
||||
}
|
||||
|
||||
public double EarliestTransformTime
|
||||
{
|
||||
get
|
||||
{
|
||||
// If we got to this point, either no alpha commands were present, or the earliest had a non-zero start value.
|
||||
// The sprite's StartTime will be determined by the earliest command, regardless of type.
|
||||
double earliestStartTime = TimelineGroup.StartTime;
|
||||
foreach (var l in Loops)
|
||||
earliestStartTime = Math.Min(earliestStartTime, l.StartTime);
|
||||
return earliestStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
double latestEndTime = TimelineGroup.EndTime;
|
||||
|
||||
foreach (var l in Loops)
|
||||
latestEndTime = Math.Max(latestEndTime, l.EndTime);
|
||||
|
||||
return latestEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTimeForDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
double latestEndTime = TimelineGroup.EndTime;
|
||||
|
||||
foreach (var l in Loops)
|
||||
latestEndTime = Math.Max(latestEndTime, l.StartTime + l.CommandsDuration * l.TotalIterations);
|
||||
|
||||
return latestEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCommands => TimelineGroup.HasCommands || Loops.Any(l => l.HasCommands);
|
||||
|
||||
protected StoryboardElementWithDuration(string path, Anchor origin, Vector2 initialPosition)
|
||||
{
|
||||
Path = path;
|
||||
Origin = origin;
|
||||
InitialPosition = initialPosition;
|
||||
}
|
||||
|
||||
public abstract Drawable CreateDrawable();
|
||||
|
||||
public CommandLoop AddLoop(double startTime, int repeatCount)
|
||||
{
|
||||
var loop = new CommandLoop(startTime, repeatCount);
|
||||
Loops.Add(loop);
|
||||
return loop;
|
||||
}
|
||||
|
||||
public CommandTrigger AddTrigger(string triggerName, double startTime, double endTime, int groupNumber)
|
||||
{
|
||||
var trigger = new CommandTrigger(triggerName, startTime, endTime, groupNumber);
|
||||
triggers.Add(trigger);
|
||||
return trigger;
|
||||
}
|
||||
|
||||
protected IEnumerable<CommandTimeline<T>.TypedCommand> GetCommands<T>(CommandTimelineSelector<T> timelineSelector, IEnumerable<Tuple<CommandTimelineGroup, double>>? triggeredGroups)
|
||||
{
|
||||
var commands = TimelineGroup.GetCommands(timelineSelector);
|
||||
foreach (var loop in Loops)
|
||||
commands = commands.Concat(loop.GetCommands(timelineSelector));
|
||||
|
||||
if (triggeredGroups != null)
|
||||
{
|
||||
foreach (var pair in triggeredGroups)
|
||||
commands = commands.Concat(pair.Item1.GetCommands(timelineSelector, pair.Item2));
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"{Path}, {Origin}, {InitialPosition}";
|
||||
}
|
||||
|
||||
public abstract class StoryboardElementWithDuration<U> : StoryboardElementWithDuration
|
||||
where U : Drawable, IDrawableStoryboardElement
|
||||
{
|
||||
private delegate void DrawablePropertyInitializer<in T>(U drawable, T value);
|
||||
|
||||
protected StoryboardElementWithDuration(string path, Anchor origin, Vector2 initialPosition)
|
||||
: base(path, origin, initialPosition)
|
||||
{
|
||||
}
|
||||
|
||||
public override Drawable CreateDrawable() => CreateStoryboardDrawable();
|
||||
|
||||
public abstract U CreateStoryboardDrawable();
|
||||
|
||||
public void ApplyTransforms(U drawable, IEnumerable<Tuple<CommandTimelineGroup, double>>? triggeredGroups = null)
|
||||
{
|
||||
// For performance reasons, we need to apply the commands in order by start time. Not doing so will cause many functions to be interleaved, resulting in O(n^2) complexity.
|
||||
// To achieve this, commands are "generated" as pairs of (command, initFunc, transformFunc) and batched into a contiguous list
|
||||
// The list is then stably-sorted (to preserve command order), and applied to the drawable sequentially.
|
||||
|
||||
List<IGeneratedCommand<U>> generated = new List<IGeneratedCommand<U>>();
|
||||
|
||||
generateCommands(generated, GetCommands(g => g.X, triggeredGroups), (d, value) => d.X = value);
|
||||
generateCommands(generated, GetCommands(g => g.Y, triggeredGroups), (d, value) => d.Y = value);
|
||||
generateCommands(generated, GetCommands(g => g.Scale, triggeredGroups), (d, value) => d.Scale = value);
|
||||
generateCommands(generated, GetCommands(g => g.Rotation, triggeredGroups), (d, value) => d.Rotation = value);
|
||||
generateCommands(generated, GetCommands(g => g.Colour, triggeredGroups), (d, value) => d.Colour = value);
|
||||
generateCommands(generated, GetCommands(g => g.Alpha, triggeredGroups), (d, value) => d.Alpha = value);
|
||||
generateCommands(generated, GetCommands(g => g.BlendingParameters, triggeredGroups), (d, value) => d.Blending = value, false);
|
||||
generateCommands(generated, GetCommands(g => g.VectorScale, triggeredGroups), (d, value) => d.VectorScale = value);
|
||||
generateCommands(generated, GetCommands(g => g.FlipH, triggeredGroups), (d, value) => d.FlipH = value, false);
|
||||
generateCommands(generated, GetCommands(g => g.FlipV, triggeredGroups), (d, value) => d.FlipV = value, false);
|
||||
|
||||
foreach (var command in generated.OrderBy(g => g.StartTime))
|
||||
command.ApplyTo(drawable);
|
||||
}
|
||||
|
||||
private void generateCommands<T>(List<IGeneratedCommand<U>> resultList, IEnumerable<CommandTimeline<T>.TypedCommand> commands,
|
||||
DrawablePropertyInitializer<T> initializeProperty, bool alwaysInitialize = true)
|
||||
{
|
||||
bool initialized = false;
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
DrawablePropertyInitializer<T>? initFunc = null;
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
if (alwaysInitialize || command.StartTime == command.EndTime)
|
||||
initFunc = initializeProperty;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
resultList.Add(new GeneratedCommand<T, U>(command, initFunc));
|
||||
}
|
||||
}
|
||||
|
||||
private interface IGeneratedCommand<in TDrawable>
|
||||
where TDrawable : U
|
||||
{
|
||||
double StartTime { get; }
|
||||
|
||||
void ApplyTo(TDrawable drawable);
|
||||
}
|
||||
|
||||
private readonly struct GeneratedCommand<T, TDrawable> : IGeneratedCommand<TDrawable>
|
||||
where TDrawable : U
|
||||
{
|
||||
public double StartTime => command.StartTime;
|
||||
|
||||
private readonly DrawablePropertyInitializer<T>? initializeProperty;
|
||||
private readonly CommandTimeline<T>.TypedCommand command;
|
||||
|
||||
public GeneratedCommand(CommandTimeline<T>.TypedCommand command, DrawablePropertyInitializer<T>? initializeProperty)
|
||||
{
|
||||
this.command = command;
|
||||
this.initializeProperty = initializeProperty;
|
||||
}
|
||||
|
||||
public void ApplyTo(TDrawable drawable)
|
||||
{
|
||||
initializeProperty?.Invoke(drawable, command.StartValue);
|
||||
|
||||
using (drawable.BeginAbsoluteSequence(command.StartTime))
|
||||
{
|
||||
var sequence = command.IsParameterCommand
|
||||
? drawable.TransformTo(command.PropertyName, command.StartValue).Delay(command.Duration).TransformTo(command.PropertyName, command.EndValue)
|
||||
: drawable.TransformTo(command.PropertyName, command.StartValue).Then().TransformTo(command.PropertyName, command.EndValue, command.Duration, command.Easing);
|
||||
|
||||
if (command.LoopCount > 0)
|
||||
sequence.Loop(command.Delay, command.LoopCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,164 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Storyboards.Commands;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public class StoryboardSprite : StoryboardElementWithDuration<DrawableStoryboardSprite>
|
||||
public class StoryboardSprite : IStoryboardElementWithDuration
|
||||
{
|
||||
public StoryboardSprite(string path, Anchor origin, Vector2 initialPosition)
|
||||
: base(path, origin, initialPosition)
|
||||
private readonly List<StoryboardLoopingGroup> loopGroups = new List<StoryboardLoopingGroup>();
|
||||
private readonly List<StoryboardTriggerGroup> triggerGroups = new List<StoryboardTriggerGroup>();
|
||||
|
||||
public string Path { get; }
|
||||
public bool IsDrawable => HasCommands;
|
||||
|
||||
public Anchor Origin;
|
||||
public Vector2 InitialPosition;
|
||||
|
||||
public readonly StoryboardCommandGroup Group = new StoryboardCommandGroup();
|
||||
|
||||
public double StartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
// To get the initial start time, we need to check whether the first alpha command to exist (across all loops) has a StartValue of zero.
|
||||
// A StartValue of zero governs, above all else, the first valid display time of a sprite.
|
||||
//
|
||||
// You can imagine that the first command of each type decides that type's start value, so if the initial alpha is zero,
|
||||
// anything before that point can be ignored (the sprite is not visible after all).
|
||||
var alphaCommands = new List<(double startTime, bool isZeroStartValue)>();
|
||||
|
||||
var command = Group.Alpha.FirstOrDefault();
|
||||
if (command != null) alphaCommands.Add((command.StartTime, command.StartValue == 0));
|
||||
|
||||
foreach (var loop in loopGroups)
|
||||
{
|
||||
command = loop.Alpha.FirstOrDefault();
|
||||
if (command != null) alphaCommands.Add((command.StartTime + loop.LoopStartTime, command.StartValue == 0));
|
||||
}
|
||||
|
||||
if (alphaCommands.Count > 0)
|
||||
{
|
||||
var firstAlpha = alphaCommands.MinBy(t => t.startTime);
|
||||
|
||||
if (firstAlpha.isZeroStartValue)
|
||||
return firstAlpha.startTime;
|
||||
}
|
||||
|
||||
return EarliestTransformTime;
|
||||
}
|
||||
}
|
||||
|
||||
public override DrawableStoryboardSprite CreateStoryboardDrawable() => new DrawableStoryboardSprite(this);
|
||||
public double EarliestTransformTime
|
||||
{
|
||||
get
|
||||
{
|
||||
// If we got to this point, either no alpha commands were present, or the earliest had a non-zero start value.
|
||||
// The sprite's StartTime will be determined by the earliest command, regardless of type.
|
||||
double earliestStartTime = Group.StartTime;
|
||||
foreach (var l in loopGroups)
|
||||
earliestStartTime = Math.Min(earliestStartTime, l.StartTime);
|
||||
return earliestStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
double latestEndTime = Group.EndTime;
|
||||
|
||||
foreach (var l in loopGroups)
|
||||
latestEndTime = Math.Max(latestEndTime, l.EndTime);
|
||||
|
||||
return latestEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTimeForDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
double latestEndTime = Group.StartTime;
|
||||
|
||||
foreach (var l in loopGroups)
|
||||
latestEndTime = Math.Max(latestEndTime, l.StartTime + l.Duration * l.TotalIterations);
|
||||
|
||||
return latestEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCommands => Group.HasCommands || loopGroups.Any(l => l.HasCommands);
|
||||
|
||||
public StoryboardSprite(string path, Anchor origin, Vector2 initialPosition)
|
||||
{
|
||||
Path = path;
|
||||
Origin = origin;
|
||||
InitialPosition = initialPosition;
|
||||
}
|
||||
|
||||
public virtual Drawable CreateDrawable() => new DrawableStoryboardSprite(this);
|
||||
|
||||
public StoryboardLoopingGroup AddLoopingGroup(double loopStartTime, int repeatCount)
|
||||
{
|
||||
var loop = new StoryboardLoopingGroup(loopStartTime, repeatCount);
|
||||
loopGroups.Add(loop);
|
||||
return loop;
|
||||
}
|
||||
|
||||
public StoryboardTriggerGroup AddTriggerGroup(string triggerName, double startTime, double endTime, int groupNumber)
|
||||
{
|
||||
var trigger = new StoryboardTriggerGroup(triggerName, startTime, endTime, groupNumber);
|
||||
triggerGroups.Add(trigger);
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Path}, {Origin}, {InitialPosition}";
|
||||
|
||||
public void ApplyTransforms(Drawable drawable, IEnumerable<Tuple<StoryboardCommandGroup, double>>? triggeredGroups = null)
|
||||
{
|
||||
// For performance reasons, we need to apply the commands in order by start time. Not doing so will cause many functions to be interleaved, resulting in O(n^2) complexity.
|
||||
|
||||
var commands = Group.GetAllCommands();
|
||||
commands = commands.Concat(loopGroups.SelectMany(l => l.GetAllCommands()));
|
||||
|
||||
// todo: triggers are not implemented yet.
|
||||
// if (triggeredGroups != null)
|
||||
// commands = commands.Concat(triggeredGroups.SelectMany(tuple => tuple.Item1.GetAllCommands(tuple.Item2)));
|
||||
|
||||
foreach (var command in commands.OrderBy(c => c.StartTime))
|
||||
{
|
||||
using (drawable.BeginAbsoluteSequence(command.StartTime))
|
||||
command.ApplyTransform(drawable);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: need to revisit property initialisation. apparently it has to be done per first command of every affected property (transforms are supposed to do that already?).
|
||||
// private void generateCommands<T>(List<IGeneratedCommand> resultList, IEnumerable<StoryboardCommandList<T>.TypedCommand> commands,
|
||||
// DrawablePropertyInitializer<T> initializeProperty, DrawableTransform<T> transform, bool alwaysInitialize = true)
|
||||
// {
|
||||
// bool initialized = false;
|
||||
//
|
||||
// foreach (var command in commands)
|
||||
// {
|
||||
// DrawablePropertyInitializer<T>? initFunc = null;
|
||||
//
|
||||
// if (!initialized)
|
||||
// {
|
||||
// if (alwaysInitialize || command.StartTime == command.EndTime)
|
||||
// initFunc = initializeProperty;
|
||||
// initialized = true;
|
||||
// }
|
||||
//
|
||||
// resultList.Add(new GeneratedCommand<T>(command, initFunc, transform));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user