1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 20:47:28 +08:00

Implement mania hit target skinning

This commit is contained in:
smoogipoo 2020-03-31 12:17:44 +09:00
parent 2b5e9885f6
commit 02237133cb
10 changed files with 252 additions and 139 deletions

View File

@ -0,0 +1,49 @@
// 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.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.UI;
using osuTK;
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
public class TestSceneColumnHitObjectArea : ManiaSkinnableTestScene
{
[BackgroundDependencyLoader]
private void load()
{
SetContents(() => new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f),
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
new ColumnTestContainer(0, ManiaAction.Key1)
{
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
Child = new ColumnHitObjectArea(new HitObjectContainer())
{
RelativeSizeAxes = Axes.Both
}
},
new ColumnTestContainer(1, ManiaAction.Key2)
{
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
Child = new ColumnHitObjectArea(new HitObjectContainer())
{
RelativeSizeAxes = Axes.Both
}
}
}
});
}
}
}

View File

@ -19,5 +19,6 @@ namespace osu.Game.Rulesets.Mania
public enum ManiaSkinComponents public enum ManiaSkinComponents
{ {
HitTarget
} }
} }

View File

@ -0,0 +1,69 @@
// 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.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning;
using osuTK;
namespace osu.Game.Rulesets.Mania.Skinning
{
public class LegacyHitTarget : CompositeDrawable
{
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
[Resolved(CanBeNull = true)]
private ManiaStage stage { get; set; }
private Container directionContainer;
public LegacyHitTarget()
{
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
{
string targetImage = skin.GetConfig<LegacyManiaSkinConfigurationLookup, string>(
new LegacyManiaSkinConfigurationLookup(stage?.Columns.Count ?? 4, LegacyManiaSkinConfigurationLookups.HitTargetImage))?.Value
?? "mania-stage-hint";
InternalChild = directionContainer = new Container
{
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = new Sprite
{
Texture = skin.GetTexture(targetImage),
Scale = new Vector2(1, 0.9f * 1.6025f),
RelativeSizeAxes = Axes.X,
Width = 1
}
};
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true);
}
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
{
if (direction.NewValue == ScrollingDirection.Up)
{
directionContainer.Anchor = Anchor.TopLeft;
directionContainer.Scale = new Vector2(1, -1);
}
else
{
directionContainer.Anchor = Anchor.BottomLeft;
directionContainer.Scale = Vector2.One;
}
}
}
}

View File

@ -38,10 +38,16 @@ namespace osu.Game.Rulesets.Mania.Skinning
case GameplaySkinComponent<HitResult> resultComponent: case GameplaySkinComponent<HitResult> resultComponent:
return getResult(resultComponent); return getResult(resultComponent);
case ManiaSkinComponent _: case ManiaSkinComponent maniaComponent:
if (!isLegacySkin.Value) if (!isLegacySkin.Value)
return null; return null;
switch (maniaComponent.Component)
{
case ManiaSkinComponents.HitTarget:
return new LegacyHitTarget();
}
break; break;
} }

View File

