mirror of
https://github.com/ppy/osu.git
synced 2025-02-26 04:43:01 +08:00
Merge branch 'master' into grid-momentary-shortcuts
This commit is contained in:
commit
f787da892b
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.LargeTickMiss);
|
assertTickJudgement(HitResult.LargeTickMiss);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
assertNoteJudgement(HitResult.IgnoreHit);
|
assertNoteJudgement(HitResult.IgnoreMiss);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -76,8 +76,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
performTest(objects, new List<ReplayFrame>());
|
performTest(objects, new List<ReplayFrame>());
|
||||||
|
|
||||||
addJudgementAssert(objects[0], HitResult.IgnoreHit);
|
addJudgementAssert(objects[0], HitResult.IgnoreMiss);
|
||||||
addJudgementAssert(objects[1], HitResult.IgnoreHit);
|
addJudgementAssert(objects[1], HitResult.IgnoreMiss);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -69,6 +69,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double? releaseTime;
|
private double? releaseTime;
|
||||||
|
|
||||||
|
public override double MaximumJudgementOffset => Tail.MaximumJudgementOffset;
|
||||||
|
|
||||||
public DrawableHoldNote()
|
public DrawableHoldNote()
|
||||||
: this(null)
|
: this(null)
|
||||||
{
|
{
|
||||||
@ -260,7 +262,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
tick.MissForcefully();
|
tick.MissForcefully();
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
ApplyResult(r => r.Type = Tail.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
endHold();
|
endHold();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,15 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
@ -52,6 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
};
|
};
|
||||||
|
|
||||||
private OsuDistanceSnapGrid grid;
|
private OsuDistanceSnapGrid grid;
|
||||||
|
private SnappingCursorContainer cursor;
|
||||||
|
|
||||||
public TestSceneOsuDistanceSnapGrid()
|
public TestSceneOsuDistanceSnapGrid()
|
||||||
{
|
{
|
||||||
@ -88,8 +92,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.SlateGray
|
Colour = Color4.SlateGray
|
||||||
},
|
},
|
||||||
|
cursor = new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position },
|
||||||
grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }),
|
grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }),
|
||||||
new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -154,6 +158,37 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
assertSnappedDistance(expectedDistance);
|
assertSnappedDistance(expectedDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestReferenceObjectNotOnSnapGrid()
|
||||||
|
{
|
||||||
|
AddStep("create grid", () =>
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.SlateGray
|
||||||
|
},
|
||||||
|
cursor = new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position },
|
||||||
|
grid = new OsuDistanceSnapGrid(new HitCircle
|
||||||
|
{
|
||||||
|
Position = grid_position,
|
||||||
|
// This is important. It sets the reference object to a point in time that isn't on the current snap divisor's grid.
|
||||||
|
// We are testing that the grid's display is offset correctly.
|
||||||
|
StartTime = 40,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("move mouse to point", () => InputManager.MoveMouseTo(grid.ToScreenSpace(grid_position + new Vector2(beat_length, 0) * 2)));
|
||||||
|
|
||||||
|
AddAssert("Ensure cursor is on a grid line", () =>
|
||||||
|
{
|
||||||
|
return grid.ChildrenOfType<CircularProgress>().Any(p => Precision.AlmostEquals(p.ScreenSpaceDrawQuad.TopRight.X, grid.ToScreenSpace(cursor.LastSnappedPosition).X));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLimitedDistance()
|
public void TestLimitedDistance()
|
||||||
{
|
{
|
||||||
@ -166,8 +201,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.SlateGray
|
Colour = Color4.SlateGray
|
||||||
},
|
},
|
||||||
|
cursor = new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position },
|
||||||
grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }, new HitCircle { StartTime = 200 }),
|
grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }, new HitCircle { StartTime = 200 }),
|
||||||
new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -186,6 +221,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
{
|
{
|
||||||
public Func<Vector2, Vector2> GetSnapPosition;
|
public Func<Vector2, Vector2> GetSnapPosition;
|
||||||
|
|
||||||
|
public Vector2 LastSnappedPosition { get; private set; }
|
||||||
|
|
||||||
private readonly Drawable cursor;
|
private readonly Drawable cursor;
|
||||||
|
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
@ -214,7 +251,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
cursor.Position = GetSnapPosition.Invoke(inputManager.CurrentState.Mouse.Position);
|
cursor.Position = LastSnappedPosition = GetSnapPosition.Invoke(inputManager.CurrentState.Mouse.Position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets.Taiko.Mods;
|
using osu.Game.Rulesets.Taiko.Mods;
|
||||||
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||||
{
|
{
|
||||||
@ -16,5 +20,37 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new TaikoModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true });
|
public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new TaikoModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true });
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFlashlightAlwaysHasNonZeroSize()
|
||||||
|
{
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new TestTaikoModFlashlight { ComboBasedSize = { Value = true } },
|
||||||
|
Autoplay = false,
|
||||||
|
PassCondition = () =>
|
||||||
|
{
|
||||||
|
failed |= this.ChildrenOfType<TestTaikoModFlashlight.TestTaikoFlashlight>().SingleOrDefault()?.FlashlightSize.Y == 0;
|
||||||
|
return !failed;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestTaikoModFlashlight : TaikoModFlashlight
|
||||||
|
{
|
||||||
|
protected override Flashlight CreateFlashlight() => new TestTaikoFlashlight(this, Playfield);
|
||||||
|
|
||||||
|
public class TestTaikoFlashlight : TaikoFlashlight
|
||||||
|
{
|
||||||
|
public TestTaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield)
|
||||||
|
: base(modFlashlight, taikoPlayfield)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public new Vector2 FlashlightSize => base.FlashlightSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,17 +27,17 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
|
|
||||||
public override float DefaultFlashlightSize => 200;
|
public override float DefaultFlashlightSize => 200;
|
||||||
|
|
||||||
protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield);
|
protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, Playfield);
|
||||||
|
|
||||||
private TaikoPlayfield playfield = null!;
|
protected TaikoPlayfield Playfield { get; private set; } = null!;
|
||||||
|
|
||||||
public override void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
public override void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
playfield = (TaikoPlayfield)drawableRuleset.Playfield;
|
Playfield = (TaikoPlayfield)drawableRuleset.Playfield;
|
||||||
base.ApplyToDrawableRuleset(drawableRuleset);
|
base.ApplyToDrawableRuleset(drawableRuleset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TaikoFlashlight : Flashlight
|
public class TaikoFlashlight : Flashlight
|
||||||
{
|
{
|
||||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo);
|
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo);
|
||||||
private readonly TaikoPlayfield taikoPlayfield;
|
private readonly TaikoPlayfield taikoPlayfield;
|
||||||
@ -47,21 +47,28 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
this.taikoPlayfield = taikoPlayfield;
|
this.taikoPlayfield = taikoPlayfield;
|
||||||
|
|
||||||
FlashlightSize = adjustSize(GetSize());
|
FlashlightSize = adjustSizeForPlayfieldAspectRatio(GetSize());
|
||||||
FlashlightSmoothness = 1.4f;
|
FlashlightSmoothness = 1.4f;
|
||||||
|
|
||||||
AddLayout(flashlightProperties);
|
AddLayout(flashlightProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 adjustSize(float size)
|
/// <summary>
|
||||||
|
/// Returns the aspect ratio-adjusted size of the flashlight.
|
||||||
|
/// This ensures that the size of the flashlight remains independent of taiko-specific aspect ratio adjustments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">
|
||||||
|
/// The size of the flashlight.
|
||||||
|
/// The value provided here should always come from <see cref="ModFlashlight{T}.Flashlight.GetSize"/>.
|
||||||
|
/// </param>
|
||||||
|
private Vector2 adjustSizeForPlayfieldAspectRatio(float size)
|
||||||
{
|
{
|
||||||
// Preserve flashlight size through the playfield's aspect adjustment.
|
|
||||||
return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateFlashlightSize(float size)
|
protected override void UpdateFlashlightSize(float size)
|
||||||
{
|
{
|
||||||
this.TransformTo(nameof(FlashlightSize), adjustSize(size), FLASHLIGHT_FADE_DURATION);
|
this.TransformTo(nameof(FlashlightSize), adjustSizeForPlayfieldAspectRatio(size), FLASHLIGHT_FADE_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string FragmentShader => "CircularFlashlight";
|
protected override string FragmentShader => "CircularFlashlight";
|
||||||
@ -75,7 +82,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre);
|
FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre);
|
||||||
|
|
||||||
ClearTransforms(targetMember: nameof(FlashlightSize));
|
ClearTransforms(targetMember: nameof(FlashlightSize));
|
||||||
FlashlightSize = adjustSize(Combo.Value);
|
FlashlightSize = adjustSizeForPlayfieldAspectRatio(GetSize());
|
||||||
|
|
||||||
flashlightProperties.Validate();
|
flashlightProperties.Validate();
|
||||||
}
|
}
|
||||||
|
@ -862,52 +862,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1);
|
AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRandomFallbackOnNonMatchingPrevious()
|
|
||||||
{
|
|
||||||
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
|
|
||||||
|
|
||||||
AddStep("populate maps", () =>
|
|
||||||
{
|
|
||||||
manySets.Clear();
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
manySets.Add(TestResources.CreateTestBeatmapSetInfo(3, new[]
|
|
||||||
{
|
|
||||||
// all taiko except for first
|
|
||||||
rulesets.GetRuleset(i > 0 ? 1 : 0)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
loadBeatmaps(manySets);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
AddStep("Reset filter", () => carousel.Filter(new FilterCriteria(), false));
|
|
||||||
|
|
||||||
AddStep("select first beatmap", () => carousel.SelectBeatmap(manySets.First().Beatmaps.First()));
|
|
||||||
|
|
||||||
AddStep("Toggle non-matching filter", () =>
|
|
||||||
{
|
|
||||||
carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAssert("selection lost", () => carousel.SelectedBeatmapInfo == null);
|
|
||||||
|
|
||||||
AddStep("Restore different ruleset filter", () =>
|
|
||||||
{
|
|
||||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false);
|
|
||||||
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID);
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo!.Equals(manySets.First().Beatmaps.First()));
|
|
||||||
}
|
|
||||||
|
|
||||||
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFilteringByUserStarDifficulty()
|
public void TestFilteringByUserStarDifficulty()
|
||||||
{
|
{
|
||||||
@ -955,6 +909,63 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
checkVisibleItemCount(true, 15);
|
checkVisibleItemCount(true, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCarouselSelectsNextWhenPreviousIsFiltered()
|
||||||
|
{
|
||||||
|
List<BeatmapSetInfo> sets = new List<BeatmapSetInfo>();
|
||||||
|
|
||||||
|
// 10 sets that go osu! -> taiko -> catch -> osu! -> ...
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3);
|
||||||
|
sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort mode is important to keep the ruleset order
|
||||||
|
loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title });
|
||||||
|
setSelected(1, 1);
|
||||||
|
|
||||||
|
for (int i = 1; i < 10; i++)
|
||||||
|
{
|
||||||
|
var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3);
|
||||||
|
AddStep($"Set ruleset to {rulesetInfo.ShortName}", () =>
|
||||||
|
{
|
||||||
|
carousel.Filter(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }, false);
|
||||||
|
});
|
||||||
|
waitForSelection(i + 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCarouselSelectsBackwardsWhenDistanceIsShorter()
|
||||||
|
{
|
||||||
|
List<BeatmapSetInfo> sets = new List<BeatmapSetInfo>();
|
||||||
|
|
||||||
|
// 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ...
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 4 == 0 ? 1 : 0);
|
||||||
|
sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort mode is important to keep the ruleset order
|
||||||
|
loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title });
|
||||||
|
|
||||||
|
for (int i = 2; i < 10; i += 4)
|
||||||
|
{
|
||||||
|
setSelected(i, 1);
|
||||||
|
AddStep("Set ruleset to taiko", () =>
|
||||||
|
{
|
||||||
|
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }, false);
|
||||||
|
});
|
||||||
|
waitForSelection(i - 1, 1);
|
||||||
|
AddStep("Remove ruleset filter", () =>
|
||||||
|
{
|
||||||
|
carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null, Func<FilterCriteria> initialCriteria = null, Action<BeatmapCarousel> carouselAdjust = null, int? count = null,
|
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null, Func<FilterCriteria> initialCriteria = null, Action<BeatmapCarousel> carouselAdjust = null, int? count = null,
|
||||||
bool randomDifficulties = false)
|
bool randomDifficulties = false)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +115,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
filterControl.Search(query);
|
filterControl.Search(query);
|
||||||
Show();
|
Show();
|
||||||
|
ScrollFlow.ScrollToStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader();
|
protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader();
|
||||||
|
@ -53,9 +53,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
float maxDistance = new Vector2(dx, dy).Length;
|
float maxDistance = new Vector2(dx, dy).Length;
|
||||||
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceBetweenTicks));
|
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceBetweenTicks));
|
||||||
|
|
||||||
|
// We need to offset the drawn lines to the next valid snap for the currently selected divisor.
|
||||||
|
//
|
||||||
|
// Picture the scenario where the user has just placed an object on a 1/2 snap, then changes to
|
||||||
|
// 1/3 snap and expects to be able to place the next object on a valid 1/3 snap, regardless of the
|
||||||
|
// fact that the 1/2 snap reference object is not valid for 1/3 snapping.
|
||||||
|
float offset = SnapProvider.FindSnappedDistance(ReferenceObject, 0);
|
||||||
|
|
||||||
for (int i = 0; i < requiredCircles; i++)
|
for (int i = 0; i < requiredCircles; i++)
|
||||||
{
|
{
|
||||||
float diameter = (i + 1) * DistanceBetweenTicks * 2;
|
float diameter = (offset + (i + 1) * DistanceBetweenTicks) * 2;
|
||||||
|
|
||||||
AddInternal(new Ring(ReferenceObject, GetColourForIndexFromPlacement(i))
|
AddInternal(new Ring(ReferenceObject, GetColourForIndexFromPlacement(i))
|
||||||
{
|
{
|
||||||
|
@ -1048,7 +1048,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected override void PerformSelection()
|
protected override void PerformSelection()
|
||||||
{
|
{
|
||||||
if (LastSelected == null || LastSelected.Filtered.Value)
|
if (LastSelected == null)
|
||||||
carousel?.SelectNextRandom();
|
carousel?.SelectNextRandom();
|
||||||
else
|
else
|
||||||
base.PerformSelection();
|
base.PerformSelection();
|
||||||
|
@ -108,10 +108,35 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
PerformSelection();
|
PerformSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the item this group would select next if it attempted selection
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An unfiltered item nearest to the last selected one or null if all items are filtered</returns>
|
||||||
protected virtual CarouselItem GetNextToSelect()
|
protected virtual CarouselItem GetNextToSelect()
|
||||||
{
|
{
|
||||||
return Items.Skip(lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value) ??
|
if (Items.Count == 0)
|
||||||
Items.Reverse().Skip(Items.Count - lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value);
|
return null;
|
||||||
|
|
||||||
|
int forwardsIndex = lastSelectedIndex;
|
||||||
|
int backwardsIndex = Math.Min(lastSelectedIndex, Items.Count - 1);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool hasBackwards = backwardsIndex >= 0 && backwardsIndex < Items.Count;
|
||||||
|
bool hasForwards = forwardsIndex < Items.Count;
|
||||||
|
|
||||||
|
if (!hasBackwards && !hasForwards)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (hasForwards && !Items[forwardsIndex].Filtered.Value)
|
||||||
|
return Items[forwardsIndex];
|
||||||
|
|
||||||
|
if (hasBackwards && !Items[backwardsIndex].Filtered.Value)
|
||||||
|
return Items[backwardsIndex];
|
||||||
|
|
||||||
|
forwardsIndex++;
|
||||||
|
backwardsIndex--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void PerformSelection()
|
protected virtual void PerformSelection()
|
||||||
|
Loading…
Reference in New Issue
Block a user