// 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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] public class TestCaseScrollingHitObjects : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(Playfield) }; [Cached(typeof(IReadOnlyList))] private IReadOnlyList mods { get; set; } = Array.Empty(); private readonly ScrollingTestContainer[] scrollContainers = new ScrollingTestContainer[4]; private readonly TestPlayfield[] playfields = new TestPlayfield[4]; public TestCaseScrollingHitObjects() { Add(new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { new Drawable[] { scrollContainers[0] = new ScrollingTestContainer(ScrollingDirection.Up) { RelativeSizeAxes = Axes.Both, Child = playfields[0] = new TestPlayfield() }, scrollContainers[1] = new ScrollingTestContainer(ScrollingDirection.Up) { RelativeSizeAxes = Axes.Both, Child = playfields[1] = new TestPlayfield() }, }, new Drawable[] { scrollContainers[2] = new ScrollingTestContainer(ScrollingDirection.Up) { RelativeSizeAxes = Axes.Both, Child = playfields[2] = new TestPlayfield() }, scrollContainers[3] = new ScrollingTestContainer(ScrollingDirection.Up) { RelativeSizeAxes = Axes.Both, Child = playfields[3] = new TestPlayfield() } } } }); AddStep("Constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant)); AddStep("Overlapping scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Overlapping)); AddStep("Sequential scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Sequential)); AddSliderStep("Time range", 100, 10000, 5000, v => scrollContainers.ForEach(c => c.TimeRange = v)); AddStep("Add control point", () => addControlPoint(Time.Current + 5000)); } protected override void LoadComplete() { base.LoadComplete(); scrollContainers.ForEach(c => c.ControlPoints.Add(new MultiplierControlPoint(0))); for (int i = 0; i <= 5000; i += 1000) addHitObject(Time.Current + i); Scheduler.AddDelayed(() => addHitObject(Time.Current + 5000), 1000, true); } private void addHitObject(double time) { playfields.ForEach(p => { var hitObject = new TestDrawableHitObject(time); setAnchor(hitObject, p); p.Add(hitObject); }); } private void addControlPoint(double time) { scrollContainers.ForEach(c => { c.ControlPoints.Add(new MultiplierControlPoint(time) { DifficultyPoint = { SpeedMultiplier = 3 } }); c.ControlPoints.Add(new MultiplierControlPoint(time + 2000) { DifficultyPoint = { SpeedMultiplier = 2 } }); c.ControlPoints.Add(new MultiplierControlPoint(time + 3000) { DifficultyPoint = { SpeedMultiplier = 1 } }); }); playfields.ForEach(p => { TestDrawableControlPoint createDrawablePoint(double t) { var obj = new TestDrawableControlPoint(p.Direction, t); setAnchor(obj, p); return obj; } p.Add(createDrawablePoint(time)); p.Add(createDrawablePoint(time + 2000)); p.Add(createDrawablePoint(time + 3000)); }); } private void setAnchor(DrawableHitObject obj, TestPlayfield playfield) { switch (playfield.Direction) { case ScrollingDirection.Up: obj.Anchor = Anchor.TopCentre; break; case ScrollingDirection.Down: obj.Anchor = Anchor.BottomCentre; break; case ScrollingDirection.Left: obj.Anchor = Anchor.CentreLeft; break; case ScrollingDirection.Right: obj.Anchor = Anchor.CentreRight; break; } } private void setScrollAlgorithm(ScrollVisualisationMethod algorithm) => scrollContainers.ForEach(c => c.ScrollAlgorithm = algorithm); private class TestPlayfield : ScrollingPlayfield { public new ScrollingDirection Direction => base.Direction.Value; public TestPlayfield() { Padding = new MarginPadding(2); InternalChildren = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Alpha = 0.5f, }, new Container { RelativeSizeAxes = Axes.Both, Masking = true, Child = HitObjectContainer } }; } } private class TestDrawableControlPoint : DrawableHitObject { public TestDrawableControlPoint(ScrollingDirection direction, double time) : base(new HitObject { StartTime = time }) { Origin = Anchor.Centre; AddInternal(new Box { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both }); switch (direction) { case ScrollingDirection.Up: case ScrollingDirection.Down: RelativeSizeAxes = Axes.X; Height = 2; break; case ScrollingDirection.Left: case ScrollingDirection.Right: RelativeSizeAxes = Axes.Y; Width = 2; break; } } protected override void UpdateState(ArmedState state) { } } private class TestDrawableHitObject : DrawableHitObject { public TestDrawableHitObject(double time) : base(new HitObject { StartTime = time }) { Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; AddInternal(new Box { Size = new Vector2(75) }); } protected override void UpdateState(ArmedState state) { } } } }