diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs
index 129dd07c3e..63378e57cc 100644
--- a/osu.Game/Rulesets/Judgements/Judgement.cs
+++ b/osu.Game/Rulesets/Judgements/Judgement.cs
@@ -28,19 +28,19 @@ namespace osu.Game.Rulesets.Judgements
///
public int HighestComboAtJudgement;
+ ///
+ /// Whether this has a result.
+ ///
+ public bool HasResult => Result > HitResult.None;
+
///
/// Whether a successful hit occurred.
///
public bool IsHit => Result > HitResult.Miss;
- ///
- /// Whether this judgement is the final judgement for the hit object.
- ///
- public bool Final = true;
-
///
/// The offset from a perfect hit at which this judgement occurred.
- /// Populated when added via .
+ /// Populated when added via .
///
public double TimeOffset { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index a22aaa784f..b767834e5d 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -38,9 +38,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
public event Action OnJudgement;
public event Action OnJudgementRemoved;
- public IReadOnlyList Judgements => judgements;
- private readonly List judgements = new List();
-
///
/// Whether a visible judgement should be displayed when this representation is hit.
///
@@ -49,20 +46,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
/// Whether this and all of its nested s have been hit.
///
- public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && NestedHitObjects.All(n => n.IsHit);
+ public bool IsHit => HitObject.Judgements.All(j => j.IsHit) && NestedHitObjects.All(n => n.IsHit);
///
/// Whether this and all of its nested s have been judged.
///
- public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && NestedHitObjects.All(h => h.AllJudged);
+ public bool AllJudged => Judged && NestedHitObjects.All(h => h.AllJudged);
///
- /// Whether this can be judged.
+ /// Whether this has been judged.
+ /// Note: This does NOT include nested hitobjects.
///
- protected virtual bool ProvidesJudgement => true;
+ public bool Judged => HitObject.Judgements.All(h => h.HasResult);
private bool judgementOccurred;
- private bool judgementFinalized => judgements.LastOrDefault()?.Final == true;
public bool Interactive = true;
public override bool HandleKeyboardInput => Interactive;
@@ -128,23 +125,31 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
public void PlaySamples() => Samples?.Play();
+ private double lastUpdateTime;
+
protected override void Update()
{
base.Update();
- var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
-
- while (judgements.Count > 0)
+ if (lastUpdateTime > Time.Current)
{
- var lastJudgement = judgements[judgements.Count - 1];
- if (lastJudgement.TimeOffset + endTime <= Time.Current)
- break;
+ var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
- judgements.RemoveAt(judgements.Count - 1);
- State.Value = ArmedState.Idle;
+ for (int i = HitObject.Judgements.Count - 1; i >= 0; i--)
+ {
+ var judgement = HitObject.Judgements[i];
- OnJudgementRemoved?.Invoke(this, lastJudgement);
+ if (judgement.TimeOffset + endTime <= Time.Current)
+ break;
+
+ judgement.Result = HitResult.None;
+ State.Value = ArmedState.Idle;
+
+ OnJudgementRemoved?.Invoke(this, judgement);
+ }
}
+
+ lastUpdateTime = Time.Current;
}
protected override void UpdateAfterChildren()
@@ -167,16 +172,17 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Notifies that a new judgement has occurred for this .
///
/// The .
- protected void AddJudgement(Judgement judgement)
+ protected void ApplyJudgement(T judgement, Action application)
+ where T : Judgement
{
judgementOccurred = true;
+ application?.Invoke(judgement);
+
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
judgement.TimeOffset = Time.Current - endTime;
- judgements.Add(judgement);
-
switch (judgement.Result)
{
case HitResult.None:
@@ -207,7 +213,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
foreach (var d in NestedHitObjects)
judgementOccurred |= d.UpdateJudgement(userTriggered);
- if (!ProvidesJudgement || judgementFinalized || judgementOccurred)
+ if (judgementOccurred || Judged)
return judgementOccurred;
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
@@ -218,7 +224,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
/// Checks if any judgements have occurred for this . This method must construct
- /// all s and notify of them through .
+ /// all s and notify of them through .
///
/// Whether the user triggered this check.
/// The offset from the end time at which this check occurred. A > 0
diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs
index 15c24e2975..0e029a8657 100644
--- a/osu.Game/Rulesets/Objects/HitObject.cs
+++ b/osu.Game/Rulesets/Objects/HitObject.cs
@@ -3,12 +3,14 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Lists;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Objects
@@ -62,6 +64,9 @@ namespace osu.Game.Rulesets.Objects
[JsonIgnore]
public IReadOnlyList NestedHitObjects => nestedHitObjects.Value;
+ private readonly List judgements = new List();
+ public IReadOnlyList Judgements => judgements;
+
///
/// Applies default values to this HitObject.
///
@@ -71,6 +76,9 @@ namespace osu.Game.Rulesets.Objects
{
ApplyDefaultsToSelf(controlPointInfo, difficulty);
+ judgements.Clear();
+ judgements.AddRange(CreateJudgements());
+
if (nestedHitObjects.IsValueCreated)
nestedHitObjects.Value.Clear();
@@ -103,6 +111,8 @@ namespace osu.Game.Rulesets.Objects
{
}
+ protected virtual IEnumerable CreateJudgements() => Enumerable.Empty();
+
protected void AddNested(HitObject hitObject) => nestedHitObjects.Value.Add(hitObject);
///