diff --git a/osu-framework b/osu-framework index 60e210c1aa..cc614047de 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 60e210c1aa62a114fb08e50797f8f839da326cc3 +Subproject commit cc614047de3471a2d2b4b988fed550fc946016b9 diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index eed7e9369e..3f5fe58ab5 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -35,14 +35,8 @@ namespace osu.Game.Beatmaps.Drawables switch (state) { case BeatmapGroupState.Expanded: - //if (!difficulties.Children.All(d => IsLoaded)) - // Task.WhenAll(difficulties.Children.Select(d => d.Preload(Game))).ContinueWith(t => difficulties.Show()); - //else foreach (BeatmapPanel panel in BeatmapPanels) - { - panel.Hidden = false; panel.FadeIn(250); - } Header.State = PanelSelectedState.Selected; if (SelectedPanel != null) @@ -54,11 +48,7 @@ namespace osu.Game.Beatmaps.Drawables SelectedPanel.State = PanelSelectedState.NotSelected; foreach (BeatmapPanel panel in BeatmapPanels) - { - panel.Hidden = true; panel.FadeOut(250); - } - break; } } @@ -76,6 +66,7 @@ namespace osu.Game.Beatmaps.Drawables BeatmapPanels = beatmap.BeatmapSetInfo.Beatmaps.Select(b => new BeatmapPanel(b) { + Alpha = 0, GainedSelection = panelGainedSelection, RelativeSizeAxes = Axes.X, }).ToList(); diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index 6de25a853b..0062ddf0e1 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -2,11 +2,14 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.MathUtils; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -22,6 +25,8 @@ namespace osu.Game.Beatmaps.Drawables public Action GainedSelection; + Color4 deselectedColour = new Color4(20, 43, 51, 255); + protected override void Selected() { base.Selected(); @@ -36,7 +41,7 @@ namespace osu.Game.Beatmaps.Drawables { base.Deselected(); - background.Colour = new Color4(20, 43, 51, 255); + background.Colour = deselectedColour; } public BeatmapPanel(BeatmapInfo beatmap) @@ -44,12 +49,18 @@ namespace osu.Game.Beatmaps.Drawables Beatmap = beatmap; Height *= 0.60f; - Children = new Framework.Graphics.Drawable[] + Children = new Drawable[] { background = new Box { RelativeSizeAxes = Axes.Both, }, + new Triangles + { + RelativeSizeAxes = Axes.Both, + BlendingMode = BlendingMode.Additive, + Colour = deselectedColour, + }, new FlowContainer { Padding = new MarginPadding(5), @@ -57,7 +68,7 @@ namespace osu.Game.Beatmaps.Drawables AutoSizeAxes = Axes.Both, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Children = new Framework.Graphics.Drawable[] + Children = new Drawable[] { new DifficultyIcon(FontAwesome.fa_dot_circle_o, new Color4(159, 198, 0, 255)) { @@ -71,7 +82,7 @@ namespace osu.Game.Beatmaps.Drawables Spacing = new Vector2(0, 5), Direction = FlowDirection.VerticalOnly, AutoSizeAxes = Axes.Both, - Children = new Framework.Graphics.Drawable[] + Children = new Drawable[] { new FlowContainer { @@ -113,5 +124,45 @@ namespace osu.Game.Beatmaps.Drawables } }; } + + public class Triangles : Container + { + private Texture triangle; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + triangle = textures.Get(@"Play/osu/triangle@2x"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + for (int i = 0; i < 10; i++) + { + Add(new Sprite + { + Texture = triangle, + Origin = Anchor.TopCentre, + RelativePositionAxes = Axes.Both, + Position = new Vector2(RNG.NextSingle(), RNG.NextSingle()), + Scale = new Vector2(RNG.NextSingle() * 0.4f + 0.2f), + Alpha = RNG.NextSingle() * 0.3f + }); + } + } + + protected override void Update() + { + base.Update(); + + foreach (Drawable d in Children) + { + d.Position -= new Vector2(0, (float)(d.Scale.X * (Time.Elapsed / 880))); + if (d.DrawPosition.Y + d.DrawSize.Y * d.Scale.Y < 0) + d.MoveToY(1); + } + } + } } } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 9ab9aaf9f5..bd36ad5149 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -27,7 +27,6 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapSetHeader(WorkingBeatmap beatmap) { this.beatmap = beatmap; - Hidden = false; Children = new Drawable[] { @@ -72,6 +71,12 @@ namespace osu.Game.Beatmaps.Drawables }; } + protected override void LoadComplete() + { + base.LoadComplete(); + FadeInFromZero(250); + } + protected override void Selected() { base.Selected(); diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index cef25d24a5..f97a5260d8 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.cs @@ -4,6 +4,7 @@ using osu.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Transformations; using osu.Framework.Input; using OpenTK; using OpenTK.Graphics; @@ -14,7 +15,12 @@ namespace osu.Game.Beatmaps.Drawables { public const float MAX_HEIGHT = 80; - public bool Hidden = true; + public override bool RemoveWhenNotAlive => false; + + public bool IsOnScreen; + + public override bool IsAlive => IsOnScreen && base.IsAlive; + private Container nestedContainer; protected override Container Content => nestedContainer; @@ -42,7 +48,6 @@ namespace osu.Game.Beatmaps.Drawables { base.LoadComplete(); applyState(); - FadeInFromZero(250); } private void applyState() diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index c6ed202326..7e87194cf4 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -16,10 +16,27 @@ namespace osu.Game.Screens.Select { class BeatmapInfoWedge : Container { + private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); + private Container beatmapInfoContainer; private BaseGame game; + public BeatmapInfoWedge() + { + Shear = wedged_container_shear; + Masking = true; + BorderColour = new Color4(221, 255, 255, 255); + BorderThickness = 2.5f; + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Colour = new Color4(130, 204, 255, 150), + Radius = 20, + Roundness = 15, + }; + } + [BackgroundDependencyLoader] private void load(BaseGame game) { @@ -35,8 +52,6 @@ namespace osu.Game.Screens.Select float newDepth = lastContainer?.Depth - 1 ?? 0; - FadeIn(250); - BeatmapSetInfo beatmapSetInfo = beatmap.BeatmapSetInfo; BeatmapInfo beatmapInfo = beatmap.BeatmapInfo; @@ -126,6 +141,8 @@ namespace osu.Game.Screens.Select } }).Preload(game, delegate(Drawable d) { + FadeIn(250); + lastContainer?.FadeOut(250); lastContainer?.Expire(); diff --git a/osu.Game/Screens/Select/CarouselContainer.cs b/osu.Game/Screens/Select/CarouselContainer.cs index cfc36b9caa..9ff950cc06 100644 --- a/osu.Game/Screens/Select/CarouselContainer.cs +++ b/osu.Game/Screens/Select/CarouselContainer.cs @@ -10,39 +10,85 @@ using osu.Game.Database; using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Lists; using osu.Game.Beatmaps.Drawables; - +using osu.Framework.Timing; + namespace osu.Game.Screens.Select { class CarouselContainer : ScrollContainer { private Container scrollableContent; private List groups = new List(); - private List panels = new List(); public BeatmapGroup SelectedGroup { get; private set; } public BeatmapPanel SelectedPanel { get; private set; } - - private List yPositions = new List(); - - public CarouselContainer() - { - DistanceDecayJump = 0.01; - Add(scrollableContent = new Container + private List yPositions = new List(); + private CarouselLifetimeList Lifetime; + + public CarouselContainer() + { + DistanceDecayJump = 0.01; + + Add(scrollableContent = new Container(Lifetime = new CarouselLifetimeList(DepthComparer)) + { + RelativeSizeAxes = Axes.X, + }); + } + + internal class CarouselLifetimeList : LifetimeList + { + public CarouselLifetimeList(IComparer comparer) + : base(comparer) + { + } + + public int StartIndex; + public int EndIndex; + + public override bool Update(FrameTimeInfo time) { - RelativeSizeAxes = Axes.X, - }); - } + bool anyAliveChanged = false; + //check existing items to make sure they haven't died. + foreach (var item in AliveItems.ToArray()) + { + item.UpdateTime(time); + if (!item.IsAlive) + { + //todo: make this more efficient + int i = IndexOf(item); + anyAliveChanged |= CheckItem(item, ref i); + } + } + + //handle custom range + for (int i = StartIndex; i < EndIndex; i++) + { + var item = this[i]; + item.UpdateTime(time); + anyAliveChanged |= CheckItem(item, ref i); + } + + return anyAliveChanged; + } + } + public void AddGroup(BeatmapGroup group) { group.State = BeatmapGroupState.Collapsed; - groups.Add(group); - panels.Add(group.Header); + + group.Header.Depth = scrollableContent.Children.Count(); + scrollableContent.Add(group.Header); + foreach (BeatmapPanel panel in group.BeatmapPanels) - panels.Add(panel); + { + panel.Depth = scrollableContent.Children.Count(); + scrollableContent.Add(panel); + } computeYPositions(); } @@ -74,6 +120,7 @@ namespace osu.Game.Screens.Select if (group.State == BeatmapGroupState.Expanded) { group.Header.MoveToX(-100, 500, EasingTypes.OutExpo); + var headerY = group.Header.Position.Y; foreach (BeatmapPanel panel in group.BeatmapPanels) { @@ -82,6 +129,10 @@ namespace osu.Game.Screens.Select panel.MoveToX(-50, 500, EasingTypes.OutExpo); + //on first display we want to begin hidden under our group's header. + if (panel.Alpha == 0) + panel.MoveToY(headerY); + movePanel(panel, true, ref currentY); } } @@ -119,11 +170,7 @@ namespace osu.Game.Screens.Select public void SelectGroup(BeatmapGroup group, BeatmapPanel panel) { if (SelectedGroup != null && SelectedGroup != group) - { SelectedGroup.State = BeatmapGroupState.Collapsed; - foreach (BeatmapPanel p in group.BeatmapPanels) - p.MoveToY(group.Header.Position.Y); - } SelectedGroup = group; panel.State = PanelSelectedState.Selected; @@ -133,7 +180,7 @@ namespace osu.Game.Screens.Select ScrollTo(selectedY); } - private static float offsetX(Panel panel, float dist, float halfHeight) + private static float offsetX(float dist, float halfHeight) { // The radius of the circle the carousel moves on. const float CIRCLE_RADIUS = 4; @@ -143,28 +190,16 @@ namespace osu.Game.Screens.Select return 125 + x; } - private void addPanel(int index) - { - Panel panel = panels[index]; - if (panel.Hidden) - return; - - if (!scrollableContent.Contains(panel)) - { - panel.Depth = index + (panel is BeatmapSetHeader ? panels.Count : 0); - scrollableContent.Add(panel); - } - } - protected override void Update() { base.Update(); float drawHeight = DrawHeight; - scrollableContent.RemoveAll(delegate (Panel p) + + Lifetime.AliveItems.ForEach(delegate (Panel p) { float panelPosY = p.Position.Y; - return panelPosY < Current - p.DrawHeight || panelPosY > Current + drawHeight || !IsVisible; + p.IsOnScreen = panelPosY >= Current - p.DrawHeight && panelPosY <= Current + drawHeight; }); int firstIndex = yPositions.BinarySearch(Current - Panel.MAX_HEIGHT); @@ -172,19 +207,24 @@ namespace osu.Game.Screens.Select int lastIndex = yPositions.BinarySearch(Current + drawHeight); if (lastIndex < 0) lastIndex = ~lastIndex; - for (int i = firstIndex; i < lastIndex; ++i) - addPanel(i); + Lifetime.StartIndex = firstIndex; + Lifetime.EndIndex = lastIndex; float halfHeight = drawHeight / 2; - foreach (Panel panel in scrollableContent.Children) + + for (int i = firstIndex; i < lastIndex; ++i) { + var panel = Lifetime[i]; + + panel.IsOnScreen = true; + float panelDrawY = panel.Position.Y - Current + panel.DrawHeight / 2; float dist = Math.Abs(1f - panelDrawY / halfHeight); // Setting the origin position serves as an additive position on top of potential // local transformation we may want to apply (e.g. when a panel gets selected, we // may want to smoothly transform it leftwards.) - panel.OriginPosition = new Vector2(-offsetX(panel, dist, halfHeight), 0); + panel.OriginPosition = new Vector2(-offsetX(dist, halfHeight), 0); // We are applying a multiplicative alpha (which is internally done by nesting an // additional container and setting that container's alpha) such that we can diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 371d014659..8c8ff39fba 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -38,7 +38,6 @@ namespace osu.Game.Screens.Select private TrackManager trackManager; private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 225); - private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); private static readonly Vector2 wedged_container_start_position = new Vector2(0, 50); private BeatmapInfoWedge beatmapInfoWedge; @@ -105,18 +104,7 @@ namespace osu.Game.Screens.Select Position = wedged_container_start_position, Size = wedged_container_size, RelativeSizeAxes = Axes.X, - Shear = wedged_container_shear, Margin = new MarginPadding { Top = 20, Right = 20, }, - Masking = true, - BorderColour = new Color4(221, 255, 255, 255), - BorderThickness = 2.5f, - EdgeEffect = new EdgeEffect - { - Type = EdgeEffectType.Glow, - Colour = new Color4(130, 204, 255, 150), - Radius = 20, - Roundness = 15, - }, }, new Container {