1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 16:47:24 +08:00

Merge branch 'master' into overlay-headers-update-three

This commit is contained in:
Dean Herbert 2019-12-30 13:42:23 +09:00 committed by GitHub
commit 9d5d61a64d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 184 additions and 75 deletions

View File

@ -22,10 +22,57 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly Drawable hitTarget;
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
{
InternalChildren = new[]
{
hitTarget = new DefaultHitTarget
{
RelativeSizeAxes = Axes.X,
},
hitObjectContainer
};
}
[BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo)
{
direction.BindTo(scrollingInfo.Direction);
direction.BindValueChanged(dir =>
{
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
hitTarget.Anchor = hitTarget.Origin = anchor;
}, true);
}
private Color4 accentColour;
public Color4 AccentColour
{
get => accentColour;
set
{
if (accentColour == value)
return;
accentColour = value;
if (hitTarget is IHasAccentColour colouredHitTarget)
colouredHitTarget.AccentColour = accentColour;
}
}
private class DefaultHitTarget : CompositeDrawable, IHasAccentColour
{
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly Container hitTargetLine;
private readonly Drawable hitTargetBar;
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
public DefaultHitTarget()
{
InternalChildren = new[]
{
@ -43,7 +90,6 @@ namespace osu.Game.Rulesets.Mania.UI.Components
Masking = true,
Child = new Box { RelativeSizeAxes = Axes.Both }
},
hitObjectContainer
};
}
@ -96,3 +142,4 @@ namespace osu.Game.Rulesets.Mania.UI.Components
}
}
}
}

View File

@ -3,12 +3,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
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.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
@ -28,12 +30,16 @@ namespace osu.Game.Tests.Visual.Gameplay
[Cached(typeof(IReadOnlyList<Mod>))]
private IReadOnlyList<Mod> mods { get; set; } = Array.Empty<Mod>();
private const int spawn_interval = 5000;
private readonly ScrollingTestContainer[] scrollContainers = new ScrollingTestContainer[4];
private readonly TestPlayfield[] playfields = new TestPlayfield[4];
private ScheduledDelegate hitObjectSpawnDelegate;
public TestSceneScrollingHitObjects()
[SetUp]
public void Setup() => Schedule(() =>
{
Add(new GridContainer
Child = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
@ -43,48 +49,66 @@ namespace osu.Game.Tests.Visual.Gameplay
scrollContainers[0] = new ScrollingTestContainer(ScrollingDirection.Up)
{
RelativeSizeAxes = Axes.Both,
Child = playfields[0] = new TestPlayfield()
Child = playfields[0] = new TestPlayfield(),
TimeRange = spawn_interval
},
scrollContainers[1] = new ScrollingTestContainer(ScrollingDirection.Up)
scrollContainers[1] = new ScrollingTestContainer(ScrollingDirection.Down)
{
RelativeSizeAxes = Axes.Both,
Child = playfields[1] = new TestPlayfield()
Child = playfields[1] = new TestPlayfield(),
TimeRange = spawn_interval
},
},
new Drawable[]
{
scrollContainers[2] = new ScrollingTestContainer(ScrollingDirection.Up)
scrollContainers[2] = new ScrollingTestContainer(ScrollingDirection.Left)
{
RelativeSizeAxes = Axes.Both,
Child = playfields[2] = new TestPlayfield()
Child = playfields[2] = new TestPlayfield(),
TimeRange = spawn_interval
},
scrollContainers[3] = new ScrollingTestContainer(ScrollingDirection.Up)
scrollContainers[3] = new ScrollingTestContainer(ScrollingDirection.Right)
{
RelativeSizeAxes = Axes.Both,
Child = playfields[3] = new TestPlayfield()
Child = playfields[3] = new TestPlayfield(),
TimeRange = spawn_interval
}
}
}
};
setUpHitObjects();
});
private void setUpHitObjects()
{
scrollContainers.ForEach(c => c.ControlPoints.Add(new MultiplierControlPoint(0)));
for (int i = 0; i <= spawn_interval; i += 1000)
addHitObject(Time.Current + i);
hitObjectSpawnDelegate?.Cancel();
hitObjectSpawnDelegate = Scheduler.AddDelayed(() => addHitObject(Time.Current + spawn_interval), 1000, true);
}
[Test]
public void TestScrollAlgorithms()
{
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));
AddSliderStep("Time range", 100, 10000, spawn_interval, v => scrollContainers.Where(c => c != null).ForEach(c => c.TimeRange = v));
AddStep("Add control point", () => addControlPoint(Time.Current + spawn_interval));
}
protected override void LoadComplete()
[Test]
public void TestScrollLifetime()
{
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);
AddStep("Set constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant));
// scroll container time range must be less than the rate of spawning hitobjects
// otherwise the hitobjects will spawn already partly visible on screen and look wrong
AddStep("Set time range", () => scrollContainers.ForEach(c => c.TimeRange = spawn_interval / 2.0));
}
private void addHitObject(double time)
@ -207,7 +231,9 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestDrawableHitObject(double time)
: base(new HitObject { StartTime = time })
{
Origin = Anchor.Centre;
Origin = Anchor.Custom;
OriginPosition = new Vector2(75 / 4.0f);
AutoSizeAxes = Axes.Both;
AddInternal(new Box { Size = new Vector2(75) });

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -9,21 +10,25 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Direct
{
public abstract class DirectPanel : Container
public abstract class DirectPanel : OsuClickableContainer, IHasContextMenu
{
public readonly BeatmapSetInfo SetInfo;
@ -32,8 +37,6 @@ namespace osu.Game.Overlays.Direct
private Container content;
private BeatmapSetOverlay beatmapSetOverlay;
public PreviewTrack Preview => PlayButton.Preview;
public Bindable<bool> PreviewPlaying => PlayButton?.Playing;
@ -44,6 +47,8 @@ namespace osu.Game.Overlays.Direct
protected override Container<Drawable> Content => content;
protected Action ViewBeatmap;
protected DirectPanel(BeatmapSetInfo setInfo)
{
Debug.Assert(setInfo.OnlineBeatmapSetID != null);
@ -70,8 +75,6 @@ namespace osu.Game.Overlays.Direct
[BackgroundDependencyLoader(permitNulls: true)]
private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay)
{
this.beatmapSetOverlay = beatmapSetOverlay;
AddInternal(content = new Container
{
RelativeSizeAxes = Axes.Both,
@ -88,6 +91,12 @@ namespace osu.Game.Overlays.Direct
},
}
});
Action = ViewBeatmap = () =>
{
Debug.Assert(SetInfo.OnlineBeatmapSetID != null);
beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value);
};
}
protected override void Update()
@ -120,13 +129,6 @@ namespace osu.Game.Overlays.Direct
base.OnHoverLost(e);
}
protected override bool OnClick(ClickEvent e)
{
Debug.Assert(SetInfo.OnlineBeatmapSetID != null);
beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value);
return true;
}
protected override void LoadComplete()
{
base.LoadComplete();
@ -203,5 +205,10 @@ namespace osu.Game.Overlays.Direct
Value = value;
}
}
public MenuItem[] ContextMenuItems => new MenuItem[]
{
new OsuMenuItem("View Beatmap", MenuItemType.Highlighted, ViewBeatmap),
};
}
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
namespace osu.Game.Overlays.SearchableList
{
@ -61,15 +62,15 @@ namespace osu.Game.Overlays.SearchableList
scrollContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new[]
Child = new OsuContextMenuContainer
{
new OsuScrollContainer
RelativeSizeAxes = Axes.Both,
Masking = true,
Child = new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
Children = new[]
{
ScrollFlow = new FillFlowContainer
Child = ScrollFlow = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
@ -79,7 +80,6 @@ namespace osu.Game.Overlays.SearchableList
},
},
},
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,

