1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 15:27:24 +08:00

Combine hit types and remove old drumroll hits using a more efficient method

This commit is contained in:
Dean Herbert 2020-04-27 16:13:28 +09:00
parent ff736a22dd
commit b9f28c8373
10 changed files with 67 additions and 113 deletions

View File

@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[] public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
{ {
typeof(DrawableHit), typeof(DrawableHit),
typeof(DrawableCentreHit),
typeof(DrawableRimHit),
typeof(LegacyHit), typeof(LegacyHit),
typeof(LegacyCirclePiece), typeof(LegacyCirclePiece),
}).ToList(); }).ToList();
@ -30,25 +28,25 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
AddStep("Centre hit", () => SetContents(() => new DrawableCentreHit(createHitAtCurrentTime()) AddStep("Centre hit", () => SetContents(() => new DrawableHit(createHitAtCurrentTime())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
})); }));
AddStep("Centre hit (strong)", () => SetContents(() => new DrawableCentreHit(createHitAtCurrentTime(true)) AddStep("Centre hit (strong)", () => SetContents(() => new DrawableHit(createHitAtCurrentTime(true))
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
})); }));
AddStep("Rim hit", () => SetContents(() => new DrawableRimHit(createHitAtCurrentTime()) AddStep("Rim hit", () => SetContents(() => new DrawableHit(createHitAtCurrentTime())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
})); }));
AddStep("Rim hit (strong)", () => SetContents(() => new DrawableRimHit(createHitAtCurrentTime(true)) AddStep("Rim hit (strong)", () => SetContents(() => new DrawableHit(createHitAtCurrentTime(true))
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -224,7 +224,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
drawableRuleset.Playfield.Add(new DrawableCentreHit(h)); drawableRuleset.Playfield.Add(new DrawableHit(h));
} }
private void addRimHit(bool strong) private void addRimHit(bool strong)
@ -237,7 +237,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
drawableRuleset.Playfield.Add(new DrawableRimHit(h)); drawableRuleset.Playfield.Add(new DrawableHit(h));
} }
private class TestStrongNestedHit : DrawableStrongNestedHit private class TestStrongNestedHit : DrawableStrongNestedHit

View File

@ -1,21 +0,0 @@
// 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.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
public class DrawableCentreHit : DrawableHit
{
public override TaikoAction[] HitActions { get; } = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
public DrawableCentreHit(Hit hit)
: base(hit)
{
}
protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.CentreHit),
_ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit);
}
}

View File

@ -6,7 +6,10 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public class DrawableFlyingCentreHit : DrawableCentreHit /// <summary>
/// A hit used specifically for drum rolls, where spawning flying hits is required.
/// </summary>
public class DrawableFlyingHit : DrawableHit
{ {
protected override void LoadComplete() protected override void LoadComplete()
{ {
@ -14,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = r.Judgement.MaxResult); ApplyResult(r => r.Type = r.Judgement.MaxResult);
} }
public DrawableFlyingCentreHit(double time, bool isStrong = false) public DrawableFlyingHit(double time, bool isStrong = false)
: base(new IgnoreHit { StartTime = time, IsStrong = isStrong }) : base(new IgnoreHit { StartTime = time, IsStrong = isStrong })
{ {
HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

View File

@ -1,23 +0,0 @@
// 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.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
public class DrawableFlyingRimHit : DrawableRimHit
{
protected override void LoadComplete()
{
base.LoadComplete();
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
public DrawableFlyingRimHit(double time, bool isStrong = false)
: base(new IgnoreHit { StartTime = time, IsStrong = isStrong })
{
HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
}
}
}

View File

@ -8,31 +8,45 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public abstract class DrawableHit : DrawableTaikoHitObject<Hit> public class DrawableHit : DrawableTaikoHitObject<Hit>
{ {
/// <summary> /// <summary>
/// A list of keys which can result in hits for this HitObject. /// A list of keys which can result in hits for this HitObject.
/// </summary> /// </summary>
public abstract TaikoAction[] HitActions { get; } public TaikoAction[] HitActions { get; }
/// <summary> /// <summary>
/// The action that caused this <see cref="DrawableHit"/> to be hit. /// The action that caused this <see cref="DrawableHit"/> to be hit.
/// </summary> /// </summary>
public TaikoAction? HitAction { get; private set; } public TaikoAction? HitAction
{
get;
private set;
}
private bool validActionPressed; private bool validActionPressed;
private bool pressHandledThisFrame; private bool pressHandledThisFrame;
protected DrawableHit(Hit hit) public DrawableHit(Hit hit)
: base(hit) : base(hit)
{ {
FillMode = FillMode.Fit; FillMode = FillMode.Fit;
HitActions =
HitObject.Type == HitType.Centre
? new[] { TaikoAction.LeftCentre, TaikoAction.RightCentre }
: new[] { TaikoAction.LeftRim, TaikoAction.RightRim };
} }
protected override SkinnableDrawable CreateMainPiece() => HitObject.Type == HitType.Centre
? new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.CentreHit), _ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit)
: new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.RimHit), _ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit);
protected override void CheckForResult(bool userTriggered, double timeOffset) protected override void CheckForResult(bool userTriggered, double timeOffset)
{ {
Debug.Assert(HitObject.HitWindows != null); Debug.Assert(HitObject.HitWindows != null);
@ -58,7 +72,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
if (pressHandledThisFrame) if (pressHandledThisFrame)
return true; return true;
if (Judged) if (Judged)
return false; return false;
@ -66,14 +79,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
// Only count this as handled if the new judgement is a hit // Only count this as handled if the new judgement is a hit
var result = UpdateResult(true); var result = UpdateResult(true);
if (IsHit) if (IsHit)
HitAction = action; HitAction = action;
// Regardless of whether we've hit or not, any secondary key presses in the same frame should be discarded // Regardless of whether we've hit or not, any secondary key presses in the same frame should be discarded
// E.g. hitting a non-strong centre as a strong should not fall through and perform a hit on the next note // E.g. hitting a non-strong centre as a strong should not fall through and perform a hit on the next note
pressHandledThisFrame = true; pressHandledThisFrame = true;
return result; return result;
} }
@ -81,7 +92,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
if (action == HitAction) if (action == HitAction)
HitAction = null; HitAction = null;
base.OnReleased(action); base.OnReleased(action);
} }

