diff --git a/osu.Android.props b/osu.Android.props
index 69f897128c..650ebde54d 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,7 +51,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs
index 520961d3ce..16ef5b968d 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs
@@ -3,6 +3,7 @@
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Testing;
+using osu.Framework.Timing;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Skinning;
@@ -12,11 +13,30 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
{
public class TestSceneTaikoScroller : TaikoSkinnableTestScene
{
+ private readonly ManualClock clock = new ManualClock();
+
+ private bool reversed;
+
public TestSceneTaikoScroller()
{
- AddStep("Load scroller", () => SetContents(() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty())));
+ AddStep("Load scroller", () => SetContents(() =>
+ new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty())
+ {
+ Clock = new FramedClock(clock),
+ Height = 0.4f,
+ }));
+
AddToggleStep("Toggle passing", passing => this.ChildrenOfType().ForEach(s => s.LastResult.Value =
new JudgementResult(null, new Judgement()) { Type = passing ? HitResult.Perfect : HitResult.Miss }));
+
+ AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ clock.CurrentTime += (reversed ? -1 : 1) * Clock.ElapsedFrameTime;
}
}
}
diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs
index 1ecdb839fb..03813e0a99 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs
@@ -17,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning
{
public class LegacyTaikoScroller : CompositeDrawable
{
+ public Bindable LastResult = new Bindable();
+
public LegacyTaikoScroller()
{
RelativeSizeAxes = Axes.Both;
@@ -50,37 +52,38 @@ namespace osu.Game.Rulesets.Taiko.Skinning
}, true);
}
- public Bindable LastResult = new Bindable();
-
protected override void Update()
{
base.Update();
- while (true)
+ // store X before checking wide enough so if we perform layout there is no positional discrepancy.
+ float currentX = (InternalChildren?.FirstOrDefault()?.X ?? 0) - (float)Clock.ElapsedFrameTime * 0.1f;
+
+ // ensure we have enough sprites
+ if (!InternalChildren.Any()
+ || InternalChildren.First().ScreenSpaceDrawQuad.Width * InternalChildren.Count < ScreenSpaceDrawQuad.Width * 2)
+ AddInternal(new ScrollerSprite { Passing = passing });
+
+ var first = InternalChildren.First();
+ var last = InternalChildren.Last();
+
+ foreach (var sprite in InternalChildren)
{
- float? additiveX = null;
+ // add the x coordinates and perform re-layout on all sprites as spacing may change with gameplay scale.
+ sprite.X = currentX;
+ currentX += sprite.DrawWidth;
+ }
- foreach (var sprite in InternalChildren)
- {
- // add the x coordinates and perform re-layout on all sprites as spacing may change with gameplay scale.
- sprite.X = additiveX ??= sprite.X - (float)Time.Elapsed * 0.1f;
+ if (first.ScreenSpaceDrawQuad.TopLeft.X >= ScreenSpaceDrawQuad.TopLeft.X)
+ {
+ foreach (var internalChild in InternalChildren)
+ internalChild.X -= first.DrawWidth;
+ }
- additiveX += sprite.DrawWidth - 1;
-
- if (sprite.X + sprite.DrawWidth < 0)
- sprite.Expire();
- }
-
- var last = InternalChildren.LastOrDefault();
-
- // only break from this loop once we have saturated horizontal space completely.
- if (last != null && last.ScreenSpaceDrawQuad.TopRight.X >= ScreenSpaceDrawQuad.TopRight.X)
- break;
-
- AddInternal(new ScrollerSprite
- {
- Passing = passing
- });
+ if (last.ScreenSpaceDrawQuad.TopRight.X <= ScreenSpaceDrawQuad.TopRight.X)
+ {
+ foreach (var internalChild in InternalChildren)
+ internalChild.X += first.DrawWidth;
}
}
diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
index 9b37af1111..e6aacf34dc 100644
--- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{
new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
- AddInternal(scroller = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty())
+ FrameStableComponents.Add(scroller = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty())
{
RelativeSizeAxes = Axes.X,
Depth = float.MaxValue
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index c6dba8da13..ee6206e166 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -25,7 +25,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index f78fd2e4ff..cbf8600c62 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -71,7 +71,7 @@
-
+