mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 03:22:55 +08:00
Merge pull request #11990 from peppy/fix-storyboard-alpha-start-time-woes
Fix storyboard commands occurring before the earliest point of visibility delaying gameplay
This commit is contained in:
commit
d8db29de35
osu.Game.Tests/Visual/Gameplay
osu.Game/Storyboards
@ -46,11 +46,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[TestCase(0, 0)]
|
[TestCase(0, 0)]
|
||||||
[TestCase(-1000, -1000)]
|
[TestCase(-1000, -1000)]
|
||||||
[TestCase(-10000, -10000)]
|
[TestCase(-10000, -10000)]
|
||||||
public void TestStoryboardProducesCorrectStartTime(double firstStoryboardEvent, double expectedStartTime)
|
public void TestStoryboardProducesCorrectStartTimeSimpleAlpha(double firstStoryboardEvent, double expectedStartTime)
|
||||||
{
|
{
|
||||||
var storyboard = new Storyboard();
|
var storyboard = new Storyboard();
|
||||||
|
|
||||||
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
||||||
|
|
||||||
sprite.TimelineGroup.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1);
|
sprite.TimelineGroup.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1);
|
||||||
|
|
||||||
storyboard.GetLayer("Background").Add(sprite);
|
storyboard.GetLayer("Background").Add(sprite);
|
||||||
@ -64,6 +65,43 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(1000, 0, false)]
|
||||||
|
[TestCase(0, 0, false)]
|
||||||
|
[TestCase(-1000, -1000, false)]
|
||||||
|
[TestCase(-10000, -10000, false)]
|
||||||
|
[TestCase(1000, 0, true)]
|
||||||
|
[TestCase(0, 0, true)]
|
||||||
|
[TestCase(-1000, -1000, true)]
|
||||||
|
[TestCase(-10000, -10000, true)]
|
||||||
|
public void TestStoryboardProducesCorrectStartTimeFadeInAfterOtherEvents(double firstStoryboardEvent, double expectedStartTime, bool addEventToLoop)
|
||||||
|
{
|
||||||
|
var storyboard = new Storyboard();
|
||||||
|
|
||||||
|
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, -20000, -18000, 0, 1);
|
||||||
|
var loopGroup = sprite.AddLoop(-20000, 50);
|
||||||
|
loopGroup.Scale.Add(Easing.None, -20000, -18000, 0, 1);
|
||||||
|
|
||||||
|
var target = addEventToLoop ? loopGroup : sprite.TimelineGroup;
|
||||||
|
target.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1);
|
||||||
|
|
||||||
|
// 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, 18000, 20000, 0, 1);
|
||||||
|
|
||||||
|
storyboard.GetLayer("Background").Add(sprite);
|
||||||
|
|
||||||
|
loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard);
|
||||||
|
|
||||||
|
AddAssert($"first frame is {expectedStartTime}", () =>
|
||||||
|
{
|
||||||
|
Debug.Assert(player.FirstFrameClockTime != null);
|
||||||
|
return Precision.AlmostEquals(player.FirstFrameClockTime.Value, expectedStartTime, lenience_ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||||
{
|
{
|
||||||
AddStep("create player", () =>
|
AddStep("create player", () =>
|
||||||
|
@ -45,11 +45,30 @@ namespace osu.Game.Storyboards
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the earliest visible time. Will be null unless this group's first <see cref="Alpha"/> command has a start value of zero.
|
||||||
|
/// </summary>
|
||||||
|
public double? EarliestDisplayedTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var first = Alpha.Commands.FirstOrDefault();
|
||||||
|
|
||||||
|
return first?.StartValue == 0 ? first.StartTime : (double?)null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public double CommandsStartTime
|
public double CommandsStartTime
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
// if the first alpha command starts at zero it should be given priority over anything else.
|
||||||
|
// this is due to it creating a state where the target is not present before that time, causing any other events to not be visible.
|
||||||
|
var earliestDisplay = EarliestDisplayedTime;
|
||||||
|
if (earliestDisplay != null)
|
||||||
|
return earliestDisplay.Value;
|
||||||
|
|
||||||
double min = double.MaxValue;
|
double min = double.MaxValue;
|
||||||
|
|
||||||
for (int i = 0; i < timelines.Length; i++)
|
for (int i = 0; i < timelines.Length; i++)
|
||||||
|
@ -24,13 +24,46 @@ namespace osu.Game.Storyboards
|
|||||||
|
|
||||||
public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup();
|
public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup();
|
||||||
|
|
||||||
public double StartTime => Math.Min(
|
public double StartTime
|
||||||
TimelineGroup.HasCommands ? TimelineGroup.CommandsStartTime : double.MaxValue,
|
{
|
||||||
loops.Any(l => l.HasCommands) ? loops.Where(l => l.HasCommands).Min(l => l.StartTime) : double.MaxValue);
|
get
|
||||||
|
{
|
||||||
|
// check for presence affecting commands as an initial pass.
|
||||||
|
double earliestStartTime = TimelineGroup.EarliestDisplayedTime ?? double.MaxValue;
|
||||||
|
|
||||||
public double EndTime => Math.Max(
|
foreach (var l in loops)
|
||||||
TimelineGroup.HasCommands ? TimelineGroup.CommandsEndTime : double.MinValue,
|
{
|
||||||
loops.Any(l => l.HasCommands) ? loops.Where(l => l.HasCommands).Max(l => l.EndTime) : double.MinValue);
|
if (!(l.EarliestDisplayedTime is double lEarliest))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
earliestStartTime = Math.Min(earliestStartTime, lEarliest);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (earliestStartTime < double.MaxValue)
|
||||||
|
return earliestStartTime;
|
||||||
|
|
||||||
|
// if an alpha-affecting command was not found, use the earliest of any command.
|
||||||
|
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 bool HasCommands => TimelineGroup.HasCommands || loops.Any(l => l.HasCommands);
|
public bool HasCommands => TimelineGroup.HasCommands || loops.Any(l => l.HasCommands);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user