diff --git a/osu.Game.Modes.Catch/CatchRuleset.cs b/osu.Game.Modes.Catch/CatchRuleset.cs index 16c9114c66..43f9b97112 100644 --- a/osu.Game.Modes.Catch/CatchRuleset.cs +++ b/osu.Game.Modes.Catch/CatchRuleset.cs @@ -8,7 +8,6 @@ using osu.Game.Modes.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; using osu.Game.Beatmaps; -using osu.Game.Screens.Play; namespace osu.Game.Modes.Catch { @@ -16,10 +15,9 @@ namespace osu.Game.Modes.Catch { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap, PlayerInputManager input = null) => new CatchHitRenderer + public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new CatchHitRenderer { Beatmap = beatmap, - InputManager = input, }; public override IEnumerable GetModsFor(ModType type) diff --git a/osu.Game.Modes.Mania/ManiaRuleset.cs b/osu.Game.Modes.Mania/ManiaRuleset.cs index d4b5ecad22..eb900aafc7 100644 --- a/osu.Game.Modes.Mania/ManiaRuleset.cs +++ b/osu.Game.Modes.Mania/ManiaRuleset.cs @@ -8,7 +8,6 @@ using osu.Game.Modes.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; using osu.Game.Beatmaps; -using osu.Game.Screens.Play; namespace osu.Game.Modes.Mania { @@ -16,10 +15,9 @@ namespace osu.Game.Modes.Mania { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap, PlayerInputManager input = null) => new ManiaHitRenderer + public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new ManiaHitRenderer { Beatmap = beatmap, - InputManager = input, }; public override IEnumerable GetModsFor(ModType type) diff --git a/osu.Game.Modes.Osu/OsuRuleset.cs b/osu.Game.Modes.Osu/OsuRuleset.cs index b58dc70b16..9de4f1ea97 100644 --- a/osu.Game.Modes.Osu/OsuRuleset.cs +++ b/osu.Game.Modes.Osu/OsuRuleset.cs @@ -9,7 +9,6 @@ using osu.Game.Modes.Objects; using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.UI; using osu.Game.Modes.UI; -using osu.Game.Screens.Play; namespace osu.Game.Modes.Osu { @@ -17,10 +16,9 @@ namespace osu.Game.Modes.Osu { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap, PlayerInputManager input = null) => new OsuHitRenderer + public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new OsuHitRenderer { Beatmap = beatmap, - InputManager = input }; public override IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] diff --git a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs index 41abb4736f..849d7e74d6 100644 --- a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs @@ -32,7 +32,7 @@ namespace osu.Game.Modes.Osu.UI } } - public OsuPlayfield() + public OsuPlayfield() : base(512) { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -62,8 +62,7 @@ namespace osu.Game.Modes.Osu.UI protected override void LoadComplete() { base.LoadComplete(); - if (InputManager?.ReplayInputHandler != null) - Add(new OsuCursorContainer { Colour = Color4.LightYellow }); + AddInternal(new OsuCursorContainer { Colour = Color4.LightYellow }); } public override void Add(DrawableHitObject h) @@ -83,7 +82,7 @@ namespace osu.Game.Modes.Osu.UI public override void PostProcess() { connectionLayer.HitObjects = HitObjects.Children - .Select(d => (OsuHitObject)d.HitObject) + .Select(d => d.HitObject) .OrderBy(h => h.StartTime); } diff --git a/osu.Game.Modes.Taiko/TaikoRuleset.cs b/osu.Game.Modes.Taiko/TaikoRuleset.cs index 73e65a2734..f023f25a87 100644 --- a/osu.Game.Modes.Taiko/TaikoRuleset.cs +++ b/osu.Game.Modes.Taiko/TaikoRuleset.cs @@ -8,7 +8,6 @@ using osu.Game.Modes.Osu.UI; using osu.Game.Modes.Taiko.UI; using osu.Game.Modes.UI; using osu.Game.Beatmaps; -using osu.Game.Screens.Play; namespace osu.Game.Modes.Taiko { @@ -16,10 +15,9 @@ namespace osu.Game.Modes.Taiko { public override ScoreOverlay CreateScoreOverlay() => new OsuScoreOverlay(); - public override HitRenderer CreateHitRendererWith(Beatmap beatmap, PlayerInputManager input = null) => new TaikoHitRenderer + public override HitRenderer CreateHitRendererWith(Beatmap beatmap) => new TaikoHitRenderer { Beatmap = beatmap, - InputManager = input, }; public override IEnumerable GetModsFor(ModType type) diff --git a/osu.Game/Modes/Ruleset.cs b/osu.Game/Modes/Ruleset.cs index e145e60b97..fefba6caf8 100644 --- a/osu.Game/Modes/Ruleset.cs +++ b/osu.Game/Modes/Ruleset.cs @@ -8,7 +8,6 @@ using System; using System.Collections.Concurrent; using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Screens.Play; namespace osu.Game.Modes { @@ -31,7 +30,7 @@ namespace osu.Game.Modes public abstract ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0); - public abstract HitRenderer CreateHitRendererWith(Beatmap beatmap, PlayerInputManager input = null); + public abstract HitRenderer CreateHitRendererWith(Beatmap beatmap); public abstract HitObjectParser CreateHitObjectParser(); diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs index cf5c2460d2..fb28dd6c47 100644 --- a/osu.Game/Modes/UI/HitRenderer.cs +++ b/osu.Game/Modes/UI/HitRenderer.cs @@ -11,6 +11,7 @@ using osu.Game.Modes.Objects; using osu.Game.Modes.Objects.Drawables; using osu.Game.Beatmaps; using osu.Game.Screens.Play; +using OpenTK; namespace osu.Game.Modes.UI { @@ -20,6 +21,13 @@ namespace osu.Game.Modes.UI public event Action OnAllJudged; + internal readonly PlayerInputManager InputManager = new PlayerInputManager(); + + /// + /// A function to convert coordinates from gamefield to screen space. + /// + public abstract Func MapPlayfieldToScreenSpace { get; } + public abstract bool AllObjectsJudged { get; } protected void TriggerOnJudgement(JudgementInfo j) @@ -35,10 +43,10 @@ namespace osu.Game.Modes.UI { private List objects; - public PlayerInputManager InputManager; - protected Playfield Playfield; + public override Func MapPlayfieldToScreenSpace => Playfield.ScaledContent.ToScreenSpace; + public override bool AllObjectsJudged => Playfield.HitObjects.Children.First()?.Judgement.Result != null; //reverse depth sort means First() instead of Last(). public IEnumerable DrawableObjects => Playfield.HitObjects.Children; @@ -62,16 +70,26 @@ namespace osu.Game.Modes.UI protected HitRenderer() { RelativeSizeAxes = Axes.Both; + + InputManager.Add(content = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new[] + { + Playfield = CreatePlayfield(), + } + }); + + AddInternal(InputManager); } + protected override Container Content => content; + + private Container content; + [BackgroundDependencyLoader] private void load() { - Playfield = CreatePlayfield(); - Playfield.InputManager = InputManager; - - Add(Playfield); - loadObjects(); } diff --git a/osu.Game/Modes/UI/Playfield.cs b/osu.Game/Modes/UI/Playfield.cs index 502e072603..aa773323a5 100644 --- a/osu.Game/Modes/UI/Playfield.cs +++ b/osu.Game/Modes/UI/Playfield.cs @@ -1,13 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Modes.Objects; using osu.Game.Modes.Objects.Drawables; -using osu.Game.Screens.Play; +using OpenTK; namespace osu.Game.Modes.UI { @@ -18,22 +16,21 @@ namespace osu.Game.Modes.UI public virtual void Add(DrawableHitObject h) => HitObjects.Add(h); - public class HitObjectContainer : Container - where U : Drawable - { - public override bool Contains(Vector2 screenSpacePos) => true; - } - - private Container scaledContent; + internal Container ScaledContent; public override bool Contains(Vector2 screenSpacePos) => true; protected override Container Content { get; } - public Playfield() + /// + /// A container for keeping track of DrawableHitObjects. + /// + /// Whether we want our internal coordinate system to be scaled to a specified width. + protected Playfield(float? customWidth = null) { - AddInternal(scaledContent = new ScaledContainer + AddInternal(ScaledContent = new ScaledContainer { + CustomWidth = customWidth, RelativeSizeAxes = Axes.Both, Children = new[] { @@ -50,35 +47,24 @@ namespace osu.Game.Modes.UI }); } - /// - /// An optional inputManager to provide interactivity etc. - /// - public PlayerInputManager InputManager; - - [BackgroundDependencyLoader] - private void load() - { - if (InputManager != null) - { - //if we've been provided an InputManager, we want it to sit inside the scaledcontainer - scaledContent.Remove(Content); - scaledContent.Add(InputManager); - InputManager.Add(Content); - } - } - public virtual void PostProcess() { } - public class ScaledContainer : Container + private class ScaledContainer : Container { - protected override Vector2 DrawScale => new Vector2(DrawSize.X / 512); + /// + /// A value (in game pixels that we should scale our content to match). + /// + public float? CustomWidth; + + //dividing by the customwidth will effectively scale our content to the required container size. + protected override Vector2 DrawScale => CustomWidth.HasValue ? new Vector2(DrawSize.X / CustomWidth.Value) : base.DrawScale; public override bool Contains(Vector2 screenSpacePos) => true; } - public class HitObjectContainer : Container + public class HitObjectContainer : Container where U : Drawable { public override bool Contains(Vector2 screenSpacePos) => true; } diff --git a/osu.Game/Modes/UI/ScoreOverlay.cs b/osu.Game/Modes/UI/ScoreOverlay.cs index 66c361fcda..09f34d4c2e 100644 --- a/osu.Game/Modes/UI/ScoreOverlay.cs +++ b/osu.Game/Modes/UI/ScoreOverlay.cs @@ -81,11 +81,17 @@ namespace osu.Game.Modes.UI public void BindProcessor(ScoreProcessor processor) { - //bind processor bindables to combocounter, score display etc. + //bind processor bindables to combocounter, score display etc. + //TODO: these should be bindable binds, not events! processor.TotalScore.ValueChanged += delegate { ScoreCounter?.Set((ulong)processor.TotalScore.Value); }; processor.Accuracy.ValueChanged += delegate { AccuracyCounter?.Set((float)processor.Accuracy.Value); }; processor.Combo.ValueChanged += delegate { ComboCounter?.Set((ulong)processor.Combo.Value); }; HealthDisplay?.Current.BindTo(processor.Health); } + + public void BindHitRenderer(HitRenderer hitRenderer) + { + hitRenderer.InputManager.Add(KeyCounter.GetReceptor()); + } } } diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index b144db8626..aa2bf47227 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -1,10 +1,12 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Input; namespace osu.Game.Screens.Play { @@ -93,5 +95,37 @@ namespace osu.Game.Screens.Play } } } + + public override bool HandleInput => receptor?.IsAlive != true; + + private Receptor receptor; + + public Receptor GetReceptor() + { + return receptor ?? (receptor = new Receptor(this)); + } + + public class Receptor : Drawable + { + private KeyCounterCollection target; + + public Receptor(KeyCounterCollection target) + { + RelativeSizeAxes = Axes.Both; + this.target = target; + } + + public override bool Contains(Vector2 screenSpacePos) => true; + + public override bool HandleInput => true; + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerKeyDown(state, args)); + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => target.Children.Any(c => c.TriggerKeyUp(state, args)); + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => target.Children.Any(c => c.TriggerMouseDown(state, args)); + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => target.Children.Any(c => c.TriggerMouseUp(state, args)); + } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index f1206034b7..0026cc12fa 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -124,10 +124,15 @@ namespace osu.Game.Screens.Play OnQuit = Exit }; - hitRenderer = ruleset.CreateHitRendererWith(beatmap, new PlayerInputManager + hitRenderer = ruleset.CreateHitRendererWith(beatmap); + + if (ReplayInputHandler != null) { - ReplayInputHandler = ReplayInputHandler - }); + ReplayInputHandler.ToScreenSpace = hitRenderer.MapPlayfieldToScreenSpace; + hitRenderer.InputManager.ReplayInputHandler = ReplayInputHandler; + } + + scoreOverlay.BindHitRenderer(hitRenderer); //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation) hitRenderer.OnJudgement += scoreProcessor.AddJudgement; @@ -228,8 +233,8 @@ namespace osu.Game.Screens.Play if (!Push(newPlayer)) { - // Error(?) - } + // Error(?) + } }); } diff --git a/osu.Game/Screens/Play/PlayerInputManager.cs b/osu.Game/Screens/Play/PlayerInputManager.cs index 6d669e5169..a16c1ba9c6 100644 --- a/osu.Game/Screens/Play/PlayerInputManager.cs +++ b/osu.Game/Screens/Play/PlayerInputManager.cs @@ -35,10 +35,7 @@ namespace osu.Game.Screens.Play UseParentState = replayInputHandler == null; if (replayInputHandler != null) - { - replayInputHandler.ToScreenSpace = ToScreenSpace; AddHandler(replayInputHandler); - } } }