diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 77d24db084..2e63160d36 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -31,6 +31,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Container scaleContainer; private InputManager inputManager; + public DrawableHitCircle() + : this(null) + { + } + public DrawableHitCircle([CanBeNull] HitCircle h = null) : base(h) { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 3f91a31066..05e4587307 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -41,6 +41,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Container tickContainer; private Container repeatContainer; + public DrawableSlider() + : this(null) + { + } + public DrawableSlider([CanBeNull] Slider s = null) : base(s) { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index eb125969b0..f04a914fe3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -33,6 +33,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Bindable isSpinning; private bool spinnerFrequencyModulate; + public DrawableSpinner() + : this(null) + { + } + public DrawableSpinner([CanBeNull] Spinner s = null) : base(s) { diff --git a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs index b2299398e1..1c119e2e95 100644 --- a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs @@ -4,12 +4,14 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Pooling; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Input.Handlers; using osu.Game.Replays; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -24,11 +26,28 @@ namespace osu.Game.Rulesets.Osu.UI { protected new OsuRulesetConfigManager Config => (OsuRulesetConfigManager)base.Config; + public new OsuPlayfield Playfield => (OsuPlayfield)base.Playfield; + public DrawableOsuRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) { } + protected override bool PoolHitObjects => true; + + [BackgroundDependencyLoader] + private void load() + { + RegisterPool(10, 100); + RegisterPool(10, 100); + RegisterPool(2, 20); + } + + protected override DrawablePool CreatePool(int initialSize, int? maximumSize = null) + => new OsuDrawablePool(Playfield.CheckHittable, Playfield.OnHitObjectLoaded, initialSize, maximumSize); + + protected override HitObjectLifetimeEntry CreateLifetimeEntry(OsuHitObject hitObject) => new OsuHitObjectLifetimeEntry(hitObject); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor protected override Playfield CreatePlayfield() => new OsuPlayfield(); @@ -39,23 +58,6 @@ namespace osu.Game.Rulesets.Osu.UI protected override ResumeOverlay CreateResumeOverlay() => new OsuResumeOverlay(); - public override DrawableHitObject CreateDrawableRepresentation(OsuHitObject h) - { - switch (h) - { - case HitCircle circle: - return new DrawableHitCircle(circle); - - case Slider slider: - return new DrawableSlider(slider); - - case Spinner spinner: - return new DrawableSpinner(spinner); - } - - return null; - } - protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuFramedReplayInputHandler(replay); protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new OsuReplayRecorder(replay); @@ -70,5 +72,15 @@ namespace osu.Game.Rulesets.Osu.UI return 0; } } + + private class OsuHitObjectLifetimeEntry : HitObjectLifetimeEntry + { + public OsuHitObjectLifetimeEntry(HitObject hitObject) + : base(hitObject) + { + } + + protected override double InitialLifetimeOffset => ((OsuHitObject)HitObject).TimePreempt; + } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuDrawablePool.cs b/osu.Game.Rulesets.Osu/UI/OsuDrawablePool.cs new file mode 100644 index 0000000000..148146f25a --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/OsuDrawablePool.cs @@ -0,0 +1,33 @@ +// 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 osu.Framework.Graphics; +using osu.Framework.Graphics.Pooling; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.UI +{ + public class OsuDrawablePool : DrawablePool + where T : DrawableHitObject, new() + { + private readonly Func checkHittable; + private readonly Action onLoaded; + + public OsuDrawablePool(Func checkHittable, Action onLoaded, int initialSize, int? maximumSize = null) + : base(initialSize, maximumSize) + { + this.checkHittable = checkHittable; + this.onLoaded = onLoaded; + } + + protected override T CreateNewDrawable() => base.CreateNewDrawable().With(o => + { + var osuObject = (DrawableOsuHitObject)(object)o; + + osuObject.CheckHittable = checkHittable; + osuObject.OnLoadComplete += onLoaded; + }); + } +} diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 321eeeab65..5d59a6ff38 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Configuration; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Connections; using osu.Game.Rulesets.Osu.Scoring; @@ -26,6 +27,8 @@ namespace osu.Game.Rulesets.Osu.UI { public class OsuPlayfield : Playfield { + public readonly Func CheckHittable; + private readonly PlayfieldBorder playfieldBorder; private readonly ProxyContainer approachCircles; private readonly ProxyContainer spinnerProxies; @@ -78,6 +81,7 @@ namespace osu.Game.Rulesets.Osu.UI }; hitPolicy = new OrderedHitPolicy(HitObjectContainer); + CheckHittable = hitPolicy.IsHittable; var hitWindows = new OsuHitWindows(); @@ -85,6 +89,8 @@ namespace osu.Game.Rulesets.Osu.UI poolDictionary.Add(result, new DrawableJudgementPool(result)); AddRangeInternal(poolDictionary.Values); + + NewResult += onNewResult; } [BackgroundDependencyLoader(true)] @@ -93,37 +99,37 @@ namespace osu.Game.Rulesets.Osu.UI config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle); } - public override void Add(DrawableHitObject h) + protected override void OnHitObjectAdded(HitObject hitObject) { - DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)h; - - h.OnNewResult += onNewResult; - h.OnLoadComplete += d => - { - if (d is DrawableSpinner) - spinnerProxies.Add(d.CreateProxy()); - - if (d is IDrawableHitObjectWithProxiedApproach c) - approachCircles.Add(c.ProxiedLayer.CreateProxy()); - }; - - base.Add(h); - - osuHitObject.CheckHittable = hitPolicy.IsHittable; - - followPoints.AddFollowPoints(osuHitObject.HitObject); + base.OnHitObjectAdded(hitObject); + followPoints.AddFollowPoints((OsuHitObject)hitObject); } - public override bool Remove(DrawableHitObject h) + protected override void OnHitObjectRemoved(HitObject hitObject) { - DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)h; + base.OnHitObjectRemoved(hitObject); + followPoints.RemoveFollowPoints((OsuHitObject)hitObject); + } - bool result = base.Remove(h); + public void OnHitObjectLoaded(Drawable drawable) + { + switch (drawable) + { + case DrawableSliderHead _: + case DrawableSliderTail _: + case DrawableSliderTick _: + case DrawableSliderRepeat _: + case DrawableSpinnerTick _: + break; - if (result) - followPoints.RemoveFollowPoints(osuHitObject.HitObject); + case DrawableSpinner _: + spinnerProxies.Add(drawable.CreateProxy()); + break; - return result; + case IDrawableHitObjectWithProxiedApproach approach: + approachCircles.Add(approach.ProxiedLayer.CreateProxy()); + break; + } } private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)