View File

@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
private void computeLifetimeStartRecursive(DrawableHitObject hitObject)
{
hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value);
hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject);
foreach (var obj in hitObject.NestedHitObjects)
computeLifetimeStartRecursive(obj);
@ -108,6 +108,35 @@ namespace osu.Game.Rulesets.UI.Scrolling
private readonly Dictionary<DrawableHitObject, Cached> hitObjectInitialStateCache = new Dictionary<DrawableHitObject, Cached>();
private double computeOriginAdjustedLifetimeStart(DrawableHitObject hitObject)
{
float originAdjustment = 0.0f;
// calculate the dimension of the part of the hitobject that should already be visible
// when the hitobject origin first appears inside the scrolling container
switch (direction.Value)
{
case ScrollingDirection.Up:
originAdjustment = hitObject.OriginPosition.Y;
break;
case ScrollingDirection.Down:
originAdjustment = hitObject.DrawHeight - hitObject.OriginPosition.Y;
break;
case ScrollingDirection.Left:
originAdjustment = hitObject.OriginPosition.X;
break;
case ScrollingDirection.Right:
originAdjustment = hitObject.DrawWidth - hitObject.OriginPosition.X;
break;
}
var adjustedStartTime = scrollingInfo.Algorithm.TimeAt(-originAdjustment, hitObject.HitObject.StartTime, timeRange.Value, scrollLength);
return scrollingInfo.Algorithm.GetDisplayStartTime(adjustedStartTime, timeRange.Value);
}
// Cant use AddOnce() since the delegate is re-constructed every invocation
private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() =>
{