// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.UI { [Cached] public class Column : ScrollingPlayfield, IKeyBindingHandler, IHasAccentColour { public const float COLUMN_WIDTH = 80; public const float SPECIAL_COLUMN_WIDTH = 70; /// /// The index of this column as part of the whole playfield. /// public readonly int Index; public readonly Bindable Action = new Bindable(); public readonly ColumnHitObjectArea HitObjectArea; internal readonly Container TopLevelContainer; private readonly DrawablePool hitExplosionPool; private readonly OrderedHitPolicy hitPolicy; public Container UnderlayElements => HitObjectArea.UnderlayElements; private readonly GameplaySampleTriggerSource sampleTriggerSource; public Column(int index) { Index = index; RelativeSizeAxes = Axes.Y; Width = COLUMN_WIDTH; Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both }; InternalChildren = new[] { hitExplosionPool = new DrawablePool(5), sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer), // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both }, new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) { RelativeSizeAxes = Axes.Both }, background, TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }, new ColumnTouchInputArea(this) }; hitPolicy = new OrderedHitPolicy(HitObjectContainer); TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy()); RegisterPool(10, 50); RegisterPool(10, 50); RegisterPool(10, 50); RegisterPool(10, 50); RegisterPool(50, 250); } protected override void LoadComplete() { base.LoadComplete(); NewResult += OnNewResult; } public ColumnType ColumnType { get; set; } public bool IsSpecial => ColumnType == ColumnType.Special; public Color4 AccentColour { get; set; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); dependencies.CacheAs>(Action); return dependencies; } protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObject) { base.OnNewDrawableHitObject(drawableHitObject); DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)drawableHitObject; maniaObject.AccentColour.Value = AccentColour; maniaObject.CheckHittable = hitPolicy.IsHittable; } internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result) { if (result.IsHit) hitPolicy.HandleHit(judgedObject); if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value) return; HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result))); } public bool OnPressed(KeyBindingPressEvent e) { if (e.Action != Action.Value) return false; sampleTriggerSource.Play(); return true; } public void OnReleased(KeyBindingReleaseEvent e) { } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) // This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border => DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos)); public class ColumnTouchInputArea : Drawable { private readonly Column column; [Resolved(canBeNull: true)] private ManiaInputManager maniaInputManager { get; set; } private KeyBindingContainer keyBindingContainer; public ColumnTouchInputArea(Column column) { RelativeSizeAxes = Axes.Both; this.column = column; } protected override void LoadComplete() { keyBindingContainer = maniaInputManager?.KeyBindingContainer; } protected override bool OnMouseDown(MouseDownEvent e) { keyBindingContainer?.TriggerPressed(column.Action.Value); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { keyBindingContainer?.TriggerReleased(column.Action.Value); base.OnMouseUp(e); } protected override bool OnTouchDown(TouchDownEvent e) { keyBindingContainer?.TriggerPressed(column.Action.Value); return true; } protected override void OnTouchUp(TouchUpEvent e) { keyBindingContainer?.TriggerReleased(column.Action.Value); } } } }