// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI { /// /// A collection of s. /// public class ManiaStage : ScrollingPlayfield { public const float HIT_TARGET_POSITION = 50; public IReadOnlyList Columns => columnFlow.Children; private readonly FillFlowContainer columnFlow; private readonly Container barLineContainer; public Container Judgements => judgements; private readonly JudgementContainer judgements; private readonly Container topLevelContainer; private List normalColumnColours = new List(); private Color4 specialColumnColour; private readonly int firstColumnIndex; public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction) { this.firstColumnIndex = firstColumnIndex; Name = "Stage"; Anchor = Anchor.Centre; Origin = Anchor.Centre; RelativeSizeAxes = Axes.Y; AutoSizeAxes = Axes.X; InternalChildren = new Drawable[] { new Container { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, Children = new Drawable[] { new Container { Name = "Columns mask", RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, Masking = true, CornerRadius = 5, Children = new Drawable[] { new Box { Name = "Background", RelativeSizeAxes = Axes.Both, Colour = Color4.Black }, columnFlow = new FillFlowContainer { Name = "Columns", RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, Direction = FillDirection.Horizontal, Padding = new MarginPadding { Left = 1, Right = 1 }, Spacing = new Vector2(1, 0) }, } }, new Container { Name = "Barlines mask", Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, Width = 1366, // Bar lines should only be masked on the vertical axis BypassAutoSizeAxes = Axes.Both, Masking = true, Child = barLineContainer = new Container { Name = "Bar lines", Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, Child = HitObjectContainer } }, judgements = new JudgementContainer { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Y = HIT_TARGET_POSITION + 150, BypassAutoSizeAxes = Axes.Both }, topLevelContainer = new Container { RelativeSizeAxes = Axes.Both } } } }; for (int i = 0; i < definition.Columns; i++) { var isSpecial = definition.IsSpecialColumn(i); var column = new Column { IsSpecial = isSpecial, Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ } }; AddColumn(column); } Direction.BindValueChanged(d => { barLineContainer.Padding = new MarginPadding { Top = d == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0, Bottom = d == ScrollingDirection.Down ? HIT_TARGET_POSITION : 0, }; }, true); } public void AddColumn(Column c) { topLevelContainer.Add(c.TopLevelContainer.CreateProxy()); columnFlow.Add(c); AddNested(c); } public override void Add(DrawableHitObject h) { var maniaObject = (ManiaHitObject)h.HitObject; int columnIndex = maniaObject.Column - firstColumnIndex; Columns.ElementAt(columnIndex).Add(h); h.OnNewResult += OnNewResult; } public override void Remove(DrawableHitObject h) { var maniaObject = (ManiaHitObject)h.HitObject; int columnIndex = maniaObject.Column - firstColumnIndex; Columns.ElementAt(columnIndex).Remove(h); h.OnNewResult -= OnNewResult; } public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline)); internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result) { if (!judgedObject.DisplayResult || !DisplayJudgements) return; judgements.Clear(); judgements.Add(new DrawableManiaJudgement(result, judgedObject) { Anchor = Anchor.Centre, Origin = Anchor.Centre, }); } [BackgroundDependencyLoader] private void load() { normalColumnColours = new List { new Color4(94, 0, 57, 255), new Color4(6, 84, 0, 255) }; specialColumnColour = new Color4(0, 48, 63, 255); // Set the special column + colour + key foreach (var column in Columns) { if (!column.IsSpecial) continue; column.AccentColour = specialColumnColour; } var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList(); // We'll set the colours of the non-special columns in a separate loop, because the non-special // column colours are mirrored across their centre and special styles mess with this for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++) { Color4 colour = normalColumnColours[i % normalColumnColours.Count]; nonSpecialColumns[i].AccentColour = colour; nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour; } } protected override void Update() { // Due to masking differences, it is not possible to get the width of the columns container automatically // While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually barLineContainer.Width = columnFlow.Width; } } }