mirror of
https://github.com/osukey/osukey.git
synced 2025-07-02 08:49:59 +09:00
Merge pull request #13747 from ekrctb/catcher-flip
Don't flip catcher plate contents when catcher changes direction
This commit is contained in:
114
osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs
Normal file
114
osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using Direction = osu.Game.Rulesets.Catch.UI.Direction;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneCatchSkinConfiguration : OsuTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly DroppedObjectContainer droppedObjectContainer;
|
||||||
|
|
||||||
|
private Catcher catcher;
|
||||||
|
|
||||||
|
private readonly Container container;
|
||||||
|
|
||||||
|
public TestSceneCatchSkinConfiguration()
|
||||||
|
{
|
||||||
|
Add(droppedObjectContainer = new DroppedObjectContainer());
|
||||||
|
Add(container = new Container { RelativeSizeAxes = Axes.Both });
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestCatcherPlateFlipping(bool flip)
|
||||||
|
{
|
||||||
|
AddStep("setup catcher", () =>
|
||||||
|
{
|
||||||
|
var skin = new TestSkin { FlipCatcherPlate = flip };
|
||||||
|
container.Child = new SkinProvidingContainer(skin)
|
||||||
|
{
|
||||||
|
Child = catcher = new Catcher(new Container())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Fruit fruit = new Fruit();
|
||||||
|
|
||||||
|
AddStep("catch fruit", () => catchFruit(fruit, 20));
|
||||||
|
|
||||||
|
float position = 0;
|
||||||
|
|
||||||
|
AddStep("record fruit position", () => position = getCaughtObjectPosition(fruit));
|
||||||
|
|
||||||
|
AddStep("face left", () => catcher.VisualDirection = Direction.Left);
|
||||||
|
|
||||||
|
if (flip)
|
||||||
|
AddAssert("fruit position changed", () => !Precision.AlmostEquals(getCaughtObjectPosition(fruit), position));
|
||||||
|
else
|
||||||
|
AddAssert("fruit position unchanged", () => Precision.AlmostEquals(getCaughtObjectPosition(fruit), position));
|
||||||
|
|
||||||
|
AddStep("face right", () => catcher.VisualDirection = Direction.Right);
|
||||||
|
|
||||||
|
AddAssert("fruit position restored", () => Precision.AlmostEquals(getCaughtObjectPosition(fruit), position));
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getCaughtObjectPosition(Fruit fruit)
|
||||||
|
{
|
||||||
|
var caughtObject = catcher.ChildrenOfType<CaughtObject>().Single(c => c.HitObject == fruit);
|
||||||
|
return caughtObject.Parent.ToSpaceOfOtherDrawable(caughtObject.Position, catcher).X;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void catchFruit(Fruit fruit, float x)
|
||||||
|
{
|
||||||
|
fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
var drawableFruit = new DrawableFruit(fruit) { X = x };
|
||||||
|
var judgement = fruit.CreateJudgement();
|
||||||
|
catcher.OnNewResult(drawableFruit, new CatchJudgementResult(fruit, judgement)
|
||||||
|
{
|
||||||
|
Type = judgement.MaxResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestSkin : DefaultSkin
|
||||||
|
{
|
||||||
|
public bool FlipCatcherPlate { get; set; }
|
||||||
|
|
||||||
|
public TestSkin()
|
||||||
|
: base(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||||
|
{
|
||||||
|
if (lookup is CatchSkinConfiguration config)
|
||||||
|
{
|
||||||
|
if (config == CatchSkinConfiguration.FlipCatcherPlate)
|
||||||
|
return SkinUtils.As<TValue>(new Bindable<bool>(FlipCatcherPlate));
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetConfig<TLookup, TValue>(lookup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs
Normal file
13
osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning
|
||||||
|
{
|
||||||
|
public enum CatchSkinConfiguration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed.
|
||||||
|
/// </summary>
|
||||||
|
FlipCatcherPlate
|
||||||
|
}
|
||||||
|
}
|
@ -103,6 +103,19 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
result.Value = LegacyColourCompatibility.DisallowZeroAlpha(result.Value);
|
result.Value = LegacyColourCompatibility.DisallowZeroAlpha(result.Value);
|
||||||
return (IBindable<TValue>)result;
|
return (IBindable<TValue>)result;
|
||||||
|
|
||||||
|
case CatchSkinConfiguration config:
|
||||||
|
switch (config)
|
||||||
|
{
|
||||||
|
case CatchSkinConfiguration.FlipCatcherPlate:
|
||||||
|
// Don't flip catcher plate contents if the catcher is provided by this legacy skin.
|
||||||
|
if (GetDrawableComponent(new CatchSkinComponent(CatchSkinComponents.Catcher)) != null)
|
||||||
|
return (IBindable<TValue>)new Bindable<bool>();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetConfig<TLookup, TValue>(lookup);
|
return base.GetConfig<TLookup, TValue>(lookup);
|
||||||
|
@ -79,8 +79,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public CatcherAnimationState CurrentState
|
public CatcherAnimationState CurrentState
|
||||||
{
|
{
|
||||||
get => body.AnimationState.Value;
|
get => Body.AnimationState.Value;
|
||||||
private set => body.AnimationState.Value = value;
|
private set => Body.AnimationState.Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -103,18 +103,22 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction VisualDirection
|
/// <summary>
|
||||||
{
|
/// The currently facing direction.
|
||||||
get => Scale.X > 0 ? Direction.Right : Direction.Left;
|
/// </summary>
|
||||||
set => Scale = new Vector2((value == Direction.Right ? 1 : -1) * Math.Abs(Scale.X), Scale.Y);
|
public Direction VisualDirection { get; set; } = Direction.Right;
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed.
|
||||||
|
/// </summary>
|
||||||
|
private bool flipCatcherPlate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the area that can be used to attempt catches during gameplay.
|
/// Width of the area that can be used to attempt catches during gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly float catchWidth;
|
private readonly float catchWidth;
|
||||||
|
|
||||||
private readonly SkinnableCatcher body;
|
internal readonly SkinnableCatcher Body;
|
||||||
|
|
||||||
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
|
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||||
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
|
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||||
@ -155,7 +159,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
// offset fruit vertically to better place "above" the plate.
|
// offset fruit vertically to better place "above" the plate.
|
||||||
Y = -5
|
Y = -5
|
||||||
},
|
},
|
||||||
body = new SkinnableCatcher(),
|
Body = new SkinnableCatcher(),
|
||||||
hitExplosionContainer = new HitExplosionContainer
|
hitExplosionContainer = new HitExplosionContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
@ -344,6 +348,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
trails.HyperDashTrailsColour = hyperDashColour;
|
trails.HyperDashTrailsColour = hyperDashColour;
|
||||||
trails.EndGlowSpritesColour = hyperDashEndGlowColour;
|
trails.EndGlowSpritesColour = hyperDashEndGlowColour;
|
||||||
|
|
||||||
|
flipCatcherPlate = skin.GetConfig<CatchSkinConfiguration, bool>(CatchSkinConfiguration.FlipCatcherPlate)?.Value ?? true;
|
||||||
|
|
||||||
runHyperDashStateTransition(HyperDashing);
|
runHyperDashStateTransition(HyperDashing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +357,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
|
var scaleFromDirection = new Vector2((int)VisualDirection, 1);
|
||||||
|
Body.Scale = scaleFromDirection;
|
||||||
|
caughtObjectContainer.Scale = hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One;
|
||||||
|
|
||||||
// Correct overshooting.
|
// Correct overshooting.
|
||||||
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
|
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
|
||||||
(hyperDashDirection < 0 && hyperDashTargetPosition > X))
|
(hyperDashDirection < 0 && hyperDashTargetPosition > X))
|
||||||
@ -459,7 +469,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DroppedObjectAnimation.Explode:
|
case DroppedObjectAnimation.Explode:
|
||||||
var originalX = droppedObjectTarget.ToSpaceOfOtherDrawable(d.DrawPosition, caughtObjectContainer).X * Scale.X;
|
float originalX = droppedObjectTarget.ToSpaceOfOtherDrawable(d.DrawPosition, caughtObjectContainer).X * caughtObjectContainer.Scale.X;
|
||||||
d.MoveToY(d.Y - 50, 250, Easing.OutSine).Then().MoveToY(d.Y + 50, 500, Easing.InSine);
|
d.MoveToY(d.Y - 50, 250, Easing.OutSine).Then().MoveToY(d.Y + 50, 500, Easing.InSine);
|
||||||
d.MoveToX(d.X + originalX * 6, 1000);
|
d.MoveToX(d.X + originalX * 6, 1000);
|
||||||
d.FadeOut(750);
|
d.FadeOut(750);
|
||||||
|
@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
CatcherTrail sprite = trailPool.Get();
|
CatcherTrail sprite = trailPool.Get();
|
||||||
|
|
||||||
sprite.AnimationState = catcher.CurrentState;
|
sprite.AnimationState = catcher.CurrentState;
|
||||||
sprite.Scale = catcher.Scale;
|
sprite.Scale = catcher.Scale * catcher.Body.Scale;
|
||||||
sprite.Position = catcher.Position;
|
sprite.Position = catcher.Position;
|
||||||
|
|
||||||
target.Add(sprite);
|
target.Add(sprite);
|
||||||
|
Reference in New Issue
Block a user