diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 547d0afe4a..82c92ab1e5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -6,19 +6,19 @@ using System; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Utils; -using osu.Game.Graphics; -using osu.Game.Rulesets.Objects.Drawables; -using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; +using osu.Framework.Utils; +using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -77,9 +77,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables OnNewResult += onNewResult; } - protected override void RecreatePieces() + protected override void RestorePieceState() { - base.RecreatePieces(); updateColour(); Height = HitObject.IsStrong ? TaikoStrongableHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE; } @@ -119,8 +118,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.CreateNestedHitObject(hitObject); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollBody), - _ => new ElongatedCirclePiece()); + protected override SkinnableDrawable OnLoadCreateMainPiece() + => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollBody), _ => new ElongatedCirclePiece()); public override bool OnPressed(KeyBindingPressEvent e) => false; @@ -174,7 +173,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private void updateColour(double fadeDuration = 0) { Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1); - (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); + (MainPiece?.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); } public partial class StrongNestedHit : DrawableStrongNestedHit diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 64d2020edc..5b8bb5500d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables FillMode = FillMode.Fit; } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); + protected override SkinnableDrawable OnLoadCreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); protected override void OnApply() { @@ -45,9 +45,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables IsFirstTick.Value = HitObject.FirstTick; } - protected override void RecreatePieces() + protected override void RestorePieceState() { - base.RecreatePieces(); Size = new Vector2(HitObject.IsStrong ? TaikoStrongableHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE); } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs index aad9214c5e..bf9e46ed07 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs @@ -3,6 +3,8 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Taiko.Skinning.Default; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -26,6 +28,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.LoadComplete(); ApplyMaxResult(); + Size = new osuTK.Vector2(0.3f); + } + + private static float degree = 0f; + protected override void PrepareForUse() + { + const float single_rotation_degree = 7f; + + base.PrepareForUse(); + degree = (degree + single_rotation_degree) % 360f; + Rotation = degree; } protected override void LoadSamples() @@ -33,5 +46,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // block base call - flying hits are not supposed to play samples // the base call could overwrite the type of this hit } + + // TODO: which skin use? + protected override SkinnableDrawable? OnLoadCreateMainPiece() + => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), _ => new SwellCirclePiece(), confineMode: ConfineMode.ScaleToFit); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 28831a6d2c..b9522b9f67 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -55,15 +55,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { type.BindTo(HitObject.TypeBindable); // this doesn't need to be run inline as RecreatePieces is called by the base call below. - type.BindValueChanged(_ => Scheduler.AddOnce(RecreatePieces)); + type.BindValueChanged(_ => Scheduler.AddOnce(RestorePieceState)); base.OnApply(); } - protected override void RecreatePieces() + protected override void RestorePieceState() { updateActionsFromType(); - base.RecreatePieces(); Size = new Vector2(HitObject.IsStrong ? TaikoStrongableHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE); } @@ -90,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables : new[] { TaikoAction.LeftRim, TaikoAction.RightRim }; } - protected override SkinnableDrawable CreateMainPiece() => HitObject.Type == HitType.Centre + protected override SkinnableDrawable OnLoadCreateMainPiece() => HitObject.Type == HitType.Centre ? new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.CentreHit), _ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit) : new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.RimHit), _ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 28617b35f6..3ce4ac447d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -10,16 +10,16 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Rulesets.Objects.Drawables; -using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), + protected override SkinnableDrawable OnLoadCreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), _ => new SwellCirclePiece { // to allow for rotation transform @@ -144,9 +144,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Origin = Anchor.Centre, }); - protected override void RecreatePieces() + protected override void RestorePieceState() { - base.RecreatePieces(); Size = baseSize = new Vector2(TaikoHitObject.DEFAULT_SIZE); } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 04dd01e066..0098e9ac0a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -43,7 +43,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public override bool OnPressed(KeyBindingPressEvent e) => false; - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), - _ => new TickPiece()); + protected override void RestorePieceState() { } + protected override SkinnableDrawable OnLoadCreateMainPiece() + => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 0cf9651965..e5fd1838a1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; @@ -141,22 +142,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both; } + [BackgroundDependencyLoader] + private void load() + { + var drawable = OnLoadCreateMainPiece(); + if (drawable is not null) + Content.Add(MainPiece = drawable); + } + protected override void OnApply() { base.OnApply(); + // TODO: now it fixed, yes? // TODO: THIS CANNOT BE HERE, it makes pooling pointless (see https://github.com/ppy/osu/issues/21072). - RecreatePieces(); + RestorePieceState(); } - protected virtual void RecreatePieces() + protected abstract void RestorePieceState(); + protected abstract SkinnableDrawable OnLoadCreateMainPiece(); + + // TODO: call it from Editor OR even delete it and use somehow TaikoPlayfield from Editor + public unsafe void ReLoadMainPiece() { - if (MainPiece != null) - Content.Remove(MainPiece, true); - - Content.Add(MainPiece = CreateMainPiece()); + Content.Remove(MainPiece, true); + load(); } - - protected abstract SkinnableDrawable CreateMainPiece(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs index 7c3ff4f27e..93fd6af496 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { isStrong.BindTo(HitObject.IsStrongBindable); // this doesn't need to be run inline as RecreatePieces is called by the base call below. - isStrong.BindValueChanged(_ => Scheduler.AddOnce(RecreatePieces)); + isStrong.BindValueChanged(_ => Scheduler.AddOnce(RestorePieceState)); base.OnApply(); } diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 156e890607..f41ea3216d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -42,6 +42,11 @@ namespace osu.Game.Rulesets.Taiko.Objects SamplesBindable.BindCollectionChanged((_, _) => updateTypeFromSamples()); } + public Hit(HitType type) : this() + { + Type = type; + } + private void updateTypeFromSamples() { Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; diff --git a/osu.Game.Rulesets.Taiko/UI/HitPool.cs b/osu.Game.Rulesets.Taiko/UI/HitPool.cs new file mode 100644 index 0000000000..f627304fd6 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/UI/HitPool.cs @@ -0,0 +1,23 @@ +// 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.Pooling; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.UI +{ + /// Pool for hit of a specific HitType. + internal partial class HitPool : DrawablePool + { + private readonly HitType hitType; + + public HitPool(HitType hitType, int initialSize) + : base(initialSize) + { + this.hitType = hitType; + } + + protected override DrawableHit CreateNewDrawable() => new DrawableHit(new Hit(hitType)); + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index bdcb341fb4..b518e6e4de 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -7,17 +7,18 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Game.Graphics; -using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; -using osu.Game.Rulesets.UI.Scrolling; -using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.UI @@ -180,7 +181,6 @@ namespace osu.Game.Rulesets.Taiko.UI inputDrum, }; - RegisterPool(50); RegisterPool(50); RegisterPool(5); @@ -194,13 +194,31 @@ namespace osu.Game.Rulesets.Taiko.UI var hitWindows = new TaikoHitWindows(); - HitResult[] usableHitResults = Enum.GetValues().Where(r => hitWindows.IsHitResultAllowed(r)).ToArray(); + HitResult[] usableHitResults = Enum.GetValues().Where(hitWindows.IsHitResultAllowed).ToArray(); AddInternal(judgementPooler = new JudgementPooler(usableHitResults)); foreach (var result in usableHitResults) explosionPools.Add(result, new HitExplosionPool(result)); AddRangeInternal(explosionPools.Values); + + AddRangeInternal(poolsHit.Values); + } + + private readonly IDictionary poolsHit = new Dictionary() + { + {HitType.Centre, new HitPool(HitType.Centre, 50)}, + {HitType.Rim, new HitPool(HitType.Rim, 50)}, + }; + protected override IDrawablePool? AdditionalPrepareDrawablePool(HitObject hitObject) + { + switch (hitObject) + { + case Hit hit: return poolsHit[hit.Type]; + // TODO: ??? + //case Hit.StrongNestedHit hitStrong: return ; + default: return null; + } } protected override void LoadComplete() diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 90a2f63faa..c3a978f05b 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -11,19 +11,19 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; +using osu.Framework.Graphics.Primitives; using osu.Game.Audio; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Pooling; using osu.Game.Skinning; using osuTK; -using osu.Game.Rulesets.Objects.Pooling; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.UI { @@ -350,6 +350,8 @@ namespace osu.Game.Rulesets.UI OnHitObjectRemoved(entry.HitObject); } + protected virtual IDrawablePool AdditionalPrepareDrawablePool(HitObject hitObject) => null; + /// /// Creates the for a given . /// @@ -430,12 +432,13 @@ namespace osu.Game.Rulesets.UI private IDrawablePool prepareDrawableHitObjectPool(HitObject hitObject) { + var additional = AdditionalPrepareDrawablePool(hitObject); + if (additional is not null) return additional; + var lookupType = hitObject.GetType(); - IDrawablePool pool; - // Tests may add derived hitobject instances for which pools don't exist. Try to find any applicable pool and dynamically assign the type if the pool exists. - if (!pools.TryGetValue(lookupType, out pool)) + if (!pools.TryGetValue(lookupType, out var pool)) { foreach (var (t, p) in pools) {