diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs new file mode 100644 index 0000000000..1db07b3244 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + internal class DrawableTestHit : DrawableTaikoHitObject + { + private readonly HitResult type; + + public DrawableTestHit(Hit hit, HitResult type = HitResult.Great) + : base(hit) + { + this.type = type; + } + + [BackgroundDependencyLoader] + private void load() + { + Result.Type = type; + } + + public override bool OnPressed(TaikoAction action) => false; + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs new file mode 100644 index 0000000000..791c438c94 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Skinning; +using osu.Game.Rulesets.Taiko.UI; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + [TestFixture] + public class TestSceneHitExplosion : TaikoSkinnableTestScene + { + public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] + { + typeof(HitExplosion), + typeof(LegacyHitExplosion), + typeof(DefaultHitExplosion), + }).ToList(); + + [BackgroundDependencyLoader] + private void load() + { + AddStep("Great", () => SetContents(() => getContentFor(HitResult.Great))); + AddStep("Good", () => SetContents(() => getContentFor(HitResult.Good))); + AddStep("Miss", () => SetContents(() => getContentFor(HitResult.Miss))); + } + + private Drawable getContentFor(HitResult type) + { + DrawableTaikoHitObject hit; + + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + hit = createHit(type), + new HitExplosion(hit) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + }; + } + + private DrawableTaikoHitObject createHit(HitResult type) => new DrawableTestHit(new Hit { StartTime = Time.Current }, type); + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs index 23adb79083..44452d70c1 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs @@ -149,6 +149,8 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; + Add(h); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult }); } @@ -164,6 +166,8 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; + Add(h); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult }); ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great }); } @@ -249,13 +253,5 @@ namespace osu.Game.Rulesets.Taiko.Tests public override bool OnPressed(TaikoAction action) => false; } - - private class DrawableTestHit : DrawableHitObject - { - public DrawableTestHit(TaikoHitObject hitObject) - : base(hitObject) - { - } - } } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs new file mode 100644 index 0000000000..d29b574866 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Rulesets.Taiko.Skinning +{ + public class LegacyHitExplosion : CompositeDrawable + { + public LegacyHitExplosion(Drawable sprite) + { + InternalChild = sprite; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + AutoSizeAxes = Axes.Both; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.FadeIn(120); + this.ScaleTo(0.6f).Then().ScaleTo(1, 240, Easing.OutElastic); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs index 447d6ae455..f0df612e18 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; @@ -81,11 +82,38 @@ namespace osu.Game.Rulesets.Taiko.Skinning return new LegacyBarLine(); return null; + + case TaikoSkinComponents.TaikoExplosionGood: + case TaikoSkinComponents.TaikoExplosionGreat: + case TaikoSkinComponents.TaikoExplosionMiss: + + var sprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); + if (sprite != null) + return new LegacyHitExplosion(sprite); + + return null; } return source.GetDrawableComponent(component); } + private string getHitName(TaikoSkinComponents component) + { + switch (component) + { + case TaikoSkinComponents.TaikoExplosionMiss: + return "taiko-hit0"; + + case TaikoSkinComponents.TaikoExplosionGood: + return "taiko-hit100"; + + case TaikoSkinComponents.TaikoExplosionGreat: + return "taiko-hit300"; + } + + throw new ArgumentOutOfRangeException(nameof(component), "Invalid result type"); + } + public Texture GetTexture(string componentName) => source.GetTexture(componentName); public SampleChannel GetSample(ISampleInfo sampleInfo) => source.GetSample(new LegacyTaikoSampleInfo(sampleInfo)); diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index a90ce608b2..fd091f97d0 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -14,6 +14,9 @@ namespace osu.Game.Rulesets.Taiko HitTarget, PlayfieldBackgroundLeft, PlayfieldBackgroundRight, - BarLine + BarLine, + TaikoExplosionMiss, + TaikoExplosionGood, + TaikoExplosionGreat, } } diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs new file mode 100644 index 0000000000..aa444d0494 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.UI +{ + internal class DefaultHitExplosion : CircularContainer + { + [Resolved] + private DrawableHitObject judgedObject { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.Both; + + BorderColour = Color4.White; + BorderThickness = 1; + + Alpha = 0.15f; + Masking = true; + + if (judgedObject.Result.Type == HitResult.Miss) + return; + + bool isRim = (judgedObject.HitObject as Hit)?.Type == HitType.Rim; + + InternalChildren = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = isRim ? colours.BlueDarker : colours.PinkDarker, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.ScaleTo(3f, 1000, Easing.OutQuint); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index fbaae7e322..35a54d6ea7 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -1,15 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.UI { @@ -20,15 +20,12 @@ namespace osu.Game.Rulesets.Taiko.UI { public override bool RemoveWhenNotAlive => true; + [Cached(typeof(DrawableHitObject))] public readonly DrawableHitObject JudgedObject; - private readonly HitType type; - private readonly Box innerFill; - - public HitExplosion(DrawableHitObject judgedObject, HitType type) + public HitExplosion(DrawableHitObject judgedObject) { JudgedObject = judgedObject; - this.type = type; Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -37,35 +34,36 @@ namespace osu.Game.Rulesets.Taiko.UI Size = new Vector2(TaikoHitObject.DEFAULT_SIZE); RelativePositionAxes = Axes.Both; - - BorderColour = Color4.White; - BorderThickness = 1; - - Alpha = 0.15f; - Masking = true; - - Children = new[] - { - innerFill = new Box - { - RelativeSizeAxes = Axes.Both, - } - }; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - innerFill.Colour = type == HitType.Rim ? colours.BlueDarker : colours.PinkDarker; + Child = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject.Result?.Type ?? HitResult.Great)), _ => new DefaultHitExplosion()); + } + + private TaikoSkinComponents getComponentName(HitResult resultType) + { + switch (resultType) + { + case HitResult.Miss: + return TaikoSkinComponents.TaikoExplosionMiss; + + case HitResult.Good: + return TaikoSkinComponents.TaikoExplosionGood; + + case HitResult.Great: + return TaikoSkinComponents.TaikoExplosionGreat; + } + + throw new ArgumentOutOfRangeException(nameof(resultType), "Invalid result type"); } protected override void LoadComplete() { base.LoadComplete(); - this.ScaleTo(3f, 1000, Easing.OutQuint); this.FadeOut(500); - Expire(true); } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 4bc6cb8e4b..6a78c0a1fb 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -185,7 +185,6 @@ namespace osu.Game.Rulesets.Taiko.UI var drawableTick = (DrawableDrumRollTick)judgedObject; addDrumRollHit(drawableTick); - addExplosion(drawableTick, drawableTick.JudgementType); break; default: @@ -200,7 +199,9 @@ namespace osu.Game.Rulesets.Taiko.UI if (!result.IsHit) break; - addExplosion(judgedObject, (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre); + var type = (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre; + + addExplosion(judgedObject, type); break; } } @@ -210,7 +211,7 @@ namespace osu.Game.Rulesets.Taiko.UI private void addExplosion(DrawableHitObject drawableObject, HitType type) { - hitExplosionContainer.Add(new HitExplosion(drawableObject, type)); + hitExplosionContainer.Add(new HitExplosion(drawableObject)); if (drawableObject.HitObject.Kiai) kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type)); }