1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 09:27:29 +08:00

Rework to remove cross-class pollutions

This commit is contained in:
smoogipoo 2020-08-25 01:21:27 +09:00
parent 77bf646ea0
commit 018523a43a
8 changed files with 252 additions and 156 deletions

View File

@ -21,14 +21,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary>
/// <param name="column">The 0-based column index.</param>
/// <returns>Whether the column is a special column.</returns>
public bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2;
public readonly bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2;
/// <summary>
/// Get the type of column given a column index.
/// </summary>
/// <param name="column">The 0-based column index.</param>
/// <returns>The type of the column.</returns>
public ColumnType GetTypeOfColumn(int column)
public readonly ColumnType GetTypeOfColumn(int column)
{
if (IsSpecialColumn(column))
return ColumnType.Special;

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Skinning;
@ -14,15 +15,23 @@ namespace osu.Game.Rulesets.Mania
/// </summary>
public readonly int? TargetColumn;
/// <summary>
/// The intended <see cref="StageDefinition"/> for this component.
/// May be null if the component is not a direct member of a <see cref="Stage"/>.
/// </summary>
public readonly StageDefinition? StageDefinition;
/// <summary>
/// Creates a new <see cref="ManiaSkinComponent"/>.
/// </summary>
/// <param name="component">The component.</param>
/// <param name="targetColumn">The intended <see cref="Column"/> index for this component. May be null if the component does not exist in a <see cref="Column"/>.</param>
public ManiaSkinComponent(ManiaSkinComponents component, int? targetColumn = null)
/// <param name="stageDefinition">The intended <see cref="StageDefinition"/> for this component. May be null if the component is not a direct member of a <see cref="Stage"/>.</param>
public ManiaSkinComponent(ManiaSkinComponents component, int? targetColumn = null, StageDefinition? stageDefinition = null)
: base(component)
{
TargetColumn = targetColumn;
StageDefinition = stageDefinition;
}
protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME;

View File

@ -1,15 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning;
using osuTK;
@ -20,22 +17,12 @@ namespace osu.Game.Rulesets.Mania.Skinning
public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
{
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly bool isLastColumn;
[CanBeNull]
private readonly LegacyStageBackground stageBackground;
private Container hitTargetContainer;
private Container lightContainer;
private Sprite light;
private Drawable hitTarget;
private float hitPosition;
public LegacyColumnBackground(bool isLastColumn, [CanBeNull] LegacyStageBackground stageBackground)
public LegacyColumnBackground()
{
this.isLastColumn = isLastColumn;
this.stageBackground = stageBackground;
RelativeSizeAxes = Axes.Both;
}
@ -45,80 +32,14 @@ namespace osu.Game.Rulesets.Mania.Skinning
string lightImage = skin.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.LightImage)?.Value
?? "mania-stage-light";
float leftLineWidth = GetColumnSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.LeftLineWidth)
?.Value ?? 1;
float rightLineWidth = GetColumnSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.RightLineWidth)
?.Value ?? 1;
bool hasLeftLine = leftLineWidth > 0;
bool hasRightLine = rightLineWidth > 0 && skin.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value >= 2.4m
|| isLastColumn;
bool hasHitTarget = Column.Index == 0 || stageBackground == null;
hitPosition = GetColumnSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.HitPosition)?.Value
?? Stage.HIT_TARGET_POSITION;
float lightPosition = GetColumnSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.LightPosition)?.Value
?? 0;
Color4 lineColour = GetColumnSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnLineColour)?.Value
?? Color4.White;
Color4 backgroundColour = GetColumnSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour)?.Value
?? Color4.Black;
Color4 lightColour = GetColumnSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnLightColour)?.Value
?? Color4.White;
Container backgroundLayer;
Drawable leftLine;
Drawable rightLine;
InternalChildren = new[]
{
backgroundLayer = new Container
{
RelativeSizeAxes = Axes.Both,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = backgroundColour
},
},
hitTargetContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new[]
{
leftLine = new Box
{
RelativeSizeAxes = Axes.Y,
Width = leftLineWidth,
Scale = new Vector2(0.740f, 1),
Colour = lineColour,
Alpha = hasLeftLine ? 1 : 0
},
rightLine = new Box
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = rightLineWidth,
Scale = new Vector2(0.740f, 1),
Colour = lineColour,
Alpha = hasRightLine ? 1 : 0
},
// In legacy skins, the hit target takes on the full stage size and is sandwiched between the column background and the column light.
// To simulate this effect in lazer's hierarchy, the hit target is added to the first column's background and manually extended to the full size of the stage.
// Adding to the first columns allows depth issues to be resolved - if it were added to the last column, the previous column lights would appear below it.
// This still means that the hit target will appear below the next column backgrounds, but that's a much easier problem to solve by proxying the background layer below.
hitTarget = new LegacyHitTarget
{
RelativeSizeAxes = Axes.Y,
Alpha = hasHitTarget ? 1 : 0
},
}
},
lightContainer = new Container
{
Origin = Anchor.BottomCentre,
@ -137,11 +58,6 @@ namespace osu.Game.Rulesets.Mania.Skinning
}
};
// Resolve depth issues with the hit target appearing under the next column backgrounds by proxying to the stage background (always below the columns).
backgroundLayer.Add(leftLine.CreateProxy());
backgroundLayer.Add(rightLine.CreateProxy());
stageBackground?.AddColumnBackground(backgroundLayer.CreateProxy());
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true);
}
@ -152,24 +68,14 @@ namespace osu.Game.Rulesets.Mania.Skinning
{
lightContainer.Anchor = Anchor.TopCentre;
lightContainer.Scale = new Vector2(1, -1);
hitTargetContainer.Padding = new MarginPadding { Top = hitPosition };
}
else
{
lightContainer.Anchor = Anchor.BottomCentre;
lightContainer.Scale = Vector2.One;
hitTargetContainer.Padding = new MarginPadding { Bottom = hitPosition };
}
}
protected override void Update()
{
base.Update();
hitTarget.Width = stageBackground?.DrawWidth ?? DrawWidth;
}
public bool OnPressed(ManiaAction action)
{
if (action == Column.Action.Value)

View File

@ -2,22 +2,31 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Skinning
{
public class LegacyStageBackground : CompositeDrawable
{
private readonly StageDefinition stageDefinition;
private Drawable leftSprite;
private Drawable rightSprite;
private Container columnBackgroundContainer;
private ColumnFlow<Drawable> columnBackgrounds;
public LegacyStageBackground()
public LegacyStageBackground(StageDefinition stageDefinition)
{
this.stageDefinition = stageDefinition;
RelativeSizeAxes = Axes.Both;
}
@ -46,8 +55,18 @@ namespace osu.Game.Rulesets.Mania.Skinning
X = -0.05f,
Texture = skin.GetTexture(rightImage)
},
columnBackgroundContainer = new Container { RelativeSizeAxes = Axes.Both }
columnBackgrounds = new ColumnFlow<Drawable>(stageDefinition)
{
RelativeSizeAxes = Axes.Y
},
new HitTargetInsetContainer
{
Child = new LegacyHitTarget { RelativeSizeAxes = Axes.Both }
}
};
for (int i = 0; i < stageDefinition.Columns; i++)
columnBackgrounds.SetColumn(i, new ColumnBackground(i, i == stageDefinition.Columns - 1));
}
protected override void Update()
@ -61,6 +80,103 @@ namespace osu.Game.Rulesets.Mania.Skinning
rightSprite.Scale = new Vector2(1, DrawHeight / rightSprite.Height);
}
public void AddColumnBackground(Drawable background) => columnBackgroundContainer.Add(background);
private class ColumnBackground : CompositeDrawable
{
private readonly int columnIndex;
private readonly bool isLastColumn;
public ColumnBackground(int columnIndex, bool isLastColumn)
{
this.columnIndex = columnIndex;
this.isLastColumn = isLastColumn;
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
float leftLineWidth = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.LeftLineWidth, columnIndex)?.Value ?? 1;
float rightLineWidth = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.RightLineWidth, columnIndex)?.Value ?? 1;
bool hasLeftLine = leftLineWidth > 0;
bool hasRightLine = rightLineWidth > 0 && skin.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value >= 2.4m
|| isLastColumn;
Color4 lineColour = skin.GetManiaSkinConfig<Color4>(LegacyManiaSkinConfigurationLookups.ColumnLineColour, columnIndex)?.Value ?? Color4.White;
Color4 backgroundColour = skin.GetManiaSkinConfig<Color4>(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, columnIndex)?.Value ?? Color4.Black;
InternalChildren = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = backgroundColour
},
},
new HitTargetInsetContainer
{
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Y,
Width = leftLineWidth,
Scale = new Vector2(0.740f, 1),
Colour = lineColour,
Alpha = hasLeftLine ? 1 : 0
},
new Box
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = rightLineWidth,
Scale = new Vector2(0.740f, 1),
Colour = lineColour,
Alpha = hasRightLine ? 1 : 0
},
}
}
};
}
}
private class HitTargetInsetContainer : Container
{
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
protected override Container<Drawable> Content => content;
private readonly Container content;
private float hitPosition;
public HitTargetInsetContainer()
{
RelativeSizeAxes = Axes.Both;
InternalChild = content = new Container { RelativeSizeAxes = Axes.Both };
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
{
hitPosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? Stage.HIT_TARGET_POSITION;
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true);
}
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
{
content.Padding = direction.NewValue == ScrollingDirection.Up
? new MarginPadding { Top = hitPosition }
: new MarginPadding { Bottom = hitPosition };
}
}
}
}

