From 99b428ee4b853033abfac1e0ee08a57c185d7a91 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Apr 2021 18:03:49 +0900 Subject: [PATCH] Add very basic skin editor test --- .../Visual/Gameplay/TestSceneSkinEditor.cs | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs new file mode 100644 index 0000000000..2391945b91 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -0,0 +1,222 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; +using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinEditor : OsuTestScene + { + private HUDOverlay hudOverlay; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create hud", () => + { + hudOverlay = new HUDOverlay(null, null, null, Array.Empty()); + + // Add any key just to display the key counter visually. + hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); + + hudOverlay.ComboCounter.Current.Value = 1; + }); + + AddStep("create editor overlay", () => Add(new SkinEditor(hudOverlay))); + } + + public class SkinEditor : CompositeDrawable + { + private readonly Drawable target; + + public SkinEditor(Drawable target) + { + this.target = target; + + RelativeSizeAxes = Axes.Both; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + InternalChildren = new[] + { + target, + new SkinBlueprintContainer(target), + }; + } + + public class SkinBlueprintContainer : BlueprintContainer + { + private readonly Drawable target; + + public SkinBlueprintContainer(Drawable target) + { + this.target = target; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + SkinnableHUDComponent[] components = target.ChildrenOfType().ToArray(); + + foreach (var c in components) + { + Logger.Log($"Adding blueprint for {c.GetType()}"); + AddBlueprintFor(c); + } + } + + protected override SelectionHandler CreateSelectionHandler() => new SkinSelectionHandler(); + + public class SkinSelectionHandler : SelectionHandler + { + protected override void DeleteItems(IEnumerable items) + { + foreach (var i in items) + i.Drawable.Expire(); + } + + protected override void OnSelectionChanged() + { + base.OnSelectionChanged(); + + SelectionBox.CanRotate = true; + SelectionBox.CanScaleX = true; + SelectionBox.CanScaleY = true; + SelectionBox.CanReverse = false; + } + + public override bool HandleRotation(float angle) + { + foreach (var c in SelectedBlueprints) + c.Item.Rotation += angle; + + return base.HandleRotation(angle); + } + + public override bool HandleScale(Vector2 scale, Anchor anchor) + { + adjustScaleFromAnchor(ref scale, anchor); + + foreach (var c in SelectedBlueprints) + c.Item.Scale += scale * 0.01f; + + return true; + } + + private static void adjustScaleFromAnchor(ref Vector2 scale, Anchor reference) + { + // cancel out scale in axes we don't care about (based on which drag handle was used). + if ((reference & Anchor.x1) > 0) scale.X = 0; + if ((reference & Anchor.y1) > 0) scale.Y = 0; + + // reverse the scale direction if dragging from top or left. + if ((reference & Anchor.x0) > 0) scale.X = -scale.X; + if ((reference & Anchor.y0) > 0) scale.Y = -scale.Y; + } + + public override bool HandleMovement(MoveSelectionEvent moveEvent) + { + foreach (var c in SelectedBlueprints) + c.Item.Position += moveEvent.InstantDelta; + return true; + } + } + + protected override SelectionBlueprint CreateBlueprintFor(SkinnableHUDComponent component) + => new SkinBlueprint(component); + + public class SkinBlueprint : SelectionBlueprint + { + /// + /// The which this applies to. + /// + public readonly SkinnableHUDComponent Component; + + private Container box; + private Drawable drawable => Component.Drawable; + + /// + /// Whether the blueprint should be shown even when the is not alive. + /// + protected virtual bool AlwaysShowWhenSelected => false; + + protected override bool ShouldBeAlive => (Component.IsAlive && Component.IsPresent) || (AlwaysShowWhenSelected && State == SelectionState.Selected); + + public SkinBlueprint(SkinnableHUDComponent component) + : base(component) + { + Component = component; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + InternalChildren = new Drawable[] + { + box = new Container + { + Colour = colours.Yellow, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.2f, + AlwaysPresent = true, + }, + } + }, + }; + } + + private Quad drawableQuad; + + public override Quad ScreenSpaceDrawQuad => drawableQuad; + + protected override void Update() + { + base.Update(); + + drawableQuad = drawable.ScreenSpaceDrawQuad; + var quad = ToLocalSpace(drawable.ScreenSpaceDrawQuad); + + box.Position = quad.TopLeft; + box.Size = quad.Size; + box.Rotation = Component.Rotation; + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => drawable.ReceivePositionalInputAt(screenSpacePos); + + public override Vector2 ScreenSpaceSelectionPoint => Component.ToScreenSpace(Vector2.Zero); + + public override Quad SelectionQuad => drawable.ScreenSpaceDrawQuad; + + public override Vector2 GetInstantDelta(Vector2 screenSpacePosition) => Component.Parent.ToLocalSpace(screenSpacePosition) - Component.Position; + } + } + } + } +}