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

Split out judgement definition from judgement result

This commit is contained in:
smoogipoo 2018-08-02 20:35:54 +09:00
parent cd70e5e30b
commit 3619290c34
7 changed files with 161 additions and 111 deletions

View File

@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Judgements
private OsuColour colours; private OsuColour colours;
protected readonly Judgement Judgement; protected readonly JudgementResult Result;
public readonly DrawableHitObject JudgedObject; public readonly DrawableHitObject JudgedObject;
@ -34,11 +34,11 @@ namespace osu.Game.Rulesets.Judgements
/// <summary> /// <summary>
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>. /// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
/// </summary> /// </summary>
/// <param name="judgement">The judgement to visualise.</param> /// <param name="result">The judgement to visualise.</param>
/// <param name="judgedObject">The object which was judged.</param> /// <param name="judgedObject">The object which was judged.</param>
public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject) public DrawableJudgement(JudgementResult result, DrawableHitObject judgedObject)
{ {
Judgement = judgement; Result = result;
JudgedObject = judgedObject; JudgedObject = judgedObject;
Size = new Vector2(judgement_size); Size = new Vector2(judgement_size);
@ -49,11 +49,11 @@ namespace osu.Game.Rulesets.Judgements
{ {
this.colours = colours; this.colours = colours;
Child = new SkinnableDrawable($"Play/{Judgement.Result}", _ => JudgementText = new OsuSpriteText Child = new SkinnableDrawable($"Play/{Result.Type}", _ => JudgementText = new OsuSpriteText
{ {
Text = Judgement.Result.GetDescription().ToUpperInvariant(), Text = Result.Type.GetDescription().ToUpperInvariant(),
Font = @"Venera", Font = @"Venera",
Colour = judgementColour(Judgement.Result), Colour = judgementColour(Result.Type),
Scale = new Vector2(0.85f, 1), Scale = new Vector2(0.85f, 1),
TextSize = 12 TextSize = 12
}, restrictSize: false); }, restrictSize: false);
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Judgements
this.FadeInFromZero(100, Easing.OutQuint); this.FadeInFromZero(100, Easing.OutQuint);
switch (Judgement.Result) switch (Result.Type)
{ {
case HitResult.None: case HitResult.None:
break; break;

View File

@ -1,74 +1,44 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Judgements namespace osu.Game.Rulesets.Judgements
{ {
public class Judgement public class Judgement
{ {
/// <summary>
/// Whether this judgement is the result of a hit or a miss.
/// </summary>
public HitResult Result;
/// <summary> /// <summary>
/// The maximum <see cref="HitResult"/> that can be achieved. /// The maximum <see cref="HitResult"/> that can be achieved.
/// </summary> /// </summary>
public virtual HitResult MaxResult => HitResult.Perfect; public virtual HitResult MaxResult => HitResult.Perfect;
/// <summary> /// <summary>
/// The combo prior to this judgement occurring. /// Whether this <see cref="Judgement"/> should affect the current combo.
/// </summary>
public int ComboAtJudgement;
/// <summary>
/// The highest combo achieved prior to this judgement occurring.
/// </summary>
public int HighestComboAtJudgement;
/// <summary>
/// Whether this <see cref="Judgement"/> has a result.
/// </summary>
public bool HasResult => Result > HitResult.None;
/// <summary>
/// Whether a successful hit occurred.
/// </summary>
public bool IsHit => Result > HitResult.Miss;
/// <summary>
/// The offset from a perfect hit at which this judgement occurred.
/// Populated when added via <see cref="DrawableHitObject.ApplyJudgement"/>.
/// </summary>
public double TimeOffset { get; set; }
/// <summary>
/// Whether the <see cref="Result"/> should affect the current combo.
/// </summary> /// </summary>
public virtual bool AffectsCombo => true; public virtual bool AffectsCombo => true;
/// <summary> /// <summary>
/// Whether the <see cref="Result"/> should be counted as base (combo) or bonus score. /// Whether this <see cref="Judgement"/> should be counted as base (combo) or bonus score.
/// </summary> /// </summary>
public virtual bool IsBonus => !AffectsCombo; public virtual bool IsBonus => !AffectsCombo;
/// <summary> /// <summary>
/// The numeric representation for the result achieved. /// The numeric score representation for the maximum achievable result.
/// </summary>
public int NumericResult => NumericResultFor(Result);
/// <summary>
/// The numeric representation for the maximum achievable result.
/// </summary> /// </summary>
public int MaxNumericResult => NumericResultFor(MaxResult); public int MaxNumericResult => NumericResultFor(MaxResult);
/// <summary> /// <summary>
/// Convert a <see cref="HitResult"/> to a numeric score representation. /// Retrieves the numeric score representation of a <see cref="HitResult"/>.
/// </summary> /// </summary>
/// <param name="result">The value to convert.</param> /// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
/// <returns>The number.</returns> /// <returns>The numeric score representation of <paramref name="result"/>.</returns>
protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0; protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0;
/// <summary>
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
/// </summary>
/// <param name="result">The <see cref="JudgementResult"/> to find the numeric score representation for.</param>
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type);
} }
} }

View File

@ -0,0 +1,51 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Judgements
{
public class JudgementResult
{
/// <summary>
/// Whether this <see cref="JudgementResult"/> is the result of a hit or a miss.
/// </summary>
public HitResult Type;
/// <summary>
/// The <see cref="Judgement"/> which this <see cref="JudgementResult"/> applies for.
/// </summary>
public readonly Judgement Judgement;
/// <summary>
/// The offset from a perfect hit at which this <see cref="JudgementResult"/> occurred.
/// Populated when added via <see cref="DrawableHitObject.ApplyJudgement"/>.
/// </summary>
public double TimeOffset { get; internal set; }
/// <summary>
/// The combo prior to this judgement occurring.
/// </summary>
public int ComboAtJudgement { get; internal set; }
/// <summary>
/// The highest combo achieved prior to this judgement occurring.
/// </summary>
public int HighestComboAtJudgement { get; internal set; }
/// <summary>
/// Whether this <see cref="Judgement"/> has a result.
/// </summary>
public bool HasResult => Type > HitResult.None;
/// <summary>
/// Whether a successful hit occurred.
/// </summary>
public bool IsHit => Type > HitResult.Miss;
public JudgementResult(Judgement judgement)
{
Judgement = judgement;
}
}
}

View File

@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>(); private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
public IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty<DrawableHitObject>(); public IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty<DrawableHitObject>();
public event Action<DrawableHitObject, Judgement> OnJudgement; public event Action<DrawableHitObject, JudgementResult> OnJudgement;
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved; public event Action<DrawableHitObject, JudgementResult> OnJudgementRemoved;
/// <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.
@ -46,7 +46,7 @@ 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 => HitObject.Judgements.All(j => j.IsHit) && NestedHitObjects.All(n => n.IsHit); public bool IsHit => Results.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.
@ -57,7 +57,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Whether this <see cref="DrawableHitObject"/> has been judged. /// Whether this <see cref="DrawableHitObject"/> has been judged.
/// Note: This does NOT include nested hitobjects. /// Note: This does NOT include nested hitobjects.
/// </summary> /// </summary>
public bool Judged => HitObject.Judgements.All(h => h.HasResult); public bool Judged => Results.All(h => h.HasResult);
private readonly List<JudgementResult> results = new List<JudgementResult>();
public IReadOnlyList<JudgementResult> Results => results;
private bool judgementOccurred; private bool judgementOccurred;
@ -74,6 +77,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
protected DrawableHitObject(HitObject hitObject) protected DrawableHitObject(HitObject hitObject)
{ {
HitObject = hitObject; HitObject = hitObject;
foreach (var j in hitObject.Judgements)
results.Add(CreateJudgementResult(j));
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -135,17 +141,17 @@ namespace osu.Game.Rulesets.Objects.Drawables
{ {
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
for (int i = HitObject.Judgements.Count - 1; i >= 0; i--) for (int i = Results.Count - 1; i >= 0; i--)
{ {
var judgement = HitObject.Judgements[i]; var judgement = Results[i];
if (judgement.TimeOffset + endTime <= Time.Current) if (judgement.TimeOffset + endTime <= Time.Current)
break; break;
judgement.Result = HitResult.None;
State.Value = ArmedState.Idle;
OnJudgementRemoved?.Invoke(this, judgement); OnJudgementRemoved?.Invoke(this, judgement);
judgement.Type = HitResult.None;
State.Value = ArmedState.Idle;
} }
} }
@ -161,8 +167,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
protected virtual void AddNested(DrawableHitObject h) protected virtual void AddNested(DrawableHitObject h)
{ {
h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j); h.OnJudgement += (d, r) => OnJudgement?.Invoke(d, r);
h.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(d, j); h.OnJudgementRemoved += (d, r) => OnJudgementRemoved?.Invoke(d, r);
h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j); h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
nestedHitObjects.Value.Add(h); nestedHitObjects.Value.Add(h);
@ -172,18 +178,21 @@ 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 ApplyJudgement<T>(T judgement, Action<T> application) protected void ApplyResult(JudgementResult result, Action<JudgementResult> application)
where T : Judgement
{ {
judgementOccurred = true; // Todo: Unsure if we want to keep this
if (!Results.Contains(result))
throw new ArgumentException($"The applied judgement result must be a part of {Results}.");
application?.Invoke(judgement); application?.Invoke(result);
judgementOccurred = true;
// 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; result.TimeOffset = Time.Current - endTime;
switch (judgement.Result) switch (result.Type)
{ {
case HitResult.None: case HitResult.None:
break; break;
@ -195,7 +204,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
break; break;
} }
OnJudgement?.Invoke(this, judgement); OnJudgement?.Invoke(this, result);
} }
/// <summary> /// <summary>
@ -224,7 +233,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="ApplyJudgement"/>. /// all <see cref="Judgement"/>s and notify of them through <see cref="ApplyResult{T}"/>.
/// </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"/> &gt; 0 /// <param name="timeOffset">The offset from the <see cref="HitObject"/> end time at which this check occurred. A <paramref name="timeOffset"/> &gt; 0
@ -232,6 +241,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) protected virtual void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
} }
protected virtual JudgementResult CreateJudgementResult(Judgement judgement) => new JudgementResult(judgement);
} }
public abstract class DrawableHitObject<TObject> : DrawableHitObject public abstract class DrawableHitObject<TObject> : DrawableHitObject

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Scoring
/// <summary> /// <summary>
/// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the <see cref="ScoreProcessor"/>. /// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the <see cref="ScoreProcessor"/>.
/// </summary> /// </summary>
public event Action<Judgement> NewJudgement; public event Action<JudgementResult> NewJudgement;
/// <summary> /// <summary>
/// Additional conditions on top of <see cref="DefaultFailCondition"/> that cause a failing state. /// Additional conditions on top of <see cref="DefaultFailCondition"/> that cause a failing state.
@ -144,9 +144,10 @@ namespace osu.Game.Rulesets.Scoring
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred. /// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
/// </summary> /// </summary>
/// <param name="judgement">The judgement to notify subscribers of.</param> /// <param name="judgement">The judgement to notify subscribers of.</param>
protected void NotifyNewJudgement(Judgement judgement) /// <param name="result">The judgement scoring result to notify subscribers of.</param>
protected void NotifyNewJudgement(JudgementResult result)
{ {
NewJudgement?.Invoke(judgement); NewJudgement?.Invoke(result);
if (HasCompleted) if (HasCompleted)
AllJudged?.Invoke(); AllJudged?.Invoke();
@ -209,32 +210,47 @@ namespace osu.Game.Rulesets.Scoring
Mode.ValueChanged += _ => updateScore(); Mode.ValueChanged += _ => updateScore();
} }
/// <summary> protected virtual void ApplyBeatmap(Beatmap<TObject> beatmap)
/// Simulates an autoplay of <see cref="HitObject"/>s that will be judged by this <see cref="ScoreProcessor{TObject}"/> {
/// by adding <see cref="Judgement"/>s for each <see cref="HitObject"/> in the <see cref="Beatmap{TObject}"/>. }
/// <para>
/// This is required for <see cref="ScoringMode.Standardised"/> to work, otherwise <see cref="ScoringMode.Classic"/> will be used. protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap)
/// </para> {
/// </summary> foreach (var obj in beatmap.HitObjects)
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> containing the <see cref="HitObject"/>s that will be judged by this <see cref="ScoreProcessor{TObject}"/>.</param> simulate(obj);
protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap) { }
void simulate(HitObject obj)
{
foreach (var nested in obj.NestedHitObjects)
simulate(nested);
foreach (var judgement in obj.Judgements)
AddJudgement(new JudgementResult(judgement) { Type = judgement.MaxResult });
}
}
/// <summary> /// <summary>
/// Adds a judgement to this ScoreProcessor. /// Adds a judgement to this ScoreProcessor.
/// </summary> /// </summary>
/// <param name="judgement">The judgement to add.</param> /// <param name="judgement">The judgement to add.</param>
protected void AddJudgement(Judgement judgement) /// <param name="result">The judgement scoring result.</param>
protected void AddJudgement(JudgementResult result)
{ {
OnNewJudgement(judgement); OnNewJudgement(result);
updateScore(); updateScore();
UpdateFailed(); UpdateFailed();
NotifyNewJudgement(judgement); NotifyNewJudgement(result);
} }
protected void RemoveJudgement(Judgement judgement) /// <summary>
/// Removes a judgement from this ScoreProcessor.
/// </summary>
/// <param name="judgement">The judgement to remove.</param>
/// <param name="result">The judgement scoring result.</param>
protected void RemoveJudgement(JudgementResult result)
{ {
OnJudgementRemoved(judgement); OnJudgementRemoved(result);
updateScore(); updateScore();
} }
@ -242,16 +258,17 @@ namespace osu.Game.Rulesets.Scoring
/// Applies a judgement. /// Applies a judgement.
/// </summary> /// </summary>
/// <param name="judgement">The judgement to apply/</param> /// <param name="judgement">The judgement to apply/</param>
protected virtual void OnNewJudgement(Judgement judgement) /// <param name="result">The judgement scoring result.</param>
protected virtual void OnNewJudgement(JudgementResult result)
{ {
judgement.ComboAtJudgement = Combo; result.ComboAtJudgement = Combo;
judgement.HighestComboAtJudgement = HighestCombo; result.HighestComboAtJudgement = HighestCombo;
JudgedHits++; JudgedHits++;
if (judgement.AffectsCombo) if (result.Judgement.AffectsCombo)
{ {
switch (judgement.Result) switch (result.Type)
{ {
case HitResult.None: case HitResult.None:
break; break;
@ -264,15 +281,15 @@ namespace osu.Game.Rulesets.Scoring
} }
} }
if (judgement.IsBonus) if (result.Judgement.IsBonus)
{ {
if (judgement.IsHit) if (result.IsHit)
bonusScore += judgement.NumericResult; bonusScore += result.Judgement.NumericResultFor(result);
} }
else else
{ {
baseScore += judgement.NumericResult; baseScore += result.Judgement.NumericResultFor(result);
rollingMaxBaseScore += judgement.MaxNumericResult; rollingMaxBaseScore += result.Judgement.MaxNumericResult;
} }
} }
@ -280,22 +297,23 @@ namespace osu.Game.Rulesets.Scoring
/// Removes a judgement. This should reverse everything in <see cref="OnNewJudgement(Judgement)"/>. /// Removes a judgement. This should reverse everything in <see cref="OnNewJudgement(Judgement)"/>.
/// </summary> /// </summary>
/// <param name="judgement">The judgement to remove.</param> /// <param name="judgement">The judgement to remove.</param>
protected virtual void OnJudgementRemoved(Judgement judgement) /// <param name="result">The judgement scoring result.</param>
protected virtual void OnJudgementRemoved(JudgementResult result)
{ {
Combo.Value = judgement.ComboAtJudgement; Combo.Value = result.ComboAtJudgement;
HighestCombo.Value = judgement.HighestComboAtJudgement; HighestCombo.Value = result.HighestComboAtJudgement;
JudgedHits--; JudgedHits--;
if (judgement.IsBonus) if (result.Judgement.IsBonus)
{ {
if (judgement.IsHit) if (result.IsHit)
bonusScore -= judgement.NumericResult; bonusScore -= result.Judgement.NumericResultFor(result);
} }
else else
{ {
baseScore -= judgement.NumericResult; baseScore -= result.Judgement.NumericResultFor(result);
rollingMaxBaseScore -= judgement.MaxNumericResult; rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
} }
} }