View File

@ -1,21 +0,0 @@
// 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.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
public class DrawableRimHit : DrawableHit
{
public override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
public DrawableRimHit(Hit hit)
: base(hit)
{
}
protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.RimHit),
_ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit);
}
}

View File

@ -49,10 +49,7 @@ namespace osu.Game.Rulesets.Taiko.UI
switch (h) switch (h)
{ {
case Hit hit: case Hit hit:
if (hit.Type == HitType.Centre) return new DrawableHit(hit);
return new DrawableCentreHit(hit);
else
return new DrawableRimHit(hit);
case DrumRoll drumRoll: case DrumRoll drumRoll:
return new DrawableDrumRoll(drumRoll); return new DrawableDrumRoll(drumRoll);

View File

@ -0,0 +1,35 @@
// 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.Containers;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Taiko.UI
{
internal class DrumRollHitContainer : ScrollingHitObjectContainer
{
protected override void Update()
{
base.Update();
// Remove any auxiliary hit notes that were spawned during a drum roll but subsequently rewound.
for (var i = AliveInternalChildren.Count - 1; i >= 0; i--)
{
var flyingHit = (DrawableFlyingHit)AliveInternalChildren[i];
if (Time.Current < flyingHit.HitObject.StartTime)
Remove(flyingHit);
}
}
protected override void OnChildLifetimeBoundaryCrossed(LifetimeBoundaryCrossedEvent e)
{
base.OnChildLifetimeBoundaryCrossed(e);
// ensure all old hits are removed on becoming alive (may miss being in the AliveInternalChildren list above).
if (e.Kind == LifetimeBoundaryKind.Start && e.Direction == LifetimeBoundaryCrossingDirection.Backward)
Remove((DrawableHitObject)e.Child);
}
}
}

View File

@ -93,10 +93,7 @@ namespace osu.Game.Rulesets.Taiko.UI
Children = new Drawable[] Children = new Drawable[]
{ {
HitObjectContainer, HitObjectContainer,
drumRollHitContainer = new ScrollingHitObjectContainer drumRollHitContainer = new DrumRollHitContainer()
{
Name = "Drumroll hit"
}
} }
}, },
kiaiExplosionContainer = new Container<KiaiHitExplosion> kiaiExplosionContainer = new Container<KiaiHitExplosion>
@ -149,23 +146,11 @@ namespace osu.Game.Rulesets.Taiko.UI
// This is basically allowing for correct alignment as relative pieces move around them. // This is basically allowing for correct alignment as relative pieces move around them.
rightArea.Padding = new MarginPadding { Left = leftArea.DrawWidth }; rightArea.Padding = new MarginPadding { Left = leftArea.DrawWidth };
hitTargetOffsetContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 }; hitTargetOffsetContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
// When rewinding, make sure to remove any auxiliary hit notes that were
// spawned and played during a drum roll.
if (Time.Elapsed < 0)
{
foreach (var o in drumRollHitContainer.Objects)
{
if (o.HitObject.StartTime >= Time.Current)
drumRollHitContainer.Remove(o);
}
}
} }
public override void Add(DrawableHitObject h) public override void Add(DrawableHitObject h)
{ {
h.OnNewResult += OnNewResult; h.OnNewResult += OnNewResult;
base.Add(h); base.Add(h);
switch (h) switch (h)
@ -184,7 +169,6 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
if (!DisplayJudgements.Value) if (!DisplayJudgements.Value)
return; return;
if (!judgedObject.DisplayResult) if (!judgedObject.DisplayResult)
return; return;
@ -226,20 +210,12 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
bool isStrong = drawableTick.HitObject.IsStrong; bool isStrong = drawableTick.HitObject.IsStrong;
double time = drawableTick.HitObject.GetEndTime(); double time = drawableTick.HitObject.GetEndTime();
drumRollHitContainer.Add(new DrawableFlyingHit(time, isStrong));
DrawableHit drawableHit;
if (drawableTick.JudgementType == HitType.Rim)
drawableHit = new DrawableFlyingRimHit(time, isStrong);
else
drawableHit = new DrawableFlyingCentreHit(time, isStrong);
drumRollHitContainer.Add(drawableHit);
} }
private void addExplosion(DrawableHitObject drawableObject, HitType type) private void addExplosion(DrawableHitObject drawableObject, HitType type)
{ {
hitExplosionContainer.Add(new HitExplosion(drawableObject, type)); hitExplosionContainer.Add(new HitExplosion(drawableObject, type));
if (drawableObject.HitObject.Kiai) if (drawableObject.HitObject.Kiai)
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type)); kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
} }