View File

@ -9,6 +9,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Skinning;
using System.Collections.Generic;
using System.Diagnostics;
using osu.Framework.Audio.Sample;
using osu.Game.Audio;
using osu.Game.Rulesets.Objects.Legacy;
@ -57,8 +58,6 @@ namespace osu.Game.Rulesets.Mania.Skinning
/// </summary>
private Lazy<bool> hasKeyTexture;
private LegacyStageBackground stageBackground;
public ManiaLegacySkinTransformer(ISkinSource source, IBeatmap beatmap)
: base(source)
{
@ -90,10 +89,11 @@ namespace osu.Game.Rulesets.Mania.Skinning
switch (maniaComponent.Component)
{
case ManiaSkinComponents.ColumnBackground:
return new LegacyColumnBackground(maniaComponent.TargetColumn == beatmap.TotalColumns - 1, stageBackground);
return new LegacyColumnBackground();
case ManiaSkinComponents.HitTarget:
// Created within the column background, but should not fall back. See comments in LegacyColumnBackground.
// Legacy skins sandwich the hit target between the column background and the column light.
// To preserve this ordering, it's created manually inside LegacyStageBackground.
return Drawable.Empty();
case ManiaSkinComponents.KeyArea:
@ -115,7 +115,8 @@ namespace osu.Game.Rulesets.Mania.Skinning
return new LegacyHitExplosion();
case ManiaSkinComponents.StageBackground:
return stageBackground = new LegacyStageBackground();
Debug.Assert(maniaComponent.StageDefinition != null);
return new LegacyStageBackground(maniaComponent.StageDefinition.Value);
case ManiaSkinComponents.StageForeground:
return new LegacyStageForeground();

View File

@ -68,8 +68,6 @@ namespace osu.Game.Rulesets.Mania.UI
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
}
public override Axes RelativeSizeAxes => Axes.Y;
public ColumnType ColumnType { get; set; }
public bool IsSpecial => ColumnType == ColumnType.Special;

View File

@ -0,0 +1,105 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Skinning;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania.UI
{
/// <summary>
/// A <see cref="Drawable"/> which flows its contents according to the <see cref="Column"/>s in a <see cref="Stage"/>.
/// Content can be added to individual columns via <see cref="SetColumn"/>.
/// </summary>
/// <typeparam name="TContent">The type of content in each column.</typeparam>
public class ColumnFlow<TContent> : CompositeDrawable
where TContent : Drawable
{
/// <summary>
/// All contents added to this <see cref="ColumnFlow{TContent}"/>.
/// </summary>
public IReadOnlyList<TContent> Content => columns.Children.Select(c => c.Count == 0 ? null : (TContent)c.Child).ToList();
private readonly FillFlowContainer<Container> columns;
private readonly StageDefinition stageDefinition;
public ColumnFlow(StageDefinition stageDefinition)
{
this.stageDefinition = stageDefinition;
AutoSizeAxes = Axes.X;
InternalChild = columns = new FillFlowContainer<Container>
{
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
};
for (int i = 0; i < stageDefinition.Columns; i++)
columns.Add(new Container { RelativeSizeAxes = Axes.Y });
}
private ISkinSource currentSkin;
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
currentSkin = skin;
skin.SourceChanged += onSkinChanged;
onSkinChanged();
}
private void onSkinChanged()
{
for (int i = 0; i < stageDefinition.Columns; i++)
{
if (i > 0)
{
float spacing = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, i - 1))
?.Value ?? Stage.COLUMN_SPACING;
columns[i].Margin = new MarginPadding { Left = spacing };
}
float? width = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, i))
?.Value;
if (width == null)
// only used by default skin (legacy skins get defaults set in LegacyManiaSkinConfiguration)
columns[i].Width = stageDefinition.IsSpecialColumn(i) ? Column.SPECIAL_COLUMN_WIDTH : Column.COLUMN_WIDTH;
else
columns[i].Width = width.Value;
}
}
/// <summary>
/// Sets the content of one of the columns of this <see cref="ColumnFlow{TContent}"/>.
/// </summary>
/// <param name="column">The index of the column to set the content of.</param>
/// <param name="content">The content.</param>
public void SetColumn(int column, TContent content) => columns[column].Child = content;
public new MarginPadding Padding
{
get => base.Padding;
set => base.Padding = value;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (currentSkin != null)
currentSkin.SourceChanged -= onSkinChanged;
}
}
}

