1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 11:20:04 +08:00

Add top-level osu! hitobject pooling

This commit is contained in:
smoogipoo 2020-11-11 00:22:06 +09:00
parent 39d37c4779
commit bf72961959
6 changed files with 108 additions and 42 deletions

View File

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

View File

@ -41,6 +41,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private Container<DrawableSliderTick> tickContainer;
private Container<DrawableSliderRepeat> repeatContainer;
public DrawableSlider()
: this(null)
{
}
public DrawableSlider([CanBeNull] Slider s = null)
: base(s)
{

View File

@ -33,6 +33,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private Bindable<bool> isSpinning;
private bool spinnerFrequencyModulate;
public DrawableSpinner()
: this(null)
{
}
public DrawableSpinner([CanBeNull] Spinner s = null)
: base(s)
{

View File

@ -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<Mod> mods = null)
: base(ruleset, beatmap, mods)
{
}
protected override bool PoolHitObjects => true;
[BackgroundDependencyLoader]
private void load()
{
RegisterPool<HitCircle, DrawableHitCircle>(10, 100);
RegisterPool<Slider, DrawableSlider>(10, 100);
RegisterPool<Spinner, DrawableSpinner>(2, 20);
}
protected override DrawablePool<TDrawable> CreatePool<TDrawable>(int initialSize, int? maximumSize = null)
=> new OsuDrawablePool<TDrawable>(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<OsuHitObject> 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;
}
}
}

View File

@ -0,0 +1,33 @@
// 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 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<T> : DrawablePool<T>
where T : DrawableHitObject, new()
{
private readonly Func<DrawableHitObject, double, bool> checkHittable;
private readonly Action<Drawable> onLoaded;
public OsuDrawablePool(Func<DrawableHitObject, double, bool> checkHittable, Action<Drawable> 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;
});
}
}

View File

@ -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<DrawableHitObject, double, bool> 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)