1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-20 05:47:50 +08:00

Fix osu! gameplay cursor not adjusting to mod/convert circle size changes

This commit is contained in:
Dean Herbert 2020-02-14 12:30:11 +09:00
parent 7fdc8cc7c1
commit 884a5fbad4
4 changed files with 128 additions and 15 deletions

View File

@ -7,7 +7,9 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Testing.Input;
using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Screens.Play;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
@ -21,12 +23,50 @@ namespace osu.Game.Rulesets.Osu.Tests
typeof(CursorTrail)
};
[BackgroundDependencyLoader]
private void load()
[Cached]
private GameplayBeatmap gameplayBeatmap;
private ClickingCursorContainer lastContainer;
[Resolved]
private OsuConfigManager config { get; set; }
public TestSceneGameplayCursor()
{
gameplayBeatmap = new GameplayBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo));
}
[TestCase(1, 1)]
[TestCase(5, 1)]
[TestCase(10, 1)]
[TestCase(1, 1.5f)]
[TestCase(5, 1.5f)]
[TestCase(10, 1.5f)]
public void TestSizing(int circleSize, float userScale)
{
AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale));
AddStep($"adjust cs to {circleSize}", () => gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSize);
AddStep("turn on autosizing", () => config.Set(OsuSetting.AutoCursorSize, true));
AddStep("load content", loadContent);
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize) * userScale);
AddStep("set user scale to 1", () => config.Set(OsuSetting.GameplayCursorSize, 1f));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize));
AddStep("turn off autosizing", () => config.Set(OsuSetting.AutoCursorSize, false));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == 1);
AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == userScale);
}
private void loadContent()
{
SetContents(() => new MovingCursorInputManager
{
Child = new ClickingCursorContainer
Child = lastContainer = new ClickingCursorContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,

View File

@ -12,6 +12,7 @@ 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;
@ -32,7 +33,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public Bindable<float> CursorScale;
private Bindable<float> userCursorScale;
private Bindable<bool> autoCursorScale;
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
public OsuCursorContainer()
{
@ -43,13 +43,21 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
};
}
[Resolved(canBeNull: true)]
private GameplayBeatmap beatmap { get; set; }
[Resolved]
private OsuConfigManager config { get; set; }
[BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig, IBindable<WorkingBeatmap> beatmap)
private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig)
{
rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);
}
this.beatmap.BindTo(beatmap);
this.beatmap.ValueChanged += _ => calculateScale();
protected override void LoadComplete()
{
showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true);
userCursorScale = config.GetBindable<float>(OsuSetting.GameplayCursorSize);
userCursorScale.ValueChanged += _ => calculateScale();
@ -58,29 +66,41 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
autoCursorScale.ValueChanged += _ => calculateScale();
CursorScale = new BindableFloat();
CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue);
CursorScale.ValueChanged += e =>
{
var newScale = new Vector2(e.NewValue);
ActiveCursor.Scale = newScale;
cursorTrail.Scale = newScale;
};
calculateScale();
base.LoadComplete();
}
/// <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 && beatmap.Value != null)
if (autoCursorScale.Value && beatmap != null)
{
// if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier.
scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY;
scale *= GetScaleForCircleSize(beatmap.BeatmapInfo.BaseDifficulty.CircleSize);
}
CursorScale.Value = scale;
}
protected override void LoadComplete()
{
base.LoadComplete();
var newScale = new Vector2(scale);
showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true);
ActiveCursor.ScaleTo(newScale, 400, Easing.OutQuint);
cursorTrail.Scale = newScale;
}
private int downCount;

View File

@ -0,0 +1,42 @@
// 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.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Screens.Play
{
public class GameplayBeatmap : Component, IBeatmap
{
public readonly IBeatmap PlayableBeatmap;
public GameplayBeatmap(IBeatmap playableBeatmap)
{
PlayableBeatmap = playableBeatmap;
}
public BeatmapInfo BeatmapInfo
{
get => PlayableBeatmap.BeatmapInfo;
set => PlayableBeatmap.BeatmapInfo = value;
}
public BeatmapMetadata Metadata => PlayableBeatmap.Metadata;
public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo;
public List<BreakPeriod> Breaks => PlayableBeatmap.Breaks;
public double TotalBreakTime => PlayableBeatmap.TotalBreakTime;
public IReadOnlyList<HitObject> HitObjects => PlayableBeatmap.HitObjects;
public IEnumerable<BeatmapStatistic> GetStatistics() => PlayableBeatmap.GetStatistics();
public IBeatmap Clone() => PlayableBeatmap.Clone();
}
}

View File

@ -110,6 +110,13 @@ namespace osu.Game.Screens.Play
this.showResults = showResults;
}
private GameplayBeatmap gameplayBeatmap;
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
[BackgroundDependencyLoader]
private void load(AudioManager audio, IAPIProvider api, OsuConfigManager config)
{
@ -143,6 +150,10 @@ namespace osu.Game.Screens.Play
InternalChild = GameplayClockContainer = new GameplayClockContainer(Beatmap.Value, Mods.Value, DrawableRuleset.GameplayStartTime);
AddInternal(gameplayBeatmap = new GameplayBeatmap(playableBeatmap));
dependencies.CacheAs(gameplayBeatmap);
addUnderlayComponents(GameplayClockContainer);
addGameplayComponents(GameplayClockContainer, Beatmap.Value);
addOverlayComponents(GameplayClockContainer, Beatmap.Value);