1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-30 03:02:54 +08:00

WIP: use pooling without spliting Hit into two classes

But there is still problem with Editor. We should to call `ReLoadMainPiece` from Editor to update drawable hit's OR do it somehow else by reaching TaikoPlayfield from Editor.

(we should to get `TaikoPlayfield` from Editor in any case: we should to take DrawableHit's somehow)
This commit is contained in:
Nikita-str 2024-12-26 23:46:57 +03:00
parent fa0d2f4af2
commit 45c81aacc4
12 changed files with 118 additions and 45 deletions

View File

@ -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<TaikoAction> 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

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -43,7 +43,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> 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());
}
}

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -0,0 +1,23 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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
{
/// <summary>Pool for hit of a specific HitType.</summary>
internal partial class HitPool : DrawablePool<DrawableHit>
{
private readonly HitType hitType;
public HitPool(HitType hitType, int initialSize)
: base(initialSize)
{
this.hitType = hitType;
}
protected override DrawableHit CreateNewDrawable() => new DrawableHit(new Hit(hitType));
}
}

View File

@ -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<Hit, DrawableHit>(50);
RegisterPool<Hit.StrongNestedHit, DrawableHit.StrongNestedHit>(50);
RegisterPool<DrumRoll, DrawableDrumRoll>(5);
@ -194,13 +194,31 @@ namespace osu.Game.Rulesets.Taiko.UI
var hitWindows = new TaikoHitWindows();
HitResult[] usableHitResults = Enum.GetValues<HitResult>().Where(r => hitWindows.IsHitResultAllowed(r)).ToArray();
HitResult[] usableHitResults = Enum.GetValues<HitResult>().Where(hitWindows.IsHitResultAllowed).ToArray();
AddInternal(judgementPooler = new JudgementPooler<DrawableTaikoJudgement>(usableHitResults));
foreach (var result in usableHitResults)
explosionPools.Add(result, new HitExplosionPool(result));
AddRangeInternal(explosionPools.Values);
AddRangeInternal(poolsHit.Values);
}
private readonly IDictionary<HitType, HitPool> poolsHit = new Dictionary<HitType, HitPool>()
{
{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()

View File

@ -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;
/// <summary>
/// Creates the <see cref="HitObjectLifetimeEntry"/> for a given <see cref="HitObject"/>.
/// </summary>
@ -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)
{