diff --git a/osu.Android.props b/osu.Android.props
index 0563e5319d..ff04c7f120 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
index 65bed071cd..8cb7f3f4b6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Tests
if (auto && !userTriggered && Time.Current > Spinner.StartTime + Spinner.Duration / 2 && Progress < 1)
{
// force completion only once to not break human interaction
- Disc.RotationAbsolute = Spinner.SpinsRequired * 360;
+ Disc.CumulativeRotation = Spinner.SpinsRequired * 360;
auto = false;
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
index ea006ec607..6b1394d799 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
@@ -14,6 +14,12 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
using osuTK;
using System.Collections.Generic;
using System.Linq;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Replays;
+using osu.Game.Rulesets.Osu.Replays;
+using osu.Game.Rulesets.Osu.UI;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Scoring;
using osu.Game.Storyboards;
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
@@ -36,6 +42,7 @@ namespace osu.Game.Rulesets.Osu.Tests
}
private DrawableSpinner drawableSpinner;
+ private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType().Single();
[SetUpSteps]
public override void SetUpSteps()
@@ -50,25 +57,78 @@ namespace osu.Game.Rulesets.Osu.Tests
public void TestSpinnerRewindingRotation()
{
addSeekStep(5000);
- AddAssert("is rotation absolute not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, 0, 100));
+ AddAssert("is disc rotation not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Disc.Rotation, 0, 100));
+ AddAssert("is disc rotation absolute not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Disc.CumulativeRotation, 0, 100));
addSeekStep(0);
- AddAssert("is rotation absolute almost 0", () => Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, 0, 100));
+ AddAssert("is disc rotation almost 0", () => Precision.AlmostEquals(drawableSpinner.Disc.Rotation, 0, 100));
+ AddAssert("is disc rotation absolute almost 0", () => Precision.AlmostEquals(drawableSpinner.Disc.CumulativeRotation, 0, 100));
}
[Test]
public void TestSpinnerMiddleRewindingRotation()
{
- double estimatedRotation = 0;
+ double finalAbsoluteDiscRotation = 0, finalRelativeDiscRotation = 0, finalSpinnerSymbolRotation = 0;
addSeekStep(5000);
- AddStep("retrieve rotation", () => estimatedRotation = drawableSpinner.Disc.RotationAbsolute);
+ AddStep("retrieve disc relative rotation", () => finalRelativeDiscRotation = drawableSpinner.Disc.Rotation);
+ AddStep("retrieve disc absolute rotation", () => finalAbsoluteDiscRotation = drawableSpinner.Disc.CumulativeRotation);
+ AddStep("retrieve spinner symbol rotation", () => finalSpinnerSymbolRotation = spinnerSymbol.Rotation);
addSeekStep(2500);
+ AddUntilStep("disc rotation rewound",
+ // we want to make sure that the rotation at time 2500 is in the same direction as at time 5000, but about half-way in.
+ () => Precision.AlmostEquals(drawableSpinner.Disc.Rotation, finalRelativeDiscRotation / 2, 100));
+ AddUntilStep("symbol rotation rewound",
+ () => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation / 2, 100));
+
addSeekStep(5000);
- AddAssert("is rotation absolute almost same", () => Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, estimatedRotation, 100));
+ AddAssert("is disc rotation almost same",
+ () => Precision.AlmostEquals(drawableSpinner.Disc.Rotation, finalRelativeDiscRotation, 100));
+ AddAssert("is symbol rotation almost same",
+ () => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation, 100));
+ AddAssert("is disc rotation absolute almost same",
+ () => Precision.AlmostEquals(drawableSpinner.Disc.CumulativeRotation, finalAbsoluteDiscRotation, 100));
}
+ [Test]
+ public void TestRotationDirection([Values(true, false)] bool clockwise)
+ {
+ if (clockwise)
+ {
+ AddStep("flip replay", () =>
+ {
+ var drawableRuleset = this.ChildrenOfType().Single();
+ var score = drawableRuleset.ReplayScore;
+ var scoreWithFlippedReplay = new Score
+ {
+ ScoreInfo = score.ScoreInfo,
+ Replay = flipReplay(score.Replay)
+ };
+ drawableRuleset.SetReplayScore(scoreWithFlippedReplay);
+ });
+ }
+
+ addSeekStep(5000);
+
+ AddAssert("disc spin direction correct", () => clockwise ? drawableSpinner.Disc.Rotation > 0 : drawableSpinner.Disc.Rotation < 0);
+ AddAssert("spinner symbol direction correct", () => clockwise ? spinnerSymbol.Rotation > 0 : spinnerSymbol.Rotation < 0);
+ }
+
+ private Replay flipReplay(Replay scoreReplay) => new Replay
+ {
+ Frames = scoreReplay
+ .Frames
+ .Cast()
+ .Select(replayFrame =>
+ {
+ var flippedPosition = new Vector2(OsuPlayfield.BASE_SIZE.X - replayFrame.Position.X, replayFrame.Position.Y);
+ return new OsuReplayFrame(replayFrame.Time, flippedPosition, replayFrame.Actions.ToArray());
+ })
+ .Cast()
+ .ToList()
+ };
+
[Test]
public void TestSpinPerMinuteOnRewind()
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
index 4d37622be5..be6766509c 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
@@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
positionBindable.BindTo(HitObject.PositionBindable);
}
- public float Progress => Math.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1);
+ public float Progress => Math.Clamp(Disc.CumulativeRotation / 360 / Spinner.SpinsRequired, 0, 1);
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
@@ -191,13 +191,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
circle.Rotation = Disc.Rotation;
Ticks.Rotation = Disc.Rotation;
- SpmCounter.SetRotation(Disc.RotationAbsolute);
+ SpmCounter.SetRotation(Disc.CumulativeRotation);
float relativeCircleScale = Spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight;
float targetScale = relativeCircleScale + (1 - relativeCircleScale) * Progress;
Disc.Scale = new Vector2((float)Interpolation.Lerp(Disc.Scale.X, targetScale, Math.Clamp(Math.Abs(Time.Elapsed) / 100, 0, 1)));
- symbol.Rotation = (float)Interpolation.Lerp(symbol.Rotation, Disc.RotationAbsolute / 2, Math.Clamp(Math.Abs(Time.Elapsed) / 40, 0, 1));
+ symbol.Rotation = (float)Interpolation.Lerp(symbol.Rotation, Disc.Rotation / 2, Math.Clamp(Math.Abs(Time.Elapsed) / 40, 0, 1));
}
protected override void UpdateInitialTransforms()
@@ -207,9 +207,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
circleContainer.ScaleTo(Spinner.Scale * 0.3f);
circleContainer.ScaleTo(Spinner.Scale, HitObject.TimePreempt / 1.4f, Easing.OutQuint);
- Disc.RotateTo(-720);
- symbol.RotateTo(-720);
-
mainContainer
.ScaleTo(0)
.ScaleTo(Spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, HitObject.TimePreempt - 150, Easing.OutQuint)
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
index d4ef039b79..35819cd05e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
@@ -73,6 +73,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
}
}
+ ///
+ /// The total rotation performed on the spinner disc, disregarding the spin direction.
+ ///
+ ///
+ /// This value is always non-negative and is monotonically increasing with time
+ /// (i.e. will only increase if time is passing forward, but can decrease during rewind).
+ ///
+ ///
+ /// If the spinner is spun 360 degrees clockwise and then 360 degrees counter-clockwise,
+ /// this property will return the value of 720 (as opposed to 0 for ).
+ ///
+ public float CumulativeRotation;
+
///
/// Whether currently in the correct time range to allow spinning.
///
@@ -88,10 +101,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private float lastAngle;
private float currentRotation;
- public float RotationAbsolute;
private int completeTick;
- private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360));
+ private bool updateCompleteTick() => completeTick != (completeTick = (int)(CumulativeRotation / 360));
private bool rotationTransferred;
@@ -149,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
}
currentRotation += angle;
- RotationAbsolute += Math.Abs(angle) * Math.Sign(Clock.ElapsedFrameTime);
+ CumulativeRotation += Math.Abs(angle) * Math.Sign(Clock.ElapsedFrameTime);
}
}
}
diff --git a/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs b/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs
index d47d37806e..3106d1143e 100644
--- a/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs
+++ b/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs
@@ -183,6 +183,7 @@ namespace osu.Game.Beatmaps
public void Dispose()
{
cacheDownloadRequest?.Dispose();
+ updateScheduler?.Dispose();
}
[Serializable]
diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs
index 1b748cb672..de08b79f57 100644
--- a/osu.Game/Overlays/Toolbar/Toolbar.cs
+++ b/osu.Game/Overlays/Toolbar/Toolbar.cs
@@ -28,9 +28,6 @@ namespace osu.Game.Overlays.Toolbar
private const double transition_time = 500;
- private const float alpha_hovering = 0.8f;
- private const float alpha_normal = 0.6f;
-
private readonly Bindable overlayActivationMode = new Bindable(OverlayActivation.All);
// Toolbar components like RulesetSelector should receive keyboard input events even when the toolbar is hidden.
@@ -103,7 +100,6 @@ namespace osu.Game.Overlays.Toolbar
public class ToolbarBackground : Container
{
- private readonly Box solidBackground;
private readonly Box gradientBackground;
public ToolbarBackground()
@@ -111,11 +107,10 @@ namespace osu.Game.Overlays.Toolbar
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
- solidBackground = new Box
+ new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.1f),
- Alpha = alpha_normal,
},
gradientBackground = new Box
{
@@ -131,14 +126,12 @@ namespace osu.Game.Overlays.Toolbar
protected override bool OnHover(HoverEvent e)
{
- solidBackground.FadeTo(alpha_hovering, transition_time, Easing.OutQuint);
gradientBackground.FadeIn(transition_time, Easing.OutQuint);
return true;
}
protected override void OnHoverLost(HoverLostEvent e)
{
- solidBackground.FadeTo(alpha_normal, transition_time, Easing.OutQuint);
gradientBackground.FadeOut(transition_time, Easing.OutQuint);
}
}
@@ -146,7 +139,7 @@ namespace osu.Game.Overlays.Toolbar
protected override void PopIn()
{
this.MoveToY(0, transition_time, Easing.OutQuint);
- this.FadeIn(transition_time / 2, Easing.OutQuint);
+ this.FadeIn(transition_time / 4, Easing.OutQuint);
}
protected override void PopOut()
@@ -154,7 +147,7 @@ namespace osu.Game.Overlays.Toolbar
userButton.StateContainer?.Hide();
this.MoveToY(-DrawSize.Y, transition_time, Easing.OutQuint);
- this.FadeOut(transition_time);
+ this.FadeOut(transition_time, Easing.InQuint);
}
}
}
diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
index d4b6a3b79f..9c2ed26b52 100644
--- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
+++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Screens.Multi.Lounge
public LoungeSubScreen()
{
- SearchContainer searchContainer;
+ RoomsContainer roomsContainer;
InternalChildren = new Drawable[]
{
@@ -55,14 +55,9 @@ namespace osu.Game.Screens.Multi.Lounge
RelativeSizeAxes = Axes.Both,
ScrollbarOverlapsContent = false,
Padding = new MarginPadding(10),
- Child = searchContainer = new SearchContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Child = new RoomsContainer { JoinRequested = joinRequested }
- },
+ Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested }
},
- loadingLayer = new LoadingLayer(searchContainer),
+ loadingLayer = new LoadingLayer(roomsContainer),
}
},
new RoomInspector
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 4e6de77e86..e4753e7ee9 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index c31e28638f..91fa003604 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -80,7 +80,7 @@
-
+