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