From 028e941ab2fb14a5a83c6744a2acb852d4dcf723 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Apr 2017 10:01:40 +0900 Subject: [PATCH] Major rsefinements to taiko drawable classes. --- .../Tests/TestCaseTaikoHitObjects.cs | 6 +- .../Tests/TestCaseTaikoPlayfield.cs | 3 +- .../Objects/Drawables/DrawableCentreHit.cs | 4 +- .../Objects/Drawables/DrawableDrumRoll.cs | 37 ++--- .../Objects/Drawables/DrawableDrumRollTick.cs | 64 ++------ .../Objects/Drawables/DrawableHit.cs | 43 ++--- .../Objects/Drawables/DrawableRimHit.cs | 4 +- .../Drawables/DrawableStrongCentreHit.cs | 4 +- .../Drawables/DrawableStrongDrumRoll.cs | 20 --- .../Objects/Drawables/DrawableStrongHit.cs | 6 +- .../Objects/Drawables/DrawableStrongRimHit.cs | 4 +- .../Objects/Drawables/DrawableSwell.cs | 19 +-- .../Drawables/DrawableTaikoHitObject.cs | 42 ++++- .../Objects/Drawables/Pieces/CirclePiece.cs | 155 ++++++++---------- .../Drawables/Pieces/ElongatedCirclePiece.cs | 41 +++++ .../Drawables/Pieces/StrongCirclePiece.cs | 25 --- .../Objects/Drawables/Pieces/TaikoPiece.cs | 45 +++++ .../Objects/Drawables/Pieces/TickPiece.cs | 60 +++++++ .../Objects/TaikoHitObject.cs | 2 +- osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs | 2 - .../osu.Game.Modes.Taiko.csproj | 5 +- 21 files changed, 316 insertions(+), 275 deletions(-) delete mode 100644 osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongDrumRoll.cs create mode 100644 osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs delete mode 100644 osu.Game.Modes.Taiko/Objects/Drawables/Pieces/StrongCirclePiece.cs create mode 100644 osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs create mode 100644 osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs index 352af5d109..1590437495 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoHitObjects.cs @@ -37,7 +37,7 @@ namespace osu.Desktop.VisualTests.Tests } }); - Add(new StrongCirclePiece + Add(new CirclePiece(true) { Position = new Vector2(350, 100), AccentColour = Color4.DarkRed, @@ -59,7 +59,7 @@ namespace osu.Desktop.VisualTests.Tests } }); - Add(new StrongCirclePiece + Add(new CirclePiece(true) { Position = new Vector2(350, 300), AccentColour = Color4.DarkBlue, @@ -89,7 +89,7 @@ namespace osu.Desktop.VisualTests.Tests KiaiMode = kiai, }); - Add(new StrongCirclePiece + Add(new CirclePiece(true) { Position = new Vector2(575, 300), Width = 0.25f, diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs index 4bf44a21e4..d2c026251a 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs @@ -108,11 +108,12 @@ namespace osu.Desktop.VisualTests.Tests var d = new DrumRoll { StartTime = Time.Current + 1000, + IsStrong = strong, Distance = 1000, PreEmpt = 1000, }; - playfield.Add(strong ? new DrawableStrongDrumRoll(d) : new DrawableDrumRoll(d)); + playfield.Add(new DrawableDrumRoll(d)); } private void addCentreHit(bool strong) diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs index add656f208..ff5ac859b4 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableCentreHit.cs @@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables public DrawableCentreHit(Hit hit) : base(hit) { - Circle.Add(new CentreHitSymbolPiece()); + MainPiece.Add(new CentreHitSymbolPiece()); } [BackgroundDependencyLoader] private void load(OsuColour colours) { - Circle.AccentColour = colours.PinkDarker; + MainPiece.AccentColour = colours.PinkDarker; } } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 48bd3e4eb1..a4a3e0e062 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -3,28 +3,23 @@ using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Taiko.Judgements; -using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; +using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; namespace osu.Game.Modes.Taiko.Objects.Drawables { - public class DrawableDrumRoll : DrawableTaikoHitObject + public class DrawableDrumRoll : DrawableTaikoHitObject { /// /// Number of rolling hits required to reach the dark/final accent colour. /// private const int rolling_hits_for_dark_accent = 5; - private readonly DrumRoll drumRoll; - - private readonly CirclePiece circle; - private Color4 accentDarkColour; /// @@ -35,14 +30,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables public DrawableDrumRoll(DrumRoll drumRoll) : base(drumRoll) { - this.drumRoll = drumRoll; - - RelativeSizeAxes = Axes.X; - Width = (float)(drumRoll.Duration / drumRoll.PreEmpt); - - Add(circle = CreateCirclePiece()); - circle.KiaiMode = HitObject.Kiai; - foreach (var tick in drumRoll.Ticks) { var newTick = new DrawableDrumRollTick(tick) @@ -53,14 +40,22 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables newTick.OnJudgement += onTickJudgement; AddNested(newTick); - Add(newTick); + MainPiece.Add(newTick); } } + protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = HitObject.IsStrong }; + + protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(HitObject.IsStrong) + { + Length = (float)(HitObject.Duration / HitObject.PreEmpt), + PlayfieldLengthReference = () => Parent.DrawSize.X + }; + [BackgroundDependencyLoader] private void load(OsuColour colours) { - circle.AccentColour = AccentColour = colours.YellowDark; + MainPiece.AccentColour = AccentColour = colours.YellowDark; accentDarkColour = colours.YellowDarker; } @@ -72,7 +67,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables // is further than mid point of the play field, so the time taken to scroll in should always // be greater than the time taken to scroll out to the left of the screen. // Thus, using PreEmpt here is enough for the drum roll to completely scroll out. - LifetimeEnd = drumRoll.EndTime + drumRoll.PreEmpt; + LifetimeEnd = HitObject.EndTime + HitObject.PreEmpt; } private void onTickJudgement(DrawableHitObject obj) @@ -85,7 +80,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables rollingHits = MathHelper.Clamp(rollingHits, 0, rolling_hits_for_dark_accent); Color4 newAccent = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_dark_accent, AccentColour, accentDarkColour, 0, 1); - circle.FadeAccent(newAccent, 100); + MainPiece.FadeAccent(newAccent, 100); } protected override void CheckJudgement(bool userTriggered) @@ -98,10 +93,10 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit); - if (countHit > drumRoll.RequiredGoodHits) + if (countHit > HitObject.RequiredGoodHits) { Judgement.Result = HitResult.Hit; - Judgement.TaikoResult = countHit >= drumRoll.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good; + Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good; } else Judgement.Result = HitResult.Miss; diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 85f9e32c6c..296affedaf 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -3,79 +3,37 @@ using System; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Taiko.Judgements; -using OpenTK; -using OpenTK.Graphics; using OpenTK.Input; +using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; namespace osu.Game.Modes.Taiko.Objects.Drawables { - public class DrawableDrumRollTick : DrawableTaikoHitObject + public class DrawableDrumRollTick : DrawableTaikoHitObject { - /// - /// The size of a tick. - /// - private const float tick_size = TaikoHitObject.CIRCLE_RADIUS / 2; - - /// - /// Any tick that is not the first for a drumroll is not filled, but is instead displayed - /// as a hollow circle. This is what controls the border width of that circle. - /// - private const float tick_border_width = tick_size / 4; - - private readonly DrumRollTick tick; - - private readonly CircularContainer bodyContainer; - public DrawableDrumRollTick(DrumRollTick tick) : base(tick) { - this.tick = tick; - - Anchor = Anchor.CentreLeft; - Origin = Anchor.Centre; - - RelativePositionAxes = Axes.X; - Size = new Vector2(tick_size); - - Children = new[] - { - bodyContainer = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderThickness = tick_border_width, - BorderColour = Color4.White, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = tick.FirstTick ? 1 : 0, - AlwaysPresent = true - } - } - } - }; } - protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = tick.IsStrong }; + protected override TaikoPiece CreateMainPiece() => new TickPiece + { + Filled = HitObject.FirstTick + }; + + protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong }; protected override void CheckJudgement(bool userTriggered) { if (!userTriggered) { - if (Judgement.TimeOffset > tick.HitWindow) + if (Judgement.TimeOffset > HitObject.HitWindow) Judgement.Result = HitResult.Miss; return; } - if (Math.Abs(Judgement.TimeOffset) < tick.HitWindow) + if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow) { Judgement.Result = HitResult.Hit; Judgement.TaikoResult = TaikoHitResult.Great; @@ -87,7 +45,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables switch (state) { case ArmedState.Hit: - bodyContainer.ScaleTo(0, 100, EasingTypes.OutQuint); + Content.ScaleTo(0, 100, EasingTypes.OutQuint); break; } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs index 19799f7ada..40d625812a 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableHit.cs @@ -4,29 +4,19 @@ using System; using System.Linq; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Taiko.Judgements; -using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; using OpenTK.Input; namespace osu.Game.Modes.Taiko.Objects.Drawables { - public abstract class DrawableHit : DrawableTaikoHitObject + public abstract class DrawableHit : DrawableTaikoHitObject { /// /// A list of keys which can result in hits for this HitObject. /// protected abstract Key[] HitKeys { get; } - protected override Container Content => bodyContainer; - - protected readonly CirclePiece Circle; - - private readonly Hit hit; - - private readonly Container bodyContainer; - /// /// Whether the last key pressed is a valid hit key. /// @@ -35,41 +25,28 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables protected DrawableHit(Hit hit) : base(hit) { - this.hit = hit; - - AddInternal(bodyContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new[] - { - Circle = CreateCirclePiece() - } - }); - - Circle.KiaiMode = HitObject.Kiai; } protected override void CheckJudgement(bool userTriggered) { if (!userTriggered) { - if (Judgement.TimeOffset > hit.HitWindowGood) + if (Judgement.TimeOffset > HitObject.HitWindowGood) Judgement.Result = HitResult.Miss; return; } double hitOffset = Math.Abs(Judgement.TimeOffset); - if (hitOffset > hit.HitWindowMiss) + if (hitOffset > HitObject.HitWindowMiss) return; if (!validKeyPressed) Judgement.Result = HitResult.Miss; - else if (hitOffset < hit.HitWindowGood) + else if (hitOffset < HitObject.HitWindowGood) { Judgement.Result = HitResult.Hit; - Judgement.TaikoResult = hitOffset < hit.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good; + Judgement.TaikoResult = hitOffset < HitObject.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good; } else Judgement.Result = HitResult.Miss; @@ -92,16 +69,16 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables switch (State) { case ArmedState.Idle: - Delay(hit.HitWindowMiss); + Delay(HitObject.HitWindowMiss); break; case ArmedState.Miss: FadeOut(100); break; case ArmedState.Hit: - bodyContainer.ScaleTo(0.8f, 400, EasingTypes.OutQuad); - bodyContainer.MoveToY(-200, 250, EasingTypes.Out); - bodyContainer.Delay(250); - bodyContainer.MoveToY(0, 500, EasingTypes.In); + Content.ScaleTo(0.8f, 400, EasingTypes.OutQuad); + Content.MoveToY(-200, 250, EasingTypes.Out); + Content.Delay(250); + Content.MoveToY(0, 500, EasingTypes.In); FadeOut(600); break; diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs index ff8881172d..5a311d51ef 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableRimHit.cs @@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables public DrawableRimHit(Hit hit) : base(hit) { - Circle.Add(new RimHitSymbolPiece()); + MainPiece.Add(new RimHitSymbolPiece()); } [BackgroundDependencyLoader] private void load(OsuColour colours) { - Circle.AccentColour = colours.BlueDarker; + MainPiece.AccentColour = colours.BlueDarker; } } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongCentreHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongCentreHit.cs index a84c8894d5..4dee29147e 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongCentreHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongCentreHit.cs @@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables public DrawableStrongCentreHit(Hit hit) : base(hit) { - Circle.Add(new CentreHitSymbolPiece()); + MainPiece.Add(new CentreHitSymbolPiece()); } [BackgroundDependencyLoader] private void load(OsuColour colours) { - Circle.AccentColour = colours.PinkDarker; + MainPiece.AccentColour = colours.PinkDarker; } } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongDrumRoll.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongDrumRoll.cs deleted file mode 100644 index bb7e197502..0000000000 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongDrumRoll.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Modes.Taiko.Judgements; -using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; - -namespace osu.Game.Modes.Taiko.Objects.Drawables -{ - public class DrawableStrongDrumRoll : DrawableDrumRoll - { - public DrawableStrongDrumRoll(DrumRoll drumRoll) - : base(drumRoll) - { - } - - protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = true }; - - protected override CirclePiece CreateCirclePiece() => new StrongCirclePiece(); - } -} diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongHit.cs index 107f476ae2..e53c81004f 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongHit.cs @@ -6,8 +6,8 @@ using System.Linq; using osu.Framework.Input; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Taiko.Judgements; -using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; using OpenTK.Input; +using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; namespace osu.Game.Modes.Taiko.Objects.Drawables { @@ -28,9 +28,9 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables { } - protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement(); + protected override TaikoPiece CreateMainPiece() => new CirclePiece(true); - protected override CirclePiece CreateCirclePiece() => new StrongCirclePiece(); + protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement(); protected override void CheckJudgement(bool userTriggered) { diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongRimHit.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongRimHit.cs index 7ab9be548e..10e58a919e 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongRimHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableStrongRimHit.cs @@ -15,13 +15,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables public DrawableStrongRimHit(Hit hit) : base(hit) { - Circle.Add(new RimHitSymbolPiece()); + MainPiece.Add(new RimHitSymbolPiece()); } [BackgroundDependencyLoader] private void load(OsuColour colours) { - Circle.AccentColour = colours.BlueDarker; + MainPiece.AccentColour = colours.BlueDarker; } } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs index 717cda9126..e1a590a025 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableSwell.cs @@ -18,7 +18,7 @@ using OpenTK.Input; namespace osu.Game.Modes.Taiko.Objects.Drawables { - public class DrawableSwell : DrawableTaikoHitObject + public class DrawableSwell : DrawableTaikoHitObject { /// /// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime. @@ -31,8 +31,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables private const float target_ring_scale = 5f; private const float inner_ring_alpha = 0.65f; - private readonly Swell swell; - private readonly Container bodyContainer; private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; @@ -54,12 +52,11 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables public DrawableSwell(Swell swell) : base(swell) { - this.swell = swell; - Children = new Drawable[] { bodyContainer = new Container { + AutoSizeAxes = Axes.Both, Children = new Drawable[] { expandingRing = new CircularContainer @@ -120,6 +117,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables }, circlePiece = new CirclePiece { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Children = new [] { symbol = new SwellSymbolPiece() @@ -146,18 +145,18 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables { userHits++; - var completion = (float)userHits / swell.RequiredHits; + var completion = (float)userHits / HitObject.RequiredHits; expandingRing.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50); expandingRing.Delay(50); expandingRing.FadeTo(completion / 8, 2000, EasingTypes.OutQuint); expandingRing.DelayReset(); - symbol.RotateTo((float)(completion * swell.Duration / 8), 4000, EasingTypes.OutQuint); + symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, EasingTypes.OutQuint); expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint); - if (userHits == swell.RequiredHits) + if (userHits == HitObject.RequiredHits) { Judgement.Result = HitResult.Hit; Judgement.TaikoResult = TaikoHitResult.Great; @@ -169,7 +168,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables return; //TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP - if (userHits > swell.RequiredHits / 2) + if (userHits > HitObject.RequiredHits / 2) { Judgement.Result = HitResult.Hit; Judgement.TaikoResult = TaikoHitResult.Good; @@ -189,7 +188,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables Delay(preempt, true); - Delay(Judgement.TimeOffset + swell.Duration, true); + Delay(Judgement.TimeOffset + HitObject.Duration, true); const float out_transition_time = 300; diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 8afe6ad4cf..e4ab134cf3 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -3,15 +3,18 @@ using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Taiko.Judgements; using osu.Game.Modes.Taiko.Objects.Drawables.Pieces; +using OpenTK; using OpenTK.Input; namespace osu.Game.Modes.Taiko.Objects.Drawables { - public abstract class DrawableTaikoHitObject : DrawableHitObject + public abstract class DrawableTaikoHitObject : DrawableHitObject + where TaikoHitType : TaikoHitObject { /// /// A list of keys which this hit object will accept. These are the standard Taiko keys for now. @@ -19,35 +22,56 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables /// private readonly List validKeys = new List(new[] { Key.D, Key.F, Key.J, Key.K }); - protected DrawableTaikoHitObject(TaikoHitObject hitObject) + public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); + + protected override Container Content => bodyContainer; + + protected readonly TaikoPiece MainPiece; + + private readonly Container bodyContainer; + + public new TaikoHitType HitObject; + + protected DrawableTaikoHitObject(TaikoHitType hitObject) : base(hitObject) { + HitObject = hitObject; + Anchor = Anchor.CentreLeft; - Origin = Anchor.CentreLeft; + Origin = Anchor.Custom; + + AutoSizeAxes = Axes.Both; RelativePositionAxes = Axes.X; + + AddInternal(bodyContainer = new Container + { + AutoSizeAxes = Axes.Both, + Children = new[] + { + MainPiece = CreateMainPiece() + } + }); + + MainPiece.KiaiMode = HitObject.Kiai; } protected override void LoadComplete() { LifetimeStart = HitObject.StartTime - HitObject.PreEmpt * 2; - base.LoadComplete(); } protected override TaikoJudgement CreateJudgement() => new TaikoJudgement(); - protected virtual CirclePiece CreateCirclePiece() => new CirclePiece(); + protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(HitObject.IsStrong); /// /// Sets the scroll position of the DrawableHitObject relative to the offset between /// a time value and the HitObject's StartTime. /// /// - protected virtual void UpdateScrollPosition(double time) - { - MoveToX((float)((HitObject.StartTime - time) / HitObject.PreEmpt)); - } + protected virtual void UpdateScrollPosition(double time) => MoveToX((float)((HitObject.StartTime - time) / HitObject.PreEmpt)); protected override void Update() { diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs index 941ef3b37f..0ac96b02a3 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/CirclePiece.cs @@ -1,12 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using OpenTK.Graphics; @@ -15,26 +13,30 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces /// /// A circle piece which is used uniformly through osu!taiko to visualise hitobjects. /// - /// The body of this piece will overshoot its parent by to form - /// a rounded (_[-Width-]_) figure such that a regular "circle" is the result of a parent with Width = 0. + /// Note that this can actually be non-circle if the width is changed. See + /// for a usage example. /// /// - public class CirclePiece : Container, IHasAccentColour + public class CirclePiece : TaikoPiece { public const float SYMBOL_SIZE = TaikoHitObject.CIRCLE_RADIUS * 2f * 0.45f; public const float SYMBOL_BORDER = 8; public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER; - private Color4 accentColour; + /// + /// The amount to scale up the base circle to show it as a "strong" piece. + /// + private const float strong_scale = 1.5f; + /// /// The colour of the inner circle and outer glows. /// - public Color4 AccentColour + public override Color4 AccentColour { - get { return accentColour; } + get { return base.AccentColour; } set { - accentColour = value; + base.AccentColour = value; background.Colour = AccentColour; @@ -42,107 +44,92 @@ namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces } } - private bool kiaiMode; /// /// Whether Kiai mode effects are enabled for this circle piece. /// - public bool KiaiMode + public override bool KiaiMode { - get { return kiaiMode; } + get { return base.KiaiMode; } set { - kiaiMode = value; + base.KiaiMode = value; resetEdgeEffects(); } } - public override Anchor Origin - { - get { return Anchor.CentreLeft; } - set { throw new InvalidOperationException($"{nameof(CirclePiece)} must always use CentreLeft origin."); } - } + protected override Container Content => content; - protected override Container Content => SymbolContainer; - protected readonly Container SymbolContainer; + private readonly Container content; private readonly Container background; - private readonly Container innerLayer; - public CirclePiece() + public CirclePiece(bool isStrong = false) { - RelativeSizeAxes = Axes.X; - Height = TaikoHitObject.CIRCLE_RADIUS * 2; - - // The "inner layer" is the body of the CirclePiece that overshoots it by Height/2 px on both sides - AddInternal(innerLayer = new Container + AddInternal(new Drawable[] { - Name = "Inner Layer", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Children = new Drawable[] + background = new CircularContainer { - background = new CircularContainer + Name = "Background", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] { - Name = "Background", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new Drawable[] + new Box { - new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - }, - new Triangles - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - ColourLight = Color4.White, - ColourDark = Color4.White.Darken(0.1f) - } - } - }, - new CircularContainer - { - Name = "Ring", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - BorderThickness = 8, - BorderColour = Color4.White, - Masking = true, - Children = new[] + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + }, + new Triangles { - new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + ColourLight = Color4.White, + ColourDark = Color4.White.Darken(0.1f) } - }, - SymbolContainer = new Container - { - Name = "Symbol", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, } + }, + new CircularContainer + { + Name = "Ring", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + BorderThickness = 8, + BorderColour = Color4.White, + Masking = true, + Children = new[] + { + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }, + content = new Container + { + RelativeSizeAxes = Axes.Both, + Name = "Symbol", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, } }); - } - protected override void Update() - { - // Add the overshoot to compensate for corner radius - innerLayer.Width = DrawWidth + DrawHeight; + if (isStrong) + { + Size *= strong_scale; + + //for symbols etc. + Content.Scale *= strong_scale; + } } private void resetEdgeEffects() diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs new file mode 100644 index 0000000000..396392b556 --- /dev/null +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics.Primitives; +using osu.Game.Modes.Taiko.UI; + +namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces +{ + public class ElongatedCirclePiece : CirclePiece + { + /// + /// As we are being used to define the absolute size of hits, we need to be given a relative reference of our containing . + /// + public Func PlayfieldLengthReference; + + /// + /// The length of this piece as a multiple of the value returned by + /// + public float Length; + + public ElongatedCirclePiece(bool isStrong = false) : base(isStrong) + { + } + + protected override void Update() + { + base.Update(); + + var contentPadding = DrawHeight / 2 * Content.Scale.X; + + Content.Padding = new MarginPadding + { + Left = contentPadding, + Right = contentPadding, + }; + + Width = (PlayfieldLengthReference?.Invoke() ?? 0) * Length + DrawHeight; + } + } +} \ No newline at end of file diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/StrongCirclePiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/StrongCirclePiece.cs deleted file mode 100644 index 9676c4a19f..0000000000 --- a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/StrongCirclePiece.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK; - -namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces -{ - /// - /// A type of circle piece which is drawn at a higher scale to represent a "strong" piece. - /// - public class StrongCirclePiece : CirclePiece - { - /// - /// The amount to scale up the base circle to show it as a "strong" piece. - /// - private const float strong_scale = 1.5f; - - public StrongCirclePiece() - { - SymbolContainer.Scale = new Vector2(strong_scale); - } - - public override Vector2 Size => new Vector2(base.Size.X, base.Size.Y * strong_scale); - } -} diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs new file mode 100644 index 0000000000..a0c8865c59 --- /dev/null +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TaikoPiece.cs @@ -0,0 +1,45 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces +{ + public class TaikoPiece : Container, IHasAccentColour + { + private Color4 accentColour; + /// + /// The colour of the inner circle and outer glows. + /// + public virtual Color4 AccentColour + { + get { return accentColour; } + set + { + accentColour = value; + } + } + + private bool kiaiMode; + /// + /// Whether Kiai mode effects are enabled for this circle piece. + /// + public virtual bool KiaiMode + { + get { return kiaiMode; } + set + { + kiaiMode = value; + } + } + + public TaikoPiece() + { + //just a default + Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2); + } + } +} diff --git a/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs new file mode 100644 index 0000000000..697102eb22 --- /dev/null +++ b/osu.Game.Modes.Taiko/Objects/Drawables/Pieces/TickPiece.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces +{ + public class TickPiece : TaikoPiece + { + /// + /// Any tick that is not the first for a drumroll is not filled, but is instead displayed + /// as a hollow circle. This is what controls the border width of that circle. + /// + private const float tick_border_width = TaikoHitObject.CIRCLE_RADIUS / 2 / 4; + + /// + /// The size of a tick. + /// + private const float tick_size = TaikoHitObject.CIRCLE_RADIUS / 2; + + private bool filled; + public bool Filled + { + get { return filled; } + set + { + filled = value; + fillBox.Alpha = filled ? 1 : 0; + } + } + + private readonly Box fillBox; + + public TickPiece() + { + Size = new Vector2(tick_size); + + Add(new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = tick_border_width, + BorderColour = Color4.White, + Children = new[] + { + fillBox = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }); + } + } +} diff --git a/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs index 839471a651..800ee9de9f 100644 --- a/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Modes.Taiko/Objects/TaikoHitObject.cs @@ -25,7 +25,7 @@ namespace osu.Game.Modes.Taiko.Objects public float VelocityMultiplier = 1; /// - /// The time to scroll in the HitObject. + /// The time from the initial right (off-screen) spawn position to the centre of the hit target. /// public double PreEmpt; diff --git a/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs b/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs index c1ee1f6691..2394a88a9e 100644 --- a/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs +++ b/osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs @@ -133,8 +133,6 @@ namespace osu.Game.Modes.Taiko.UI var drumRoll = h as DrumRoll; if (drumRoll != null) { - if (h.IsStrong) - return new DrawableStrongDrumRoll(drumRoll); return new DrawableDrumRoll(drumRoll); } diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index 1fbf1b27a1..a96a95118b 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -61,18 +61,19 @@ - + - + +