From 22dfe46572b2f73a0fbb790688d41a8a78d873d5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 21:45:19 +0900 Subject: [PATCH 1/4] Make taiko hitobject properly unproxy when rewound --- .../Objects/Drawables/DrawableHit.cs | 4 ++ .../Objects/Drawables/DrawableSwell.cs | 20 +++---- .../Drawables/DrawableTaikoHitObject.cs | 60 +++++++++++++++++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 20 +------ 4 files changed, 70 insertions(+), 34 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index d923b2dcdf..cca2753524 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -86,6 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (State.Value) { case ArmedState.Idle: + UnproxyContent(); this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire(); break; case ArmedState.Miss: @@ -93,6 +94,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables .Expire(); break; case ArmedState.Hit: + if (X >= -0.05f) + ProxyContent(); + var flash = circlePiece?.FlashBox; if (flash != null) { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 33cc29bccf..1f571544d8 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -20,12 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public class DrawableSwell : DrawableTaikoHitObject { - /// - /// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime. - /// This is only ever invoked once. - /// - public event Action OnStart; - private const float target_ring_thick_border = 1.4f; private const float target_ring_thin_border = 1f; private const float target_ring_scale = 5f; @@ -40,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private int userHits; - private bool hasStarted; + private bool hasProxied; private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) @@ -48,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { FillMode = FillMode.Fit; - AddInternal(bodyContainer = new Container + Content.Add(bodyContainer = new Container { RelativeSizeAxes = Axes.Both, Depth = 1, @@ -177,6 +171,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { + case ArmedState.Idle: + hasProxied = false; + UnproxyContent(); + break; case ArmedState.Hit: bodyContainer.Delay(untilJudgement).ScaleTo(1.4f, out_transition_time); break; @@ -195,10 +193,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables X = Math.Max(0, X); double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime && !hasStarted) + if (t == HitObject.StartTime && !hasProxied) { - OnStart?.Invoke(); - hasStarted = true; + ProxyContent(); + hasProxied = true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 971fd8854d..c07ee3a0fd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -9,10 +9,62 @@ using OpenTK; using System.Linq; using osu.Game.Audio; using System.Collections.Generic; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + { + protected readonly Container Content; + public readonly Container ProxiedContent; + + private readonly Container nonProxiedContent; + + protected DrawableTaikoHitObject(TaikoHitObject hitObject) + : base(hitObject) + { + InternalChildren = new[] + { + nonProxiedContent = new Container + { + RelativeSizeAxes = Axes.Both, + Child = Content = new Container { RelativeSizeAxes = Axes.Both } + }, + ProxiedContent = new Container { RelativeSizeAxes = Axes.Both } + }; + } + + /// + /// is proxied into an upper layer. We don't want to get masked away otherwise would too. + /// + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + + /// + /// Moves to a layer proxied above the playfield. + /// + protected void ProxyContent() + { + nonProxiedContent.Remove(Content); + ProxiedContent.Remove(Content); + ProxiedContent.Add(Content); + } + + /// + /// Moves to the normal hitobject layer. + /// + protected void UnproxyContent() + { + ProxiedContent.Remove(Content); + nonProxiedContent.Remove(Content); + nonProxiedContent.Add(Content); + } + + public abstract bool OnPressed(TaikoAction action); + public virtual bool OnReleased(TaikoAction action) => false; + } + + public abstract class DrawableTaikoHitObject : DrawableTaikoHitObject where TaikoHitType : TaikoHitObject { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); @@ -34,7 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both; Size = BaseSize = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE); - InternalChild = MainPiece = CreateMainPiece(); + Content.Add(MainPiece = CreateMainPiece()); MainPiece.KiaiMode = HitObject.Kiai; } @@ -44,9 +96,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override string SampleNamespace => "Taiko"; protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); - - public abstract bool OnPressed(TaikoAction action); - - public virtual bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 417a7c2581..c638f807fe 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -216,10 +216,9 @@ namespace osu.Game.Rulesets.Taiko.UI if (barline != null) barlineContainer.Add(barline.CreateProxy()); - // Swells should be moved at the very top of the playfield when they reach the hit target - var swell = h as DrawableSwell; - if (swell != null) - swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy()); + var taikoObject = h as DrawableTaikoHitObject; + if (taikoObject != null) + topLevelHitContainer.Add(taikoObject.ProxiedContent.CreateProxy()); } internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) @@ -244,19 +243,6 @@ namespace osu.Game.Rulesets.Taiko.UI hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == judgedObject)?.VisualiseSecondHit(); else { - if (judgedObject.X >= -0.05f && judgedObject is DrawableHit) - { - // If we're far enough away from the left stage, we should bring outselves in front of it - // Todo: The following try-catch is temporary for replay rewinding support - try - { - topLevelHitContainer.Add(judgedObject.CreateProxy()); - } - catch - { - } - } - hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); if (judgedObject.HitObject.Kiai) From 1b12820de9e8529df794cc3d1396ba9e4d954c29 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Mon, 11 Jun 2018 21:54:11 +0900 Subject: [PATCH 2/4] Restore a removed comment --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index cca2753524..519b56a3ed 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables .Expire(); break; case ArmedState.Hit: + // If we're far enough away from the left stage, we should bring outselves in front of it if (X >= -0.05f) ProxyContent(); From 457531910294897c15cdfbc5337672d138c0ef1d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 17 Jun 2018 17:56:46 +0900 Subject: [PATCH 3/4] Privatise the proxied content --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 17 +++++++++++------ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index c07ee3a0fd..e712d62a26 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler { protected readonly Container Content; - public readonly Container ProxiedContent; + private readonly Container proxiedContent; private readonly Container nonProxiedContent; @@ -31,12 +31,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both, Child = Content = new Container { RelativeSizeAxes = Axes.Both } }, - ProxiedContent = new Container { RelativeSizeAxes = Axes.Both } + proxiedContent = new Container { RelativeSizeAxes = Axes.Both } }; } /// - /// is proxied into an upper layer. We don't want to get masked away otherwise would too. + /// is proxied into an upper layer. We don't want to get masked away otherwise would too. /// protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; @@ -46,8 +46,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected void ProxyContent() { nonProxiedContent.Remove(Content); - ProxiedContent.Remove(Content); - ProxiedContent.Add(Content); + proxiedContent.Remove(Content); + proxiedContent.Add(Content); } /// @@ -55,11 +55,16 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected void UnproxyContent() { - ProxiedContent.Remove(Content); + proxiedContent.Remove(Content); nonProxiedContent.Remove(Content); nonProxiedContent.Add(Content); } + /// + /// Creates a proxy for the content of this . + /// + public Drawable CreateProxiedContent() => proxiedContent.CreateProxy(); + public abstract bool OnPressed(TaikoAction action); public virtual bool OnReleased(TaikoAction action) => false; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index c638f807fe..7fdd3cd1e2 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -218,7 +218,7 @@ namespace osu.Game.Rulesets.Taiko.UI var taikoObject = h as DrawableTaikoHitObject; if (taikoObject != null) - topLevelHitContainer.Add(taikoObject.ProxiedContent.CreateProxy()); + topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); } internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) From 5b344525e1889e6c4fbd8a5cedccc812827a314e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 00:27:18 +0900 Subject: [PATCH 4/4] Move proxy state check to base class --- .../Objects/Drawables/DrawableSwell.cs | 7 +------ .../Objects/Drawables/DrawableTaikoHitObject.cs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 1f571544d8..df36a475d6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -34,7 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private int userHits; - private bool hasProxied; private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) @@ -172,7 +171,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { case ArmedState.Idle: - hasProxied = false; UnproxyContent(); break; case ArmedState.Hit: @@ -193,11 +191,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables X = Math.Max(0, X); double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime && !hasProxied) - { + if (t == HitObject.StartTime) ProxyContent(); - hasProxied = true; - } } private bool? lastWasCentre; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index e712d62a26..a6d61f1a5a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -40,23 +40,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + private bool isProxied; + /// /// Moves to a layer proxied above the playfield. + /// Does nothing is content is already proxied. /// protected void ProxyContent() { + if (isProxied) return; + isProxied = true; + nonProxiedContent.Remove(Content); - proxiedContent.Remove(Content); proxiedContent.Add(Content); } /// /// Moves to the normal hitobject layer. + /// Does nothing is content is not currently proxied. /// protected void UnproxyContent() { + if (!isProxied) return; + isProxied = false; + proxiedContent.Remove(Content); - nonProxiedContent.Remove(Content); nonProxiedContent.Add(Content); }