1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 17:35:10 +08:00

Merge pull request #25364 from frenzibyte/fix-resume-cursor-following-settings

Fix resume cursor following gameplay cursor scale setting
This commit is contained in:
Dean Herbert 2023-11-07 21:57:00 +09:00 committed by GitHub
commit 34219c1103
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 151 additions and 96 deletions

View File

@ -94,16 +94,16 @@ namespace osu.Game.Rulesets.Osu.Tests
AddStep("load content", loadContent);
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize) * userScale);
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.CursorScale.Value == OsuCursor.GetScaleForCircleSize(circleSize) * userScale);
AddStep("set user scale to 1", () => config.SetValue(OsuSetting.GameplayCursorSize, 1f));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.CursorScale.Value == OsuCursor.GetScaleForCircleSize(circleSize));
AddStep("turn off autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, false));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == 1);
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.CursorScale.Value == 1);
AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, userScale));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == userScale);
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.CursorScale.Value == userScale);
}
[Test]

View File

@ -1,38 +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 System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Screens.Play;
using osu.Game.Tests.Gameplay;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public partial class TestSceneResumeOverlay : OsuManualInputManagerTestScene
{
private ManualOsuInputManager osuInputManager = null!;
private CursorContainer cursor = null!;
private ResumeOverlay resume = null!;
private bool resumeFired;
private OsuConfigManager localConfig = null!;
[Cached]
private GameplayState gameplayState;
public TestSceneResumeOverlay()
{
ManualOsuInputManager osuInputManager;
CursorContainer cursor;
ResumeOverlay resume;
gameplayState = TestGameplayState.Create(new OsuRuleset());
}
bool resumeFired = false;
[BackgroundDependencyLoader]
private void load()
{
Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage));
}
Child = osuInputManager = new ManualOsuInputManager(new OsuRuleset().RulesetInfo)
protected override void LoadComplete()
{
base.LoadComplete();
AddSliderStep("cursor size", 0.1f, 2f, 1f, v => localConfig.SetValue(OsuSetting.GameplayCursorSize, v));
AddSliderStep("circle size", 0f, 10f, 0f, val =>
{
Children = new Drawable[]
{
cursor = new CursorContainer(),
resume = new OsuResumeOverlay
{
GameplayCursor = cursor
},
}
};
gameplayState.Beatmap.Difficulty.CircleSize = val;
SetUp();
});
resume.ResumeAction = () => resumeFired = true;
AddToggleStep("auto size", v => localConfig.SetValue(OsuSetting.AutoCursorSize, v));
}
[SetUp]
public void SetUp() => Schedule(loadContent);
[TestCase(1)]
[TestCase(0.5f)]
[TestCase(2)]
public void TestResume(float cursorSize)
{
AddStep($"set cursor size to {cursorSize}", () => localConfig.SetValue(OsuSetting.GameplayCursorSize, cursorSize));
AddStep("move mouse to center", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
AddStep("show", () => resume.Show());
@ -41,11 +72,39 @@ namespace osu.Game.Rulesets.Osu.Tests
AddStep("click", () => osuInputManager.GameClick());
AddAssert("not dismissed", () => !resumeFired && resume.State.Value == Visibility.Visible);
AddStep("move mouse back", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
AddStep("move mouse just out of range", () =>
{
var resumeOverlay = this.ChildrenOfType<OsuResumeOverlay>().Single();
var resumeOverlayCursor = resumeOverlay.ChildrenOfType<OsuResumeOverlay.OsuClickToResumeCursor>().Single();
Vector2 offset = resumeOverlay.ToScreenSpace(new Vector2(OsuCursor.SIZE / 2)) - resumeOverlay.ToScreenSpace(Vector2.Zero);
InputManager.MoveMouseTo(resumeOverlayCursor.ScreenSpaceDrawQuad.Centre - offset - new Vector2(1));
});
AddStep("click", () => osuInputManager.GameClick());
AddAssert("not dismissed", () => !resumeFired && resume.State.Value == Visibility.Visible);
AddStep("move mouse just within range", () =>
{
var resumeOverlay = this.ChildrenOfType<OsuResumeOverlay>().Single();
var resumeOverlayCursor = resumeOverlay.ChildrenOfType<OsuResumeOverlay.OsuClickToResumeCursor>().Single();
Vector2 offset = resumeOverlay.ToScreenSpace(new Vector2(OsuCursor.SIZE / 2)) - resumeOverlay.ToScreenSpace(Vector2.Zero);
InputManager.MoveMouseTo(resumeOverlayCursor.ScreenSpaceDrawQuad.Centre - offset + new Vector2(1));
});
AddStep("click", () => osuInputManager.GameClick());
AddAssert("dismissed", () => resumeFired && resume.State.Value == Visibility.Hidden);
}
private void loadContent()
{
Child = osuInputManager = new ManualOsuInputManager(new OsuRuleset().RulesetInfo) { Children = new Drawable[] { cursor = new CursorContainer(), resume = new OsuResumeOverlay { GameplayCursor = cursor }, } };
resumeFired = false;
resume.ResumeAction = () => resumeFired = true;
}
private partial class ManualOsuInputManager : OsuInputManager
{
public ManualOsuInputManager(RulesetInfo ruleset)

View File

@ -4,12 +4,16 @@
#nullable disable
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.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
@ -18,30 +22,42 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{
public partial class OsuCursor : SkinReloadableDrawable
{
private const float size = 28;
public const float SIZE = 28;
private const float pressed_scale = 1.2f;
private const float released_scale = 1f;
private bool cursorExpand;
private SkinnableDrawable cursorSprite;
private Container cursorScaleContainer = null!;
private Drawable expandTarget => (cursorSprite.Drawable as OsuCursorSprite)?.ExpandTarget ?? cursorSprite;
public IBindable<float> CursorScale => cursorScale;
private readonly Bindable<float> cursorScale = new BindableFloat(1);
private Bindable<float> userCursorScale = null!;
private Bindable<bool> autoCursorScale = null!;
[Resolved(canBeNull: true)]
private GameplayState state { get; set; }
[Resolved]
private OsuConfigManager config { get; set; }
public OsuCursor()
{
Origin = Anchor.Centre;
Size = new Vector2(size);
}
protected override void SkinChanged(ISkinSource skin)
{
cursorExpand = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.CursorExpand)?.Value ?? true;
Size = new Vector2(SIZE);
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = new Container
InternalChild = cursorScaleContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
@ -52,10 +68,39 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
Anchor = Anchor.Centre,
}
};
userCursorScale = config.GetBindable<float>(OsuSetting.GameplayCursorSize);
userCursorScale.ValueChanged += _ => calculateCursorScale();
autoCursorScale = config.GetBindable<bool>(OsuSetting.AutoCursorSize);
autoCursorScale.ValueChanged += _ => calculateCursorScale();
cursorScale.BindValueChanged(e => cursorScaleContainer.Scale = new Vector2(e.NewValue), true);
}
private const float pressed_scale = 1.2f;
private const float released_scale = 1f;
protected override void LoadComplete()
{
base.LoadComplete();
calculateCursorScale();
}
private void calculateCursorScale()
{
float scale = userCursorScale.Value;
if (autoCursorScale.Value && state != null)
{
// if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier.
scale *= GetScaleForCircleSize(state.Beatmap.Difficulty.CircleSize);
}
cursorScale.Value = scale;
}
protected override void SkinChanged(ISkinSource skin)
{
cursorExpand = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.CursorExpand)?.Value ?? true;
}
public void Expand()
{
@ -66,6 +111,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public void Contract() => expandTarget.ScaleTo(released_scale, 400, Easing.OutQuad);
/// <summary>
/// Get the scale applicable to the ActiveCursor based on a beatmap's circle size.
/// </summary>
public static float GetScaleForCircleSize(float circleSize) =>
1f - 0.7f * (1f + circleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY;
private partial class DefaultCursor : OsuCursorSprite
{
public DefaultCursor()
@ -83,7 +134,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = size / 6,
BorderThickness = SIZE / 6,
BorderColour = Color4.White,
EdgeEffect = new EdgeEffectParameters
{
@ -105,7 +156,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = size / 3,
BorderThickness = SIZE / 3,
BorderColour = Color4.White.Opacity(0.5f),
Children = new Drawable[]
{

View File

@ -11,11 +11,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.Configuration;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osuTK;
@ -23,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{
public partial class OsuCursorContainer : GameplayCursorContainer, IKeyBindingHandler<OsuAction>
{
public new OsuCursor ActiveCursor => (OsuCursor)base.ActiveCursor;
protected override Drawable CreateCursor() => new OsuCursor();
protected override Container<Drawable> Content => fadeContainer;
@ -33,13 +32,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly Drawable cursorTrail;
public IBindable<float> CursorScale => cursorScale;
private readonly Bindable<float> cursorScale = new BindableFloat(1);
private Bindable<float> userCursorScale;
private Bindable<bool> autoCursorScale;
private readonly CursorRippleVisualiser rippleVisualiser;
public OsuCursorContainer()
@ -56,12 +48,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
};
}
[Resolved(canBeNull: true)]
private GameplayState state { get; set; }
[Resolved]
private OsuConfigManager config { get; set; }
[BackgroundDependencyLoader(true)]
private void load(OsuRulesetConfigManager rulesetConfig)
{
@ -74,46 +60,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true);
userCursorScale = config.GetBindable<float>(OsuSetting.GameplayCursorSize);
userCursorScale.ValueChanged += _ => calculateScale();
autoCursorScale = config.GetBindable<bool>(OsuSetting.AutoCursorSize);
autoCursorScale.ValueChanged += _ => calculateScale();
CursorScale.BindValueChanged(e =>
ActiveCursor.CursorScale.BindValueChanged(e =>
{
var newScale = new Vector2(e.NewValue);
ActiveCursor.Scale = newScale;
rippleVisualiser.CursorScale = newScale;
cursorTrail.Scale = newScale;
}, true);
calculateScale();
}
/// <summary>
/// Get the scale applicable to the ActiveCursor based on a beatmap's circle size.
/// </summary>
public static float GetScaleForCircleSize(float circleSize) =>
1f - 0.7f * (1f + circleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY;
private void calculateScale()
{
float scale = userCursorScale.Value;
if (autoCursorScale.Value && state != null)
{
// if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier.
scale *= GetScaleForCircleSize(state.Beatmap.Difficulty.CircleSize);
}
cursorScale.Value = scale;
var newScale = new Vector2(scale);
ActiveCursor.ScaleTo(newScale, 400, Easing.OutQuint);
cursorTrail.Scale = newScale;
}
private int downCount;
@ -121,9 +74,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private void updateExpandedState()
{
if (downCount > 0)
(ActiveCursor as OsuCursor)?.Expand();
ActiveCursor.Expand();
else
(ActiveCursor as OsuCursor)?.Contract();
ActiveCursor.Contract();
}
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
@ -160,13 +113,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
protected override void PopIn()
{
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
ActiveCursor.ScaleTo(CursorScale.Value, 400, Easing.OutQuint);
ActiveCursor.ScaleTo(1f, 400, Easing.OutQuint);
}
protected override void PopOut()
{
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
ActiveCursor.ScaleTo(CursorScale.Value * 0.8f, 450, Easing.OutQuint);
ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
}
private partial class DefaultCursorTrail : CursorTrail

View File

@ -5,7 +5,6 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@ -14,7 +13,6 @@ using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Screens.Play;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.UI
@ -25,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.UI
private OsuClickToResumeCursor clickToResumeCursor;
private OsuCursorContainer localCursorContainer;
private IBindable<float> localCursorScale;
public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null;
@ -49,13 +46,7 @@ namespace osu.Game.Rulesets.Osu.UI
clickToResumeCursor.Appear();
if (localCursorContainer == null)
{
Add(localCursorContainer = new OsuCursorContainer());
localCursorScale = new BindableFloat();
localCursorScale.BindTo(localCursorContainer.CursorScale);
localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true);
}
}
protected override void PopOut()
@ -98,7 +89,8 @@ namespace osu.Game.Rulesets.Osu.UI
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
if (!IsHovered) return false;
if (!IsHovered)
return false;
this.ScaleTo(2, TRANSITION_TIME, Easing.OutQuint);