mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 17:32:54 +08:00
Merge pull request #24387 from peppy/playfield-skin-layer
Add new skin layer to allow components anchored to the playfield
This commit is contained in:
commit
bd8b9c8e63
@ -9,6 +9,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -25,6 +26,22 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
private readonly List<Stage> stages = new List<Stage>();
|
||||
|
||||
public override Quad SkinnableComponentScreenSpaceDrawQuad
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Stages.Count == 1)
|
||||
return Stages.First().ScreenSpaceDrawQuad;
|
||||
|
||||
RectangleF area = RectangleF.Empty;
|
||||
|
||||
foreach (var stage in Stages)
|
||||
area = RectangleF.Union(area, stage.ScreenSpaceDrawQuad.AABBFloat);
|
||||
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => stages.Any(s => s.ReceivePositionalInputAt(screenSpacePos));
|
||||
|
||||
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.SkinEditor;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
@ -19,7 +20,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestToggleEditor()
|
||||
{
|
||||
AddStep("show available components", () => SetContents(_ => new SkinComponentToolbox
|
||||
var skinComponentsContainer = new SkinComponentsContainer(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.SongSelect));
|
||||
|
||||
AddStep("show available components", () => SetContents(_ => new SkinComponentToolbox(skinComponentsContainer, null)
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.IO.Archives
|
||||
{
|
||||
ZipArchiveEntry entry = archive.Entries.SingleOrDefault(e => e.Key == name);
|
||||
if (entry == null)
|
||||
throw new FileNotFoundException();
|
||||
return null;
|
||||
|
||||
var owner = MemoryAllocator.Default.Allocate<byte>((int)entry.Size);
|
||||
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Edit.Components;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
@ -23,14 +24,22 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
{
|
||||
public Action<Type>? RequestPlacement;
|
||||
|
||||
private readonly SkinComponentsContainer? target;
|
||||
private readonly SkinComponentsContainer target;
|
||||
|
||||
private readonly RulesetInfo? ruleset;
|
||||
|
||||
private FillFlowContainer fill = null!;
|
||||
|
||||
public SkinComponentToolbox(SkinComponentsContainer? target = null)
|
||||
: base(target?.Lookup.Ruleset == null ? SkinEditorStrings.Components : LocalisableString.Interpolate($"{SkinEditorStrings.Components} ({target.Lookup.Ruleset.Name})"))
|
||||
/// <summary>
|
||||
/// Create a new component toolbox for the specified taget.
|
||||
/// </summary>
|
||||
/// <param name="target">The target. This is mainly used as a dependency source to find candidate components.</param>
|
||||
/// <param name="ruleset">A ruleset to filter components by. If null, only components which are not ruleset-specific will be included.</param>
|
||||
public SkinComponentToolbox(SkinComponentsContainer target, RulesetInfo? ruleset)
|
||||
: base(ruleset == null ? SkinEditorStrings.Components : LocalisableString.Interpolate($"{SkinEditorStrings.Components} ({ruleset.Name})"))
|
||||
{
|
||||
this.target = target;
|
||||
this.ruleset = ruleset;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -51,7 +60,7 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
{
|
||||
fill.Clear();
|
||||
|
||||
var skinnableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables(target?.Lookup.Ruleset);
|
||||
var skinnableTypes = SerialisedDrawableInfo.GetAllAvailableDrawables(ruleset);
|
||||
foreach (var type in skinnableTypes)
|
||||
attemptAddComponent(type);
|
||||
}
|
||||
|
@ -366,14 +366,14 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
// If the new target has a ruleset, let's show ruleset-specific items at the top, and the rest below.
|
||||
if (target.NewValue.Ruleset != null)
|
||||
{
|
||||
componentsSidebar.Add(new SkinComponentToolbox(skinComponentsContainer)
|
||||
componentsSidebar.Add(new SkinComponentToolbox(skinComponentsContainer, target.NewValue.Ruleset)
|
||||
{
|
||||
RequestPlacement = requestPlacement
|
||||
});
|
||||
}
|
||||
|
||||
// Remove the ruleset from the lookup to get base components.
|
||||
componentsSidebar.Add(new SkinComponentToolbox(getTarget(new SkinComponentsContainerLookup(target.NewValue.Target)))
|
||||
componentsSidebar.Add(new SkinComponentToolbox(skinComponentsContainer, null)
|
||||
{
|
||||
RequestPlacement = requestPlacement
|
||||
});
|
||||
|
@ -23,6 +23,7 @@ using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osu.Game.Rulesets.Objects.Pooling;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -94,6 +95,16 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public readonly BindableBool DisplayJudgements = new BindableBool(true);
|
||||
|
||||
/// <summary>
|
||||
/// A screen space draw quad which resembles the edges of the playfield for skinning purposes.
|
||||
/// This will allow users / components to snap objects to the "edge" of the playfield.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Rulesets which reduce the visible area further than the full relative playfield space itself
|
||||
/// should retarget this to the ScreenSpaceDrawQuad of the appropriate container.
|
||||
/// </remarks>
|
||||
public virtual Quad SkinnableComponentScreenSpaceDrawQuad => ScreenSpaceDrawQuad;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
[CanBeNull]
|
||||
protected IReadOnlyList<Mod> Mods { get; private set; }
|
||||
|
@ -12,6 +12,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Configuration;
|
||||
@ -69,7 +70,9 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
public Bindable<bool> ShowHealthBar = new Bindable<bool>(true);
|
||||
|
||||
[CanBeNull]
|
||||
private readonly DrawableRuleset drawableRuleset;
|
||||
|
||||
private readonly IReadOnlyList<Mod> mods;
|
||||
|
||||
/// <summary>
|
||||
@ -103,10 +106,11 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private readonly List<Drawable> hideTargets;
|
||||
|
||||
public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods, bool alwaysShowLeaderboard = true)
|
||||
private readonly Drawable playfieldComponents;
|
||||
|
||||
public HUDOverlay([CanBeNull] DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods, bool alwaysShowLeaderboard = true)
|
||||
{
|
||||
Drawable rulesetComponents;
|
||||
|
||||
this.drawableRuleset = drawableRuleset;
|
||||
this.mods = mods;
|
||||
|
||||
@ -123,6 +127,9 @@ namespace osu.Game.Screens.Play
|
||||
rulesetComponents = drawableRuleset != null
|
||||
? new HUDComponentsContainer(drawableRuleset.Ruleset.RulesetInfo) { AlwaysPresent = true, }
|
||||
: Empty(),
|
||||
playfieldComponents = drawableRuleset != null
|
||||
? new SkinComponentsContainer(new SkinComponentsContainerLookup(SkinComponentsContainerLookup.TargetArea.Playfield, drawableRuleset.Ruleset.RulesetInfo)) { AlwaysPresent = true, }
|
||||
: Empty(),
|
||||
topRightElements = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
@ -162,7 +169,7 @@ namespace osu.Game.Screens.Play
|
||||
},
|
||||
};
|
||||
|
||||
hideTargets = new List<Drawable> { mainComponents, rulesetComponents, topRightElements };
|
||||
hideTargets = new List<Drawable> { mainComponents, rulesetComponents, playfieldComponents, topRightElements };
|
||||
|
||||
if (!alwaysShowLeaderboard)
|
||||
hideTargets.Add(LeaderboardFlow);
|
||||
@ -230,6 +237,16 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (drawableRuleset != null)
|
||||
{
|
||||
Quad playfieldScreenSpaceDrawQuad = drawableRuleset.Playfield.SkinnableComponentScreenSpaceDrawQuad;
|
||||
|
||||
playfieldComponents.Position = ToLocalSpace(playfieldScreenSpaceDrawQuad.TopLeft);
|
||||
playfieldComponents.Width = (ToLocalSpace(playfieldScreenSpaceDrawQuad.TopRight) - ToLocalSpace(playfieldScreenSpaceDrawQuad.TopLeft)).Length;
|
||||
playfieldComponents.Height = (ToLocalSpace(playfieldScreenSpaceDrawQuad.BottomLeft) - ToLocalSpace(playfieldScreenSpaceDrawQuad.TopLeft)).Length;
|
||||
playfieldComponents.Rotation = drawableRuleset.Playfield.Rotation;
|
||||
}
|
||||
|
||||
float? lowestTopScreenSpaceLeft = null;
|
||||
float? lowestTopScreenSpaceRight = null;
|
||||
|
||||
|
@ -68,7 +68,10 @@ namespace osu.Game.Skinning
|
||||
MainHUDComponents,
|
||||
|
||||
[Description("Song select")]
|
||||
SongSelect
|
||||
SongSelect,
|
||||
|
||||
[Description("Playfield")]
|
||||
Playfield
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user