From 70fc09f81e697925955da38755691e4d6f1686f5 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 13 Jan 2018 12:42:42 +0100 Subject: [PATCH] move judgement + state logic up to DrawableHitObject --- .../Objects/Drawables/DrawableHitObject.cs | 298 +++++++++--------- 1 file changed, 142 insertions(+), 156 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 13329a1470..a29ea4cbbb 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -29,37 +29,167 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public virtual Color4 AccentColour { get; set; } = Color4.Gray; + private List nestedHitObjects; + public IReadOnlyList NestedHitObjects => nestedHitObjects; + + 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. /// public virtual bool DisplayJudgement => true; - public override bool RemoveCompletedTransforms => false; + /// + /// Whether this and all of its nested s have been judged. + /// + public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true); + + /// + /// Whether this can be judged. + /// + protected virtual bool ProvidesJudgement => true; + + private bool judgementOccurred; + private bool judgementFinalized => judgements.LastOrDefault()?.Final == true; + + public bool Interactive = true; + public override bool HandleInput => Interactive; + public override bool RemoveWhenNotAlive => false; + public override bool RemoveCompletedTransforms => false; protected override bool RequiresChildrenUpdate => true; - public virtual bool AllJudged => false; + public readonly Bindable State = new Bindable(); protected DrawableHitObject(HitObject hitObject) { HitObject = hitObject; } + protected override void LoadComplete() + { + base.LoadComplete(); + + State.ValueChanged += state => + { + UpdateState(state); + + // apply any custom state overrides + ApplyCustomUpdateState?.Invoke(this, state); + }; + + State.TriggerChange(); + } + + protected abstract void UpdateState(ArmedState state); + + /// + /// Bind to apply a custom state which can override the default implementation. + /// + public event Action ApplyCustomUpdateState; + + protected override void Update() + { + base.Update(); + + var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; + + while (judgements.Count > 0) + { + var lastJudgement = judgements[judgements.Count - 1]; + if (lastJudgement.TimeOffset + endTime <= Time.Current) + break; + + judgements.RemoveAt(judgements.Count - 1); + State.Value = ArmedState.Idle; + + OnJudgementRemoved?.Invoke(this, lastJudgement); + } + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + UpdateJudgement(false); + } + + protected virtual void AddNested(DrawableHitObject h) + { + if (nestedHitObjects == null) + nestedHitObjects = new List(); + nestedHitObjects.Add(h); + } + + /// + /// Notifies that a new judgement has occurred for this . + /// + /// The . + protected void AddJudgement(Judgement judgement) + { + judgementOccurred = true; + + // 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: + break; + case HitResult.Miss: + State.Value = ArmedState.Miss; + break; + default: + State.Value = ArmedState.Hit; + break; + } + + OnJudgement?.Invoke(this, judgement); + } + /// /// Processes this , checking if any judgements have occurred. /// /// Whether the user triggered this process. /// Whether a judgement has occurred from this or any nested s. - protected internal virtual bool UpdateJudgement(bool userTriggered) => false; - - private List nestedHitObjects; - public IReadOnlyList NestedHitObjects => nestedHitObjects; - - protected virtual void AddNested(DrawableHitObject h) + protected internal bool UpdateJudgement(bool userTriggered) + { + judgementOccurred = false; + + if (AllJudged) + return false; + + if (NestedHitObjects != null) + { + foreach (var d in NestedHitObjects) + judgementOccurred |= d.UpdateJudgement(userTriggered); + } + + if (!ProvidesJudgement || judgementFinalized || judgementOccurred) + return judgementOccurred; + + var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; + CheckForJudgements(userTriggered, Time.Current - endTime); + + return judgementOccurred; + } + + /// + /// Checks if any judgements have occurred for this . This method must construct + /// 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 + /// implies that this check occurred after the end time of . + protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { - if (nestedHitObjects == null) - nestedHitObjects = new List(); - nestedHitObjects.Add(h); } /// @@ -76,30 +206,14 @@ namespace osu.Game.Rulesets.Objects.Drawables public abstract class DrawableHitObject : DrawableHitObject where TObject : HitObject { - public event Action OnJudgement; - public event Action OnJudgementRemoved; - public new readonly TObject HitObject; - public override bool HandleInput => Interactive; - public bool Interactive = true; - - /// - /// Whether this can be judged. - /// - protected virtual bool ProvidesJudgement => true; - - private readonly List judgements = new List(); - public IReadOnlyList Judgements => judgements; - protected List Samples = new List(); protected virtual IEnumerable GetSamples() => HitObject.Samples; // Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first protected virtual string SampleNamespace => null; - public readonly Bindable State = new Bindable(); - protected DrawableHitObject(TObject hitObject) : base(hitObject) { @@ -141,139 +255,11 @@ namespace osu.Game.Rulesets.Objects.Drawables State.ValueChanged += state => { - UpdateState(state); - - // apply any custom state overrides - ApplyCustomUpdateState?.Invoke(this, state); - if (State == ArmedState.Hit) PlaySamples(); }; - - State.TriggerChange(); } - protected void PlaySamples() - { - Samples.ForEach(s => s?.Play()); - } - - private bool judgementOccurred; - private bool judgementFinalized => judgements.LastOrDefault()?.Final == true; - - /// - /// Whether this and all of its nested s have been judged. - /// - public sealed override bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true); - - /// - /// Notifies that a new judgement has occurred for this . - /// - /// The . - protected void AddJudgement(Judgement judgement) - { - judgementOccurred = true; - - // 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: - break; - case HitResult.Miss: - State.Value = ArmedState.Miss; - break; - default: - State.Value = ArmedState.Hit; - break; - } - - OnJudgement?.Invoke(this, judgement); - } - - /// - /// Processes this , checking if any judgements have occurred. - /// - /// Whether the user triggered this process. - /// Whether a judgement has occurred from this or any nested s. - protected internal sealed override bool UpdateJudgement(bool userTriggered) - { - judgementOccurred = false; - - if (AllJudged) - return false; - - if (NestedHitObjects != null) - { - foreach (var d in NestedHitObjects) - judgementOccurred |= d.UpdateJudgement(userTriggered); - } - - if (!ProvidesJudgement || judgementFinalized || judgementOccurred) - return judgementOccurred; - - var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - CheckForJudgements(userTriggered, Time.Current - endTime); - - return judgementOccurred; - } - - /// - /// Checks if any judgements have occurred for this . This method must construct - /// 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 - /// implies that this check occurred after the end time of . - protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { } - - protected override void Update() - { - base.Update(); - - var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - - while (judgements.Count > 0) - { - var lastJudgement = judgements[judgements.Count - 1]; - if (lastJudgement.TimeOffset + endTime <= Time.Current) - break; - - judgements.RemoveAt(judgements.Count - 1); - State.Value = ArmedState.Idle; - - OnJudgementRemoved?.Invoke(this, lastJudgement); - } - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - UpdateJudgement(false); - } - - protected override void AddNested(DrawableHitObject h) - { - base.AddNested(h); - - if (!(h is DrawableHitObject hWithJudgement)) - return; - - hWithJudgement.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j); - hWithJudgement.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(d, j); - hWithJudgement.ApplyCustomUpdateState += (d, s) => ApplyCustomUpdateState?.Invoke(d, s); - } - - /// - /// Bind to apply a custom state which can override the default implementation. - /// - public event Action ApplyCustomUpdateState; - - protected abstract void UpdateState(ArmedState state); + protected void PlaySamples() => Samples.ForEach(s => s?.Play()); } }