@ -12,7 +12,6 @@ using osu.Framework.Bindables;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK; using osuTK;
@ -32,12 +31,11 @@ namespace osu.Game.Rulesets.Mania.UI
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>(); public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
private readonly ColumnHitObjectArea hitObjectArea;
private readonly ColumnBackground background; private readonly ColumnBackground background;
private readonly ColumnKeyArea keyArea; private readonly ColumnKeyArea keyArea;
private readonly ColumnHitObjectArea hitObjectArea;
internal readonly Container TopLevelContainer; internal readonly Container TopLevelContainer;
private readonly Container explosionContainer;
public Column(int index) public Column(int index)
{ {
@ -48,29 +46,11 @@ namespace osu.Game.Rulesets.Mania.UI
background = new ColumnBackground { RelativeSizeAxes = Axes.Both }; background = new ColumnBackground { RelativeSizeAxes = Axes.Both };
Container hitTargetContainer;
InternalChildren = new[] InternalChildren = new[]
{ {
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
background.CreateProxy(), background.CreateProxy(),
hitTargetContainer = new Container hitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both },
{
Name = "Hit target + hit objects",
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
hitObjectArea = new ColumnHitObjectArea(HitObjectContainer)
{
RelativeSizeAxes = Axes.Both,
},
explosionContainer = new Container
{
Name = "Hit explosions",
RelativeSizeAxes = Axes.Both,
}
}
},
keyArea = new ColumnKeyArea keyArea = new ColumnKeyArea
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -80,22 +60,10 @@ namespace osu.Game.Rulesets.Mania.UI
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both } TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
}; };
TopLevelContainer.Add(explosionContainer.CreateProxy()); TopLevelContainer.Add(hitObjectArea.Explosions.CreateProxy());
Direction.BindValueChanged(dir => Direction.BindValueChanged(dir =>
{ {
hitTargetContainer.Padding = new MarginPadding
{
Top = dir.NewValue == ScrollingDirection.Up ? ManiaStage.HIT_TARGET_POSITION : 0,
Bottom = dir.NewValue == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0,
};
explosionContainer.Padding = new MarginPadding
{
Top = dir.NewValue == ScrollingDirection.Up ? NotePiece.NOTE_HEIGHT / 2 : 0,
Bottom = dir.NewValue == ScrollingDirection.Down ? NotePiece.NOTE_HEIGHT / 2 : 0
};
keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
}, true); }, true);
} }
@ -132,7 +100,6 @@ namespace osu.Game.Rulesets.Mania.UI
background.AccentColour = value; background.AccentColour = value;
keyArea.AccentColour = value; keyArea.AccentColour = value;
hitObjectArea.AccentColour = value;
} }
} }
@ -169,7 +136,7 @@ namespace osu.Game.Rulesets.Mania.UI
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value) if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
return; return;
explosionContainer.Add(new HitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick) hitObjectArea.Explosions.Add(new HitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick)
{ {
Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre, Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre,
Origin = Anchor.Centre Origin = Anchor.Centre

View File

@ -3,34 +3,35 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK.Graphics; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania.UI.Components namespace osu.Game.Rulesets.Mania.UI.Components
{ {
public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour public class ColumnHitObjectArea : SkinReloadableDrawable
{ {
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); public readonly Container<HitExplosion> Explosions;
[Resolved(CanBeNull = true)]
private ManiaStage stage { get; set; }
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly Drawable hitTarget; private readonly Drawable hitTarget;
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer) public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
{ {
InternalChildren = new[] InternalChildren = new[]
{ {
hitTarget = new DefaultHitTarget hitTarget = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitTarget), _ => new DefaultHitTarget())
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}, },
hitObjectContainer hitObjectContainer,
Explosions = new Container<HitExplosion> { RelativeSizeAxes = Axes.Both }
}; };
} }
@ -38,107 +39,39 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private void load(IScrollingInfo scrollingInfo) private void load(IScrollingInfo scrollingInfo)
{ {
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(dir => direction.BindValueChanged(onDirectionChanged, true);
{
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
hitTarget.Anchor = hitTarget.Origin = anchor;
}, true);
} }
private Color4 accentColour; protected override void SkinChanged(ISkinSource skin, bool allowFallback)
public Color4 AccentColour
{ {
get => accentColour; base.SkinChanged(skin, allowFallback);
set updateHitPosition();
{
if (accentColour == value)
return;
accentColour = value;
if (hitTarget is IHasAccentColour colouredHitTarget)
colouredHitTarget.AccentColour = accentColour;
}
} }
private class DefaultHitTarget : CompositeDrawable, IHasAccentColour private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
{ {
private const float hit_target_bar_height = 2; updateHitPosition();
}
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private void updateHitPosition()
{
float hitPosition = CurrentSkin.GetConfig<LegacyManiaSkinConfigurationLookup, float>(
new LegacyManiaSkinConfigurationLookup(stage?.Columns.Count ?? 4, LegacyManiaSkinConfigurationLookups.HitPosition))?.Value
?? ManiaStage.HIT_TARGET_POSITION;
private readonly Container hitTargetLine; if (direction.Value == ScrollingDirection.Up)
private readonly Drawable hitTargetBar;
public DefaultHitTarget()
{ {
InternalChildren = new[] hitTarget.Anchor = hitTarget.Origin = Anchor.TopLeft;
{
hitTargetBar = new Box Padding = new MarginPadding { Top = hitPosition };
{ Explosions.Padding = new MarginPadding { Top = NotePiece.NOTE_HEIGHT };
RelativeSizeAxes = Axes.X,
Height = NotePiece.NOTE_HEIGHT,
Alpha = 0.6f,
Colour = Color4.Black
},
hitTargetLine = new Container
{
RelativeSizeAxes = Axes.X,
Height = hit_target_bar_height,
Masking = true,
Child = new Box { RelativeSizeAxes = Axes.Both }
},
};
} }
else
[BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo)
{ {
direction.BindTo(scrollingInfo.Direction); hitTarget.Anchor = hitTarget.Origin = Anchor.BottomLeft;
direction.BindValueChanged(dir =>
{
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
hitTargetBar.Anchor = hitTargetBar.Origin = anchor; Padding = new MarginPadding { Bottom = hitPosition };
hitTargetLine.Anchor = hitTargetLine.Origin = anchor; Explosions.Padding = new MarginPadding { Bottom = NotePiece.NOTE_HEIGHT };
}, true);
}
protected override void LoadComplete()
{
base.LoadComplete();
updateColours();
}
private Color4 accentColour;
public Color4 AccentColour
{
get => accentColour;
set
{
if (accentColour == value)
return;
accentColour = value;
updateColours();
}
}
private void updateColours()
{
if (!IsLoaded)
return;
hitTargetLine.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = accentColour.Opacity(0.5f),
};
} }
} }
} }