View File

@ -182,8 +182,8 @@ namespace osu.Game.Rulesets.UI
public abstract class RulesetContainer<TObject> : RulesetContainer public abstract class RulesetContainer<TObject> : RulesetContainer
where TObject : HitObject where TObject : HitObject
{ {
public event Action<Judgement> OnJudgement; public event Action<JudgementResult> OnJudgement;
public event Action<Judgement> OnJudgementRemoved; public event Action<JudgementResult> OnJudgementRemoved;
/// <summary> /// <summary>
/// The Beatmap /// The Beatmap
@ -290,8 +290,8 @@ namespace osu.Game.Rulesets.UI
if (drawableObject == null) if (drawableObject == null)
continue; continue;
drawableObject.OnJudgement += (d, j) => OnJudgement?.Invoke(j); drawableObject.OnJudgement += (_, r) => OnJudgement?.Invoke(r);
drawableObject.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(j); drawableObject.OnJudgementRemoved += (_, r) => OnJudgementRemoved?.Invoke(r);
Playfield.Add(drawableObject); Playfield.Add(drawableObject);
} }

View File

@ -92,9 +92,9 @@ namespace osu.Game.Screens.Play.HUD
}; };
} }
public void Flash(Judgement judgement) public void Flash(JudgementResult result)
{ {
if (judgement.Result == HitResult.Miss) if (result.Type == HitResult.Miss)
return; return;
fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint) fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint)