From f9f72f25a2c22bc73e4985138e9bdc793371a792 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2016 16:26:50 +0900 Subject: [PATCH 1/4] Add basic flow for hitobject judgement. --- .../Tests/TestCaseHitObjects.cs | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 28 +++++++--- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Objects/Drawables/HitExplosion.cs | 6 +- osu.Game.Mode.Osu/OsuHitJudgementResolver.cs | 41 ++++++++++++++ osu.Game.Mode.Osu/OsuRuleset.cs | 2 + osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj | 1 + osu.Game/Modes/HitJudgementResolver.cs | 21 ++++--- .../Objects/Drawables/DrawableHitObject.cs | 55 ++++++++++++------- osu.Game/Screens/Play/Player.cs | 7 ++- 10 files changed, 124 insertions(+), 41 deletions(-) create mode 100644 osu.Game.Mode.Osu/OsuHitJudgementResolver.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs index 31a1bc369e..6da47c5bc4 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs @@ -50,7 +50,7 @@ namespace osu.Desktop.VisualTests.Tests Anchor = Anchor.Centre, Origin = Anchor.Centre, Depth = -i, - State = ArmedState.Armed, + State = ArmedState.Hit, }; approachContainer.Add(d.ApproachCircle.CreateProxy()); diff --git a/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs index 8c73955ca9..6c11b328a9 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -39,7 +39,9 @@ namespace osu.Game.Modes.Osu.Objects.Drawables circle = new CirclePiece { Colour = osuObject.Colour, - Hit = Hit, + Hit = () => Hit(new JudgementInfo { + UserTriggered = true, + }), }, number = new NumberPiece(), ring = new RingPiece(), @@ -73,7 +75,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables Flush(true); //move to DrawableHitObject ApproachCircle.Flush(true); - double t = HitTime ?? osuObject.StartTime; + double t = osuObject.EndTime + (Judgement?.TimeOffset ?? 0); Alpha = 0; @@ -103,14 +105,26 @@ namespace osu.Game.Modes.Osu.Objects.Drawables switch (state) { - case ArmedState.Disarmed: - Delay(osuObject.Duration + 200); - FadeOut(200); + case ArmedState.Idle: + Delay(osuObject.Duration + 500); + FadeOut(500); explosion?.Expire(); explosion = null; break; - case ArmedState.Armed: + case ArmedState.Miss: + ring.FadeOut(); + circle.FadeOut(); + number.FadeOut(); + + explosion?.Expire(); + explosion = null; + + Schedule(() => Add(explosion = new HitExplosion(HitResult.Miss))); + + FadeOut(800); + break; + case ArmedState.Hit: const double flash_in = 30; flash.FadeTo(0.8f, flash_in); @@ -119,7 +133,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables explode.FadeIn(flash_in); - Schedule(() => Add(explosion = new HitExplosion(Judgement.Hit300))); + Schedule(() => Add(explosion = new HitExplosion(Judgement.Result))); Delay(flash_in, true); diff --git a/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs index 693f05cd1f..50203d48ae 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs @@ -18,7 +18,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables Add(new CirclePiece { Colour = h.Colour, - Hit = Hit, + Hit = () => Hit(new JudgementInfo()), Position = h.Curve.PositionAt(i) - h.Position //non-relative? }); } diff --git a/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs b/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs index a3067a1eab..fac9ab636b 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs @@ -12,7 +12,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables private SpriteText line1; private SpriteText line2; - public HitExplosion(Judgement judgement, ComboJudgement comboJudgement = ComboJudgement.None) + public HitExplosion(HitResult hitResult, ComboResult comboResult = ComboResult.None) { AutoSizeAxes = Axes.Both; Anchor = Anchor.Centre; @@ -27,13 +27,13 @@ namespace osu.Game.Modes.Osu.Objects.Drawables { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = judgement.GetDescription(), + Text = hitResult.GetDescription(), Font = @"Venera", TextSize = 20, }, line2 = new SpriteText { - Text = comboJudgement.GetDescription(), + Text = comboResult.GetDescription(), Font = @"Venera", TextSize = 14, } diff --git a/osu.Game.Mode.Osu/OsuHitJudgementResolver.cs b/osu.Game.Mode.Osu/OsuHitJudgementResolver.cs new file mode 100644 index 0000000000..6dc240c7af --- /dev/null +++ b/osu.Game.Mode.Osu/OsuHitJudgementResolver.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Game.Modes.Objects.Drawables; +using osu.Game.Modes.Osu.Objects.Drawables; + +namespace osu.Game.Modes.Osu +{ + class OsuHitJudgementResolver : HitJudgementResolver + { + double hit50 = 150; + double hit100 = 80; + double hit300 = 30; + public override void CheckJudgement(DrawableHitObject h, JudgementInfo info) + { + DrawableHitCircle circle = h as DrawableHitCircle; + if (circle != null) + { + if (!info.UserTriggered) + { + if (info.TimeOffset > hit50) + info.Result = HitResult.Miss; + return; + } + + double hitOffset = Math.Abs(info.TimeOffset); + + if (hitOffset < hit300) + info.Result = HitResult.Hit300; + else if (hitOffset < hit100) + info.Result = HitResult.Hit100; + else if (hitOffset < hit50) + info.Result = HitResult.Hit50; + else + info.Result = HitResult.Miss; + } + } + } +} diff --git a/osu.Game.Mode.Osu/OsuRuleset.cs b/osu.Game.Mode.Osu/OsuRuleset.cs index ac43e5501c..e79cbef748 100644 --- a/osu.Game.Mode.Osu/OsuRuleset.cs +++ b/osu.Game.Mode.Osu/OsuRuleset.cs @@ -13,6 +13,8 @@ namespace osu.Game.Modes.Osu { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); + public override HitJudgementResolver CreateHitJudgement() => new OsuHitJudgementResolver(); + public override HitRenderer CreateHitRendererWith(List objects) => new OsuHitRenderer { Objects = objects }; public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); diff --git a/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj index e7efa413c4..d63cc2354a 100644 --- a/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj +++ b/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj @@ -52,6 +52,7 @@ + diff --git a/osu.Game/Modes/HitJudgementResolver.cs b/osu.Game/Modes/HitJudgementResolver.cs index 5f2afec369..d9f3cc96c1 100644 --- a/osu.Game/Modes/HitJudgementResolver.cs +++ b/osu.Game/Modes/HitJudgementResolver.cs @@ -4,28 +4,34 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using osu.Game.Modes.Objects; +using osu.Game.Modes.Objects.Drawables; using OpenTK; namespace osu.Game.Modes { public class HitJudgementResolver { - public JudgementResult CheckJudgement(HitObject h) => new JudgementResult { Combo = ComboJudgement.None, Judgement = Judgement.Hit300 }; + public virtual void CheckJudgement(DrawableHitObject h, JudgementInfo info) + { + info.Result = HitResult.Hit300; + } } - public struct JudgementResult + public class JudgementInfo { - public ComboJudgement Combo; - public Judgement Judgement; - public float TimeOffset; + public bool UserTriggered; + public ComboResult Combo; + public HitResult Result; + public double TimeOffset; public Vector2 PositionOffset; } - public enum ComboJudgement + public enum ComboResult { [Description(@"")] None, @@ -35,8 +41,9 @@ namespace osu.Game.Modes Perfect } - public enum Judgement + public enum HitResult { + Ignore, [Description(@"Miss")] Miss, [Description(@"50")] diff --git a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs index 387d5d061a..0d8b124be2 100644 --- a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs @@ -2,6 +2,7 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Diagnostics; using osu.Framework; using osu.Framework.Graphics.Containers; @@ -13,11 +14,11 @@ namespace osu.Game.Modes.Objects.Drawables public Action OnHit; public Action OnMiss; - public Func AllowHit; + public Action CheckJudgement; public Container ChildObjects; - public JudgementResult Result; + public JudgementInfo Judgement; public HitObject HitObject; @@ -41,36 +42,47 @@ namespace osu.Game.Modes.Objects.Drawables } } - protected double? HitTime; - - protected virtual bool Hit() + /// + /// Process a hit of this hitobject. Carries out judgement. + /// + /// Preliminary judgement information provided by the hit source. + /// Whether a hit was processed. + protected bool Hit(JudgementInfo judgement) { - if (State != ArmedState.Disarmed) + if (State != ArmedState.Idle) return false; - if (AllowHit?.Invoke(this) == false) + judgement.TimeOffset = Time.Current - HitObject.EndTime; + + CheckJudgement?.Invoke(this, judgement); + + if (judgement.Result == HitResult.Ignore) return false; - HitTime = Time.Current; + Judgement = judgement; - State = ArmedState.Armed; + switch (judgement.Result) + { + default: + State = ArmedState.Hit; + OnHit?.Invoke(this); + break; + case HitResult.Miss: + State = ArmedState.Miss; + OnMiss?.Invoke(this); + break; + } + + return true; } - private bool counted; - protected override void Update() { base.Update(); - if (Time.Current >= HitObject.EndTime && !counted) - { - counted = true; - if (state == ArmedState.Armed) - OnHit?.Invoke(this); - else - OnMiss?.Invoke(this); - } + if (Time.Current >= HitObject.EndTime && Judgement == null) + Hit(new JudgementInfo()); } protected abstract void UpdateState(ArmedState state); @@ -78,7 +90,8 @@ namespace osu.Game.Modes.Objects.Drawables public enum ArmedState { - Disarmed, - Armed + Idle, + Hit, + Miss } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 8691097ebf..a5bbf8c453 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -86,11 +86,16 @@ namespace osu.Game.Screens.Play var scoreOverlay = ruleset.CreateScoreOverlay(); var hitRenderer = ruleset.CreateHitRendererWith(beatmap.HitObjects); + var hitJudgement = ruleset.CreateHitJudgement(); + hitRenderer.OnHit += delegate (HitObject h) { scoreOverlay.OnHit(h); }; hitRenderer.OnMiss += delegate (HitObject h) { scoreOverlay.OnMiss(h); }; if (Autoplay) - hitRenderer.Schedule(() => hitRenderer.DrawableObjects.ForEach(h => h.State = ArmedState.Armed)); + hitRenderer.Schedule(() => hitRenderer.DrawableObjects.ForEach(h => h.State = ArmedState.Hit)); + + //bind DrawableHitObjects to HitJudgement + hitRenderer.Schedule(() => hitRenderer.DrawableObjects.ForEach(h => h.CheckJudgement = hitJudgement.CheckJudgement)); Children = new Drawable[] { From 202028f2c9a1bda1e254de3f3829f0929f4a9cd6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2016 16:37:14 +0900 Subject: [PATCH 2/4] Remove glow on miss. --- osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs index 6c11b328a9..a0add258f7 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -116,6 +116,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables ring.FadeOut(); circle.FadeOut(); number.FadeOut(); + glow.FadeOut(); explosion?.Expire(); explosion = null; From ef0f975960ea2c1314ff0370a273dc0c9e8bef82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2016 16:41:00 +0900 Subject: [PATCH 3/4] Fix TestCaseHitObjects. --- osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs index 6da47c5bc4..11365adafe 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs @@ -12,6 +12,7 @@ using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects.Drawables; using osu.Framework.Graphics.Containers; +using osu.Game.Modes; namespace osu.Desktop.VisualTests.Tests { @@ -51,6 +52,7 @@ namespace osu.Desktop.VisualTests.Tests Origin = Anchor.Centre, Depth = -i, State = ArmedState.Hit, + Judgement = new JudgementInfo { Result = HitResult.Hit300 } }; approachContainer.Add(d.ApproachCircle.CreateProxy()); From 396ca9fe9163263ddd60936cc07cef59cdab15f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 26 Nov 2016 16:51:51 +0900 Subject: [PATCH 4/4] Remove HitJudgementResolver; reimplement in DrawableHitObject. --- .../Tests/TestCaseHitObjects.cs | 1 - .../Objects/Drawables/DrawableHitCircle.cs | 50 ++++++++++++-- .../Objects/Drawables/DrawableOsuHitObject.cs | 32 +++++---- .../Objects/Drawables/DrawableSlider.cs | 3 +- .../Objects/Drawables/HitExplosion.cs | 7 +- .../Objects/Drawables/Pieces/CirclePiece.cs | 3 +- osu.Game.Mode.Osu/OsuHitJudgementResolver.cs | 41 ------------ osu.Game.Mode.Osu/OsuRuleset.cs | 2 - osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj | 2 +- .../Objects/Drawables/DrawableHitObject.cs | 66 ++++++++++++++----- osu.Game/Modes/Ruleset.cs | 2 - osu.Game/Modes/UI/HitRenderer.cs | 4 +- osu.Game/Screens/Play/Player.cs | 5 -- osu.Game/osu.Game.csproj | 1 - 14 files changed, 115 insertions(+), 104 deletions(-) rename osu.Game/Modes/HitJudgementResolver.cs => osu.Game.Mode.Osu/Objects/Drawables/DrawableOsuHitObject.cs (51%) delete mode 100644 osu.Game.Mode.Osu/OsuHitJudgementResolver.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs index 11365adafe..0569fcf3c3 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs @@ -52,7 +52,6 @@ namespace osu.Desktop.VisualTests.Tests Origin = Anchor.Centre, Depth = -i, State = ArmedState.Hit, - Judgement = new JudgementInfo { Result = HitResult.Hit300 } }; approachContainer.Add(d.ApproachCircle.CreateProxy()); diff --git a/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs index a0add258f7..dc5d5bf2a6 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -2,6 +2,7 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.ComponentModel; using osu.Framework.Graphics; using osu.Framework.Graphics.Transformations; using osu.Game.Modes.Objects.Drawables; @@ -10,7 +11,7 @@ using OpenTK; namespace osu.Game.Modes.Osu.Objects.Drawables { - public class DrawableHitCircle : DrawableHitObject + public class DrawableHitCircle : DrawableOsuHitObject { private OsuHitObject osuObject; @@ -39,9 +40,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables circle = new CirclePiece { Colour = osuObject.Colour, - Hit = () => Hit(new JudgementInfo { - UserTriggered = true, - }), + Hit = () => + { + ((PositionalJudgementInfo)Judgement).PositionOffset = Vector2.Zero; //todo: set to correct value + UpdateJudgement(true); + return true; + }, }, number = new NumberPiece(), ring = new RingPiece(), @@ -68,6 +72,38 @@ namespace osu.Game.Modes.Osu.Objects.Drawables UpdateState(State); } + double hit50 = 150; + double hit100 = 80; + double hit300 = 30; + + protected override void CheckJudgement(bool userTriggered) + { + if (!userTriggered) + { + if (Judgement.TimeOffset > hit50) + Judgement.Result = HitResult.Miss; + return; + } + + double hitOffset = Math.Abs(Judgement.TimeOffset); + + if (hitOffset < hit50) + { + Judgement.Result = HitResult.Hit; + + OsuJudgementInfo osuInfo = Judgement as OsuJudgementInfo; + + if (hitOffset < hit300) + osuInfo.Score = OsuScoreResult.Hit300; + else if (hitOffset < hit100) + osuInfo.Score = OsuScoreResult.Hit100; + else if (hitOffset < hit50) + osuInfo.Score = OsuScoreResult.Hit50; + } + else + Judgement.Result = HitResult.Miss; + } + protected override void UpdateState(ArmedState state) { if (!IsLoaded) return; @@ -75,7 +111,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables Flush(true); //move to DrawableHitObject ApproachCircle.Flush(true); - double t = osuObject.EndTime + (Judgement?.TimeOffset ?? 0); + double t = osuObject.EndTime + Judgement.TimeOffset; Alpha = 0; @@ -121,7 +157,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables explosion?.Expire(); explosion = null; - Schedule(() => Add(explosion = new HitExplosion(HitResult.Miss))); + Schedule(() => Add(explosion = new HitExplosion((OsuJudgementInfo)Judgement))); FadeOut(800); break; @@ -134,7 +170,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables explode.FadeIn(flash_in); - Schedule(() => Add(explosion = new HitExplosion(Judgement.Result))); + Schedule(() => Add(explosion = new HitExplosion((OsuJudgementInfo)Judgement))); Delay(flash_in, true); diff --git a/osu.Game/Modes/HitJudgementResolver.cs b/osu.Game.Mode.Osu/Objects/Drawables/DrawableOsuHitObject.cs similarity index 51% rename from osu.Game/Modes/HitJudgementResolver.cs rename to osu.Game.Mode.Osu/Objects/Drawables/DrawableOsuHitObject.cs index d9f3cc96c1..d416732327 100644 --- a/osu.Game/Modes/HitJudgementResolver.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -1,34 +1,33 @@ -//Copyright (c) 2007-2016 ppy Pty Ltd . -//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; +using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using osu.Game.Modes.Objects; using osu.Game.Modes.Objects.Drawables; -using OpenTK; -namespace osu.Game.Modes +namespace osu.Game.Modes.Osu.Objects.Drawables { - public class HitJudgementResolver + public class DrawableOsuHitObject : DrawableHitObject { - public virtual void CheckJudgement(DrawableHitObject h, JudgementInfo info) + public DrawableOsuHitObject(OsuHitObject hitObject) + : base(hitObject) { - info.Result = HitResult.Hit300; + } + + public override JudgementInfo CreateJudgementInfo() => new OsuJudgementInfo(); + + protected override void UpdateState(ArmedState state) + { + throw new NotImplementedException(); } } - public class JudgementInfo + public class OsuJudgementInfo : PositionalJudgementInfo { - public bool UserTriggered; + public OsuScoreResult Score; public ComboResult Combo; - public HitResult Result; - public double TimeOffset; - public Vector2 PositionOffset; } public enum ComboResult @@ -41,9 +40,8 @@ namespace osu.Game.Modes Perfect } - public enum HitResult + public enum OsuScoreResult { - Ignore, [Description(@"Miss")] Miss, [Description(@"50")] diff --git a/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs index 50203d48ae..55e4781cd3 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/DrawableSlider.cs @@ -5,7 +5,7 @@ using OpenTK; namespace osu.Game.Modes.Osu.Objects.Drawables { - class DrawableSlider : DrawableHitObject + class DrawableSlider : DrawableOsuHitObject { public DrawableSlider(Slider h) : base(h) { @@ -18,7 +18,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables Add(new CirclePiece { Colour = h.Colour, - Hit = () => Hit(new JudgementInfo()), Position = h.Curve.PositionAt(i) - h.Position //non-relative? }); } diff --git a/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs b/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs index fac9ab636b..a0ab68fa99 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/HitExplosion.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Transformations; +using osu.Game.Modes.Objects.Drawables; using OpenTK; namespace osu.Game.Modes.Osu.Objects.Drawables @@ -12,7 +13,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables private SpriteText line1; private SpriteText line2; - public HitExplosion(HitResult hitResult, ComboResult comboResult = ComboResult.None) + public HitExplosion(OsuJudgementInfo judgement) { AutoSizeAxes = Axes.Both; Anchor = Anchor.Centre; @@ -27,13 +28,13 @@ namespace osu.Game.Modes.Osu.Objects.Drawables { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = hitResult.GetDescription(), + Text = judgement.Score.GetDescription(), Font = @"Venera", TextSize = 20, }, line2 = new SpriteText { - Text = comboResult.GetDescription(), + Text = judgement.Combo.GetDescription(), Font = @"Venera", TextSize = 14, } diff --git a/osu.Game.Mode.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Mode.Osu/Objects/Drawables/Pieces/CirclePiece.cs index c326c46553..fd55a8315a 100644 --- a/osu.Game.Mode.Osu/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Mode.Osu/Objects/Drawables/Pieces/CirclePiece.cs @@ -49,8 +49,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - Hit?.Invoke(); - return true; + return Hit?.Invoke() ?? false; } } } \ No newline at end of file diff --git a/osu.Game.Mode.Osu/OsuHitJudgementResolver.cs b/osu.Game.Mode.Osu/OsuHitJudgementResolver.cs deleted file mode 100644 index 6dc240c7af..0000000000 --- a/osu.Game.Mode.Osu/OsuHitJudgementResolver.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using osu.Game.Modes.Objects.Drawables; -using osu.Game.Modes.Osu.Objects.Drawables; - -namespace osu.Game.Modes.Osu -{ - class OsuHitJudgementResolver : HitJudgementResolver - { - double hit50 = 150; - double hit100 = 80; - double hit300 = 30; - public override void CheckJudgement(DrawableHitObject h, JudgementInfo info) - { - DrawableHitCircle circle = h as DrawableHitCircle; - if (circle != null) - { - if (!info.UserTriggered) - { - if (info.TimeOffset > hit50) - info.Result = HitResult.Miss; - return; - } - - double hitOffset = Math.Abs(info.TimeOffset); - - if (hitOffset < hit300) - info.Result = HitResult.Hit300; - else if (hitOffset < hit100) - info.Result = HitResult.Hit100; - else if (hitOffset < hit50) - info.Result = HitResult.Hit50; - else - info.Result = HitResult.Miss; - } - } - } -} diff --git a/osu.Game.Mode.Osu/OsuRuleset.cs b/osu.Game.Mode.Osu/OsuRuleset.cs index e79cbef748..ac43e5501c 100644 --- a/osu.Game.Mode.Osu/OsuRuleset.cs +++ b/osu.Game.Mode.Osu/OsuRuleset.cs @@ -13,8 +13,6 @@ namespace osu.Game.Modes.Osu { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitJudgementResolver CreateHitJudgement() => new OsuHitJudgementResolver(); - public override HitRenderer CreateHitRendererWith(List objects) => new OsuHitRenderer { Objects = objects }; public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); diff --git a/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj index d63cc2354a..97b4ebcb99 100644 --- a/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj +++ b/osu.Game.Mode.Osu/osu.Game.Modes.Osu.csproj @@ -41,6 +41,7 @@ + @@ -52,7 +53,6 @@ - diff --git a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs index 0d8b124be2..3508d6c3a6 100644 --- a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs @@ -2,23 +2,26 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.ComponentModel; using System.Diagnostics; using osu.Framework; using osu.Framework.Graphics.Containers; +using OpenTK; +using Container = osu.Framework.Graphics.Containers.Container; namespace osu.Game.Modes.Objects.Drawables { public abstract class DrawableHitObject : Container, IStateful { //todo: move to a more central implementation. this logic should not be at a drawable level. - public Action OnHit; - public Action OnMiss; - - public Action CheckJudgement; + public Action OnHit; + public Action OnMiss; public Container ChildObjects; - public JudgementInfo Judgement; + protected JudgementInfo Judgement; + + public abstract JudgementInfo CreateJudgementInfo(); public HitObject HitObject; @@ -42,47 +45,55 @@ namespace osu.Game.Modes.Objects.Drawables } } + protected override void LoadComplete() + { + base.LoadComplete(); + + Judgement = CreateJudgementInfo(); + } + /// /// Process a hit of this hitobject. Carries out judgement. /// /// Preliminary judgement information provided by the hit source. /// Whether a hit was processed. - protected bool Hit(JudgementInfo judgement) + protected bool UpdateJudgement(bool userTriggered) { - if (State != ArmedState.Idle) + if (Judgement.Result != null) return false; - judgement.TimeOffset = Time.Current - HitObject.EndTime; + Judgement.TimeOffset = Time.Current - HitObject.EndTime; - CheckJudgement?.Invoke(this, judgement); + CheckJudgement(userTriggered); - if (judgement.Result == HitResult.Ignore) + if (Judgement.Result == null) return false; - Judgement = judgement; - - switch (judgement.Result) + switch (Judgement.Result) { default: State = ArmedState.Hit; - OnHit?.Invoke(this); + OnHit?.Invoke(this, Judgement); break; case HitResult.Miss: State = ArmedState.Miss; - OnMiss?.Invoke(this); + OnMiss?.Invoke(this, Judgement); break; } - return true; } + protected virtual void CheckJudgement(bool userTriggered) + { + + } + protected override void Update() { base.Update(); - if (Time.Current >= HitObject.EndTime && Judgement == null) - Hit(new JudgementInfo()); + UpdateJudgement(false); } protected abstract void UpdateState(ArmedState state); @@ -94,4 +105,23 @@ namespace osu.Game.Modes.Objects.Drawables Hit, Miss } + + public class PositionalJudgementInfo : JudgementInfo + { + public Vector2 PositionOffset; + } + + public class JudgementInfo + { + public HitResult? Result; + public double TimeOffset; + } + + public enum HitResult + { + [Description(@"Miss")] + Miss, + [Description(@"Hit")] + Hit, + } } diff --git a/osu.Game/Modes/Ruleset.cs b/osu.Game/Modes/Ruleset.cs index 6576159f62..d35aab6568 100644 --- a/osu.Game/Modes/Ruleset.cs +++ b/osu.Game/Modes/Ruleset.cs @@ -22,8 +22,6 @@ namespace osu.Game.Modes public abstract HitObjectParser CreateHitObjectParser(); - public virtual HitJudgementResolver CreateHitJudgement() => new HitJudgementResolver(); - public static void Register(Ruleset ruleset) => availableRulesets.TryAdd(ruleset.PlayMode, ruleset.GetType()); protected abstract PlayMode PlayMode { get; } diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs index f160356cb4..d37cf545a8 100644 --- a/osu.Game/Modes/UI/HitRenderer.cs +++ b/osu.Game/Modes/UI/HitRenderer.cs @@ -75,12 +75,12 @@ namespace osu.Game.Modes.UI } } - private void onMiss(DrawableHitObject obj) + private void onMiss(DrawableHitObject obj, JudgementInfo judgement) { OnMiss?.Invoke(obj.HitObject); } - private void onHit(DrawableHitObject obj) + private void onHit(DrawableHitObject obj, JudgementInfo judgement) { OnHit?.Invoke(obj.HitObject); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a5bbf8c453..66cec7405e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -86,17 +86,12 @@ namespace osu.Game.Screens.Play var scoreOverlay = ruleset.CreateScoreOverlay(); var hitRenderer = ruleset.CreateHitRendererWith(beatmap.HitObjects); - var hitJudgement = ruleset.CreateHitJudgement(); - hitRenderer.OnHit += delegate (HitObject h) { scoreOverlay.OnHit(h); }; hitRenderer.OnMiss += delegate (HitObject h) { scoreOverlay.OnMiss(h); }; if (Autoplay) hitRenderer.Schedule(() => hitRenderer.DrawableObjects.ForEach(h => h.State = ArmedState.Hit)); - //bind DrawableHitObjects to HitJudgement - hitRenderer.Schedule(() => hitRenderer.DrawableObjects.ForEach(h => h.CheckJudgement = hitJudgement.CheckJudgement)); - Children = new Drawable[] { new PlayerInputManager(game.Host) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9c2bbf086a..00c46a7ce3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -64,7 +64,6 @@ -