View File

@ -0,0 +1,80 @@
// 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.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI.Components
{
public class DefaultHitTarget : CompositeDrawable
{
private const float hit_target_bar_height = 2;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private Container hitTargetLine;
private Drawable hitTargetBar;
[Resolved]
private Column column { get; set; }
public DefaultHitTarget()
{
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo)
{
InternalChildren = new[]
{
hitTargetBar = new Box
{
RelativeSizeAxes = Axes.X,
Height = NotePiece.NOTE_HEIGHT,
Alpha = 0.6f,
Colour = Color4.Black
},
hitTargetLine = new Container
{
RelativeSizeAxes = Axes.X,
Height = hit_target_bar_height,
Masking = true,
Child = new Box { RelativeSizeAxes = Axes.Both }
},
};
hitTargetLine.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = column.AccentColour.Opacity(0.5f),
};
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(onDirectionChanged, true);
}
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
{
if (direction.NewValue == ScrollingDirection.Up)
{
hitTargetBar.Anchor = hitTargetBar.Origin = Anchor.TopLeft;
hitTargetLine.Anchor = hitTargetLine.Origin = Anchor.TopLeft;
}
else
{
hitTargetBar.Anchor = hitTargetBar.Origin = Anchor.BottomLeft;
hitTargetLine.Anchor = hitTargetLine.Origin = Anchor.BottomLeft;
}
}
}
}

View File

@ -12,7 +12,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
internal class HitExplosion : CompositeDrawable public class HitExplosion : CompositeDrawable
{ {
public override bool RemoveWhenNotAlive => true; public override bool RemoveWhenNotAlive => true;

View File

@ -19,5 +19,7 @@ namespace osu.Game.Skinning
public enum LegacyManiaSkinConfigurationLookups public enum LegacyManiaSkinConfigurationLookups
{ {
HitPosition,
HitTargetImage
} }
} }

View File

@ -124,8 +124,14 @@ namespace osu.Game.Skinning
if (!AllowManiaSkin) if (!AllowManiaSkin)
return null; return null;
if (!maniaConfigurations.TryGetValue(legacy.Keys, out _)) if (!maniaConfigurations.TryGetValue(legacy.Keys, out var existing))
maniaConfigurations[legacy.Keys] = new LegacyManiaSkinConfiguration(legacy.Keys); maniaConfigurations[legacy.Keys] = existing = new LegacyManiaSkinConfiguration(legacy.Keys);
switch (legacy.Lookup)
{
case LegacyManiaSkinConfigurationLookups.HitPosition:
return SkinUtils.As<TValue>(new Bindable<float>(existing.HitPosition));
}
break; break;