View File

@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
@ -11,7 +10,6 @@ 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.Mania.Skinning;
using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
@ -31,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.UI
public const float HIT_TARGET_POSITION = 110;
public IReadOnlyList<Column> Columns => columnFlow.Children;
private readonly FillFlowContainer<Column> columnFlow;
public IReadOnlyList<Column> Columns => columnFlow.Content;
private readonly ColumnFlow<Column> columnFlow;
private readonly JudgementContainer<DrawableManiaJudgement> judgements;
private readonly DrawablePool<DrawableManiaJudgement> judgementPool;
@ -73,16 +71,13 @@ namespace osu.Game.Rulesets.Mania.UI
AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground())
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: definition), _ => new DefaultStageBackground())
{
RelativeSizeAxes = Axes.Both
},
columnFlow = new FillFlowContainer<Column>
columnFlow = new ColumnFlow<Column>(definition)
{
Name = "Columns",
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
},
new Container
@ -102,7 +97,7 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y,
}
},
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null)
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: definition), _ => null)
{
RelativeSizeAxes = Axes.Both
},
@ -123,6 +118,8 @@ namespace osu.Game.Rulesets.Mania.UI
var columnType = definition.GetTypeOfColumn(i);
var column = new Column(firstColumnIndex + i)
{
RelativeSizeAxes = Axes.Both,
Width = 1,
ColumnType = columnType,
AccentColour = columnColours[columnType],
Action = { Value = columnType == ColumnType.Special ? specialColumnStartAction++ : normalColumnStartAction++ }
@ -132,46 +129,10 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
private ISkin currentSkin;
[BackgroundDependencyLoader]
private void load(ISkinSource skin)
{
currentSkin = skin;
skin.SourceChanged += onSkinChanged;
onSkinChanged();
}
private void onSkinChanged()
{
foreach (var col in columnFlow)
{
if (col.Index > 0)
{
float spacing = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, col.Index - 1))
?.Value ?? COLUMN_SPACING;
col.Margin = new MarginPadding { Left = spacing };
}
float? width = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, col.Index))
?.Value;
if (width == null)
// only used by default skin (legacy skins get defaults set in LegacyManiaSkinConfiguration)
col.Width = col.IsSpecial ? Column.SPECIAL_COLUMN_WIDTH : Column.COLUMN_WIDTH;
else
col.Width = width.Value;
}
}
public void AddColumn(Column c)
{
topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
columnFlow.Add(c);
columnFlow.SetColumn(c.Index, c);
AddNested(c);
}