mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 18:42:56 +08:00
Merge remote-tracking branch 'upstream/master' into beatmap-overlay-mod-selector-new
This commit is contained in:
commit
880f7ddca7
@ -19,6 +19,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
@ -75,14 +76,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) => new CustomSkinWorkingBeatmap(beatmap, Clock, audio, testBeatmapSkin);
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, audio, testBeatmapSkin);
|
||||
|
||||
public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
|
||||
{
|
||||
private readonly ISkinSource skin;
|
||||
|
||||
public CustomSkinWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin)
|
||||
: base(beatmap, frameBasedClock, audio)
|
||||
public CustomSkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin)
|
||||
: base(beatmap, storyboard, frameBasedClock, audio)
|
||||
{
|
||||
this.skin = skin;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Storyboards;
|
||||
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
@ -28,9 +29,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
protected override bool Autoplay => true;
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
{
|
||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
track = (TrackVirtualManual)working.Track;
|
||||
return working;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Storyboards;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
@ -29,9 +30,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
}
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
{
|
||||
var working = base.CreateWorkingBeatmap(beatmap);
|
||||
var working = base.CreateWorkingBeatmap(beatmap, storyboard);
|
||||
|
||||
track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track;
|
||||
|
||||
|
@ -17,6 +17,7 @@ using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Storyboards;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
@ -35,9 +36,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private Track track;
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
{
|
||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
track = working.Track;
|
||||
return working;
|
||||
}
|
||||
|
113
osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
Normal file
113
osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
Normal file
@ -0,0 +1,113 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneLeadIn : RateAdjustedBeatmapTestScene
|
||||
{
|
||||
private LeadInPlayer player;
|
||||
|
||||
private const double lenience_ms = 10;
|
||||
|
||||
private const double first_hit_object = 2170;
|
||||
|
||||
[TestCase(1000, 0)]
|
||||
[TestCase(2000, 0)]
|
||||
[TestCase(3000, first_hit_object - 3000)]
|
||||
[TestCase(10000, first_hit_object - 10000)]
|
||||
public void TestLeadInProducesCorrectStartTime(double leadIn, double expectedStartTime)
|
||||
{
|
||||
loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo = { AudioLeadIn = leadIn }
|
||||
});
|
||||
|
||||
AddAssert($"first frame is {expectedStartTime}", () =>
|
||||
{
|
||||
Debug.Assert(player.FirstFrameClockTime != null);
|
||||
return Precision.AlmostEquals(player.FirstFrameClockTime.Value, expectedStartTime, lenience_ms);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1000, 0)]
|
||||
[TestCase(0, 0)]
|
||||
[TestCase(-1000, -1000)]
|
||||
[TestCase(-10000, -10000)]
|
||||
public void TestStoryboardProducesCorrectStartTime(double firstStoryboardEvent, double expectedStartTime)
|
||||
{
|
||||
var storyboard = new Storyboard();
|
||||
|
||||
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
|
||||
sprite.TimelineGroup.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 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)
|
||||
{
|
||||
AddStep("create player", () =>
|
||||
{
|
||||
Beatmap.Value = CreateWorkingBeatmap(beatmap, storyboard);
|
||||
LoadScreen(player = new LeadInPlayer());
|
||||
});
|
||||
|
||||
AddUntilStep("player loaded", () => player.IsLoaded && player.Alpha == 1);
|
||||
}
|
||||
|
||||
private class LeadInPlayer : TestPlayer
|
||||
{
|
||||
public LeadInPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
public double? FirstFrameClockTime;
|
||||
|
||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||
|
||||
public double GameplayStartTime => DrawableRuleset.GameplayStartTime;
|
||||
|
||||
public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime;
|
||||
|
||||
public double GameplayClockTime => GameplayClockContainer.GameplayClock.CurrentTime;
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
if (!FirstFrameClockTime.HasValue)
|
||||
{
|
||||
FirstFrameClockTime = GameplayClockContainer.GameplayClock.CurrentTime;
|
||||
AddInternal(new OsuSpriteText
|
||||
{
|
||||
Text = $"GameplayStartTime: {DrawableRuleset.GameplayStartTime} "
|
||||
+ $"FirstHitObjectTime: {FirstHitObjectTime} "
|
||||
+ $"LeadInTime: {Beatmap.Value.BeatmapInfo.AudioLeadIn} "
|
||||
+ $"FirstFrameClockTime: {FirstFrameClockTime}"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using osu.Framework.Lists;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Storyboards;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
@ -42,9 +43,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
}
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
{
|
||||
var working = base.CreateWorkingBeatmap(beatmap);
|
||||
var working = base.CreateWorkingBeatmap(beatmap, storyboard);
|
||||
workingWeakReferences.Add(working);
|
||||
return working;
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -18,25 +18,37 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
private SkipOverlay skip;
|
||||
private int requestCount;
|
||||
|
||||
private double increment;
|
||||
|
||||
private GameplayClockContainer gameplayClockContainer;
|
||||
private GameplayClock gameplayClock;
|
||||
|
||||
private const double skip_time = 6000;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
requestCount = 0;
|
||||
Child = new Container
|
||||
increment = skip_time;
|
||||
|
||||
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new Mod[] { }, 0)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = new FramedOffsetClock(Clock)
|
||||
{
|
||||
Offset = -Clock.CurrentTime,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
skip = new SkipOverlay(6000)
|
||||
skip = new SkipOverlay(skip_time)
|
||||
{
|
||||
RequestSeek = _ => requestCount++
|
||||
RequestSkip = () =>
|
||||
{
|
||||
requestCount++;
|
||||
gameplayClockContainer.Seek(gameplayClock.CurrentTime + increment);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
gameplayClockContainer.Start();
|
||||
gameplayClock = gameplayClockContainer.GameplayClock;
|
||||
});
|
||||
|
||||
[Test]
|
||||
@ -64,19 +76,35 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestClickOnlyActuatesOnce()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () =>
|
||||
{
|
||||
increment = skip_time - gameplayClock.CurrentTime - GameplayClockContainer.MINIMUM_SKIP_TIME / 2;
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
checkRequestCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClickOnlyActuatesMultipleTimes()
|
||||
{
|
||||
AddStep("set increment lower", () => increment = 3000);
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
checkRequestCount(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoesntFadeOnMouseDown()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
|
||||
AddUntilStep("wait for overlay disapper", () => !skip.IsAlive);
|
||||
AddUntilStep("wait for overlay disappear", () => !skip.IsPresent);
|
||||
AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
|
||||
AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
checkRequestCount(0);
|
||||
|
@ -76,7 +76,7 @@ namespace osu.Game.Beatmaps
|
||||
public string MD5Hash { get; set; }
|
||||
|
||||
// General
|
||||
public int AudioLeadIn { get; set; }
|
||||
public double AudioLeadIn { get; set; }
|
||||
public bool Countdown { get; set; } = true;
|
||||
public float StackLeniency { get; set; } = 0.7f;
|
||||
public bool SpecialStyle { get; set; }
|
||||
|
@ -34,7 +34,6 @@ namespace osu.Game.Screens.Play
|
||||
public void ProcessFrame()
|
||||
{
|
||||
// we do not want to process the underlying clock.
|
||||
// this is handled by PauseContainer.
|
||||
}
|
||||
|
||||
public double ElapsedFrameTime => underlyingClock.ElapsedFrameTime;
|
||||
|
@ -41,6 +41,8 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private readonly double gameplayStartTime;
|
||||
|
||||
private readonly double firstHitObjectTime;
|
||||
|
||||
public readonly Bindable<double> UserPlaybackRate = new BindableDouble(1)
|
||||
{
|
||||
Default = 1,
|
||||
@ -66,6 +68,7 @@ namespace osu.Game.Screens.Play
|
||||
this.beatmap = beatmap;
|
||||
this.mods = mods;
|
||||
this.gameplayStartTime = gameplayStartTime;
|
||||
this.firstHitObjectTime = beatmap.Beatmap.HitObjects.First().StartTime;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
@ -89,6 +92,11 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private double totalOffset => userOffsetClock.Offset + platformOffsetClock.Offset;
|
||||
|
||||
/// <summary>
|
||||
/// Duration before gameplay start time required before skip button displays.
|
||||
/// </summary>
|
||||
public const double MINIMUM_SKIP_TIME = 1000;
|
||||
|
||||
private readonly BindableDouble pauseFreqAdjust = new BindableDouble(1);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -97,9 +105,22 @@ namespace osu.Game.Screens.Play
|
||||
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
|
||||
userAudioOffset.BindValueChanged(offset => userOffsetClock.Offset = offset.NewValue, true);
|
||||
|
||||
UserPlaybackRate.ValueChanged += _ => updateRate();
|
||||
// sane default provided by ruleset.
|
||||
double startTime = Math.Min(0, gameplayStartTime);
|
||||
|
||||
Seek(Math.Min(-beatmap.BeatmapInfo.AudioLeadIn, gameplayStartTime));
|
||||
// if a storyboard is present, it may dictate the appropriate start time by having events in negative time space.
|
||||
// this is commonly used to display an intro before the audio track start.
|
||||
startTime = Math.Min(startTime, beatmap.Storyboard.FirstEventTime);
|
||||
|
||||
// some beatmaps specify a current lead-in time which should be used instead of the ruleset-provided value when available.
|
||||
// this is not available as an option in the live editor but can still be applied via .osu editing.
|
||||
if (beatmap.BeatmapInfo.AudioLeadIn > 0)
|
||||
startTime = Math.Min(startTime, firstHitObjectTime - beatmap.BeatmapInfo.AudioLeadIn);
|
||||
|
||||
Seek(startTime);
|
||||
|
||||
adjustableClock.ProcessFrame();
|
||||
UserPlaybackRate.ValueChanged += _ => updateRate();
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
@ -130,6 +151,23 @@ namespace osu.Game.Screens.Play
|
||||
this.TransformBindableTo(pauseFreqAdjust, 1, 200, Easing.In);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip forward to the next valid skip point.
|
||||
/// </summary>
|
||||
public void Skip()
|
||||
{
|
||||
if (GameplayClock.CurrentTime > gameplayStartTime - MINIMUM_SKIP_TIME)
|
||||
return;
|
||||
|
||||
double skipTarget = gameplayStartTime - MINIMUM_SKIP_TIME;
|
||||
|
||||
if (GameplayClock.CurrentTime < 0 && skipTarget > 6000)
|
||||
// double skip exception for storyboards with very long intros
|
||||
skipTarget = 0;
|
||||
|
||||
Seek(skipTarget);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seek to a specific time in gameplay.
|
||||
/// <remarks>
|
||||
|
@ -203,7 +203,7 @@ namespace osu.Game.Screens.Play
|
||||
},
|
||||
new SkipOverlay(DrawableRuleset.GameplayStartTime)
|
||||
{
|
||||
RequestSeek = GameplayClockContainer.Seek
|
||||
RequestSkip = GameplayClockContainer.Skip
|
||||
},
|
||||
FailOverlay = new FailOverlay
|
||||
{
|
||||
|
@ -19,6 +19,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
@ -27,7 +28,7 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
private readonly double startTime;
|
||||
|
||||
public Action<double> RequestSeek;
|
||||
public Action RequestSkip;
|
||||
|
||||
private Button button;
|
||||
private Box remainingTimeBox;
|
||||
@ -35,6 +36,9 @@ namespace osu.Game.Screens.Play
|
||||
private FadeContainer fadeContainer;
|
||||
private double displayTime;
|
||||
|
||||
[Resolved]
|
||||
private GameplayClock gameplayClock { get; set; }
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
/// <summary>
|
||||
@ -45,8 +49,6 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
this.startTime = startTime;
|
||||
|
||||
Show();
|
||||
|
||||
RelativePositionAxes = Axes.Both;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
@ -57,13 +59,8 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, GameplayClock clock)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
var baseClock = Clock;
|
||||
|
||||
if (clock != null)
|
||||
Clock = clock;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fadeContainer = new FadeContainer
|
||||
@ -73,7 +70,6 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
button = new Button
|
||||
{
|
||||
Clock = baseClock,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
@ -90,46 +86,42 @@ namespace osu.Game.Screens.Play
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Duration before gameplay start time required before skip button displays.
|
||||
/// </summary>
|
||||
private const double skip_buffer = 1000;
|
||||
|
||||
private const double fade_time = 300;
|
||||
|
||||
private double beginFadeTime => startTime - fade_time;
|
||||
private double fadeOutBeginTime => startTime - GameplayClockContainer.MINIMUM_SKIP_TIME;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// skip is not required if there is no extra "empty" time to skip.
|
||||
if (Clock.CurrentTime > beginFadeTime - skip_buffer)
|
||||
// we may need to remove this if rewinding before the initial player load position becomes a thing.
|
||||
if (fadeOutBeginTime < gameplayClock.CurrentTime)
|
||||
{
|
||||
Alpha = 0;
|
||||
Expire();
|
||||
return;
|
||||
}
|
||||
|
||||
this.FadeInFromZero(fade_time);
|
||||
using (BeginAbsoluteSequence(beginFadeTime))
|
||||
this.FadeOut(fade_time);
|
||||
button.Action = () => RequestSkip?.Invoke();
|
||||
displayTime = gameplayClock.CurrentTime;
|
||||
|
||||
button.Action = () => RequestSeek?.Invoke(beginFadeTime);
|
||||
|
||||
displayTime = Time.Current;
|
||||
|
||||
Expire();
|
||||
Show();
|
||||
}
|
||||
|
||||
protected override void PopIn() => this.FadeIn();
|
||||
protected override void PopIn() => this.FadeIn(fade_time);
|
||||
|
||||
protected override void PopOut() => this.FadeOut();
|
||||
protected override void PopOut() => this.FadeOut(fade_time);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
remainingTimeBox.ResizeWidthTo((float)Math.Max(0, 1 - (Time.Current - displayTime) / (beginFadeTime - displayTime)), 120, Easing.OutQuint);
|
||||
|
||||
var progress = Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime));
|
||||
|
||||
remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1));
|
||||
|
||||
button.Enabled.Value = progress > 0;
|
||||
State.Value = progress > 0 ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
@ -335,13 +327,7 @@ namespace osu.Game.Screens.Play
|
||||
box.FlashColour(Color4.White, 500, Easing.OutQuint);
|
||||
aspect.ScaleTo(1.2f, 2000, Easing.OutQuint);
|
||||
|
||||
bool result = base.OnClick(e);
|
||||
|
||||
// for now, let's disable the skip button after the first press.
|
||||
// this will likely need to be contextual in the future (bound from external components).
|
||||
Enabled.Value = false;
|
||||
|
||||
return result;
|
||||
return base.OnClick(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -640,10 +640,19 @@ namespace osu.Game.Screens.Select
|
||||
itemsCache.Validate();
|
||||
}
|
||||
|
||||
private bool firstScroll = true;
|
||||
|
||||
private void updateScrollPosition()
|
||||
{
|
||||
if (scrollTarget != null)
|
||||
{
|
||||
if (firstScroll)
|
||||
{
|
||||
// reduce movement when first displaying the carousel.
|
||||
scroll.ScrollTo(scrollTarget.Value - 200, false);
|
||||
firstScroll = false;
|
||||
}
|
||||
|
||||
scroll.ScrollTo(scrollTarget.Value);
|
||||
scrollPositionCache.Validate();
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IBindable<WorkingBeatmap> beatmap, TextureStore textureStore)
|
||||
{
|
||||
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
||||
var path = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
||||
if (path == null)
|
||||
return;
|
||||
|
||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Storyboards
|
||||
|
||||
public bool HasDrawable => Layers.Any(l => l.Elements.Any(e => e.IsDrawable));
|
||||
|
||||
public double FirstEventTime => Layers.Min(l => l.Elements.FirstOrDefault()?.StartTime ?? 0);
|
||||
|
||||
public Storyboard()
|
||||
{
|
||||
layers.Add("Background", new StoryboardLayer("Background", 3));
|
||||
|
@ -5,25 +5,31 @@ using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Graphics.Video;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Storyboards;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
public class TestWorkingBeatmap : WorkingBeatmap
|
||||
{
|
||||
private readonly IBeatmap beatmap;
|
||||
private readonly Storyboard storyboard;
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance which provides the <see cref="IBeatmap"/> when requested.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap</param>
|
||||
public TestWorkingBeatmap(IBeatmap beatmap)
|
||||
/// <param name="beatmap">The beatmap.</param>
|
||||
/// <param name="storyboard">An optional storyboard.</param>
|
||||
public TestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
: base(beatmap.BeatmapInfo, null)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
this.storyboard = storyboard;
|
||||
}
|
||||
|
||||
protected override IBeatmap GetBeatmap() => beatmap;
|
||||
|
||||
protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard();
|
||||
|
||||
protected override Texture GetBackground() => null;
|
||||
|
||||
protected override VideoSprite GetVideo() => null;
|
||||
|
@ -21,6 +21,7 @@ using osu.Game.Database;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
@ -119,10 +120,10 @@ namespace osu.Game.Tests.Visual
|
||||
protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset);
|
||||
|
||||
protected WorkingBeatmap CreateWorkingBeatmap(RulesetInfo ruleset) =>
|
||||
CreateWorkingBeatmap(CreateBeatmap(ruleset));
|
||||
CreateWorkingBeatmap(CreateBeatmap(ruleset), null);
|
||||
|
||||
protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) =>
|
||||
new ClockBackedTestWorkingBeatmap(beatmap, Clock, audio);
|
||||
protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) =>
|
||||
new ClockBackedTestWorkingBeatmap(beatmap, storyboard, Clock, audio);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
@ -168,7 +169,7 @@ namespace osu.Game.Tests.Visual
|
||||
/// <param name="referenceClock">A clock which should be used instead of a stopwatch for virtual time progression.</param>
|
||||
/// <param name="audio">Audio manager. Required if a reference clock isn't provided.</param>
|
||||
public ClockBackedTestWorkingBeatmap(RulesetInfo ruleset, IFrameBasedClock referenceClock, AudioManager audio)
|
||||
: this(new TestBeatmap(ruleset), referenceClock, audio)
|
||||
: this(new TestBeatmap(ruleset), null, referenceClock, audio)
|
||||
{
|
||||
}
|
||||
|
||||
@ -176,11 +177,12 @@ namespace osu.Game.Tests.Visual
|
||||
/// Create an instance which provides the <see cref="IBeatmap"/> when requested.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap</param>
|
||||
/// <param name="storyboard">The storyboard.</param>
|
||||
/// <param name="referenceClock">An optional clock which should be used instead of a stopwatch for virtual time progression.</param>
|
||||
/// <param name="audio">Audio manager. Required if a reference clock isn't provided.</param>
|
||||
/// <param name="length">The length of the returned virtual track.</param>
|
||||
public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock referenceClock, AudioManager audio, double length = 60000)
|
||||
: base(beatmap)
|
||||
public ClockBackedTestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio, double length = 60000)
|
||||
: base(beatmap, storyboard)
|
||||
{
|
||||
if (referenceClock != null)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user