diff --git a/osu-framework b/osu-framework index 80bcb82ef8..6594729122 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 80bcb82ef8d2e1af1ce077f4a037b6d279ad9e74 +Subproject commit 65947291229541de3eb1aff0e703f6968b07f976 diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index e7a33d930e..f601ce624d 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps if (beatmap.ComboColors.Count == 0) return; - int comboIndex = 0; + int index = 0; int colourIndex = 0; CatchHitObject lastObj = null; @@ -31,12 +31,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps if (obj.NewCombo) { if (lastObj != null) lastObj.LastInCombo = true; - - comboIndex = 0; colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count; } - obj.ComboIndex = comboIndex++; + obj.IndexInBeatmap = index++; obj.ComboColour = beatmap.ComboColors[colourIndex]; lastObj = obj; diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 35410a7a77..37525470c2 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Catch public override int LegacyID => 2; - public CatchRuleset(RulesetInfo rulesetInfo) + public CatchRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { } diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 109f8401c5..559bf47842 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -15,8 +15,11 @@ namespace osu.Game.Rulesets.Catch.Objects public float X { get; set; } - public Color4 ComboColour { get; set; } = Color4.Gray; - public int ComboIndex { get; set; } + public Color4 ComboColour { get; set; } + + public int IndexInBeatmap { get; set; } + + public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4); public virtual bool NewCombo { get; set; } @@ -44,4 +47,13 @@ namespace osu.Game.Rulesets.Catch.Objects Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; } } + + public enum FruitVisualRepresentation + { + Pear, + Grape, + Raspberry, + Pineapple, + Banana // banananananannaanana + } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs index 31af779943..289323c1b5 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs @@ -14,9 +14,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable : base(h) { Origin = Anchor.Centre; - - Size = new Vector2(Pulp.PULP_SIZE); - + Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4; AccentColour = h.ComboColour; Masking = false; } @@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable Child = new Pulp { AccentColour = AccentColour, - Scale = new Vector2(0.8f), + Size = Size }; } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs index 2c327c9261..c2c59468e9 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs @@ -1,9 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.MathUtils; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using OpenTK; @@ -13,12 +16,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { public class DrawableFruit : DrawableCatchHitObject { + private Circle border; + public DrawableFruit(Fruit h) : base(h) { Origin = Anchor.Centre; - Size = new Vector2(Pulp.PULP_SIZE * 2.2f, Pulp.PULP_SIZE * 2.8f); + Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS); AccentColour = HitObject.ComboColour; Masking = false; @@ -28,48 +33,34 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable [BackgroundDependencyLoader] private void load() { - Children = new Framework.Graphics.Drawable[] + Children = new[] { - //todo: share this more - new BufferedContainer + createPulp(HitObject.VisualRepresentation), + border = new Circle { - RelativeSizeAxes = Axes.Both, - CacheDrawnFrameBuffer = true, + EdgeEffect = new EdgeEffectParameters + { + Hollow = !HitObject.HyperDash, + Type = EdgeEffectType.Glow, + Radius = 4, + Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f) + }, + Size = new Vector2(Height * 1.5f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BorderColour = Color4.White, + BorderThickness = 4f, Children = new Framework.Graphics.Drawable[] { - new Pulp + new Box { - RelativePositionAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AccentColour = AccentColour, - Scale = new Vector2(0.6f), - }, - new Pulp - { - RelativePositionAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AccentColour = AccentColour, - Y = -0.08f - }, - new Pulp - { - RelativePositionAxes = Axes.Both, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AccentColour = AccentColour, - Y = -0.08f - }, - new Pulp - { - RelativePositionAxes = Axes.Both, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - AccentColour = AccentColour, - }, + AlwaysPresent = true, + Colour = AccentColour, + Alpha = 0, + RelativeSizeAxes = Axes.Both + } } - } + }, }; if (HitObject.HyperDash) @@ -82,9 +73,184 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable AccentColour = Color4.Red, Blending = BlendingMode.Additive, Alpha = 0.5f, - Scale = new Vector2(2) + Scale = new Vector2(1.333f) }); } } + + private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation) + { + const float large_pulp_3 = 13f; + const float distance_from_centre_3 = 0.23f; + + const float large_pulp_4 = large_pulp_3 * 0.925f; + const float distance_from_centre_4 = distance_from_centre_3 / 0.925f; + + const float small_pulp = large_pulp_3 / 2; + + Vector2 positionAt(float angle, float distance) => new Vector2( + distance * (float)Math.Sin(angle * Math.PI / 180), + distance * (float)Math.Cos(angle * Math.PI / 180)); + + switch (representation) + { + default: + return new Container(); + case FruitVisualRepresentation.Raspberry: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + AccentColour = AccentColour, + Size = new Vector2(small_pulp), + Y = 0.05f, + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_4), + Position = positionAt(0, distance_from_centre_4), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_4), + Position = positionAt(90, distance_from_centre_4), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_4), + Position = positionAt(180, distance_from_centre_4), + }, + new Pulp + { + Size = new Vector2(large_pulp_4), + AccentColour = AccentColour, + Position = positionAt(270, distance_from_centre_4), + }, + } + }; + case FruitVisualRepresentation.Pineapple: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + AccentColour = AccentColour, + Size = new Vector2(small_pulp), + Y = 0.1f, + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_4), + Position = positionAt(45, distance_from_centre_4), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_4), + Position = positionAt(135, distance_from_centre_4), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_4), + Position = positionAt(225, distance_from_centre_4), + }, + new Pulp + { + Size = new Vector2(large_pulp_4), + AccentColour = AccentColour, + Position = positionAt(315, distance_from_centre_4), + }, + } + }; + case FruitVisualRepresentation.Pear: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AccentColour = AccentColour, + Size = new Vector2(small_pulp), + Y = -0.1f, + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_3), + Position = positionAt(60, distance_from_centre_3), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_3), + Position = positionAt(180, distance_from_centre_3), + }, + new Pulp + { + Size = new Vector2(large_pulp_3), + AccentColour = AccentColour, + Position = positionAt(300, distance_from_centre_3), + }, + } + }; + case FruitVisualRepresentation.Grape: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AccentColour = AccentColour, + Size = new Vector2(small_pulp), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_3), + Position = positionAt(0, distance_from_centre_3), + }, + new Pulp + { + AccentColour = AccentColour, + Size = new Vector2(large_pulp_3), + Position = positionAt(120, distance_from_centre_3), + }, + new Pulp + { + Size = new Vector2(large_pulp_3), + AccentColour = AccentColour, + Position = positionAt(240, distance_from_centre_3), + }, + } + }; + } + } + + protected override void Update() + { + base.Update(); + + border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1); + } } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs index 87d2ab6eee..80520ea846 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs @@ -6,18 +6,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using OpenTK; using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces { public class Pulp : Circle, IHasAccentColour { - public const float PULP_SIZE = (float)CatchHitObject.OBJECT_RADIUS / 2.2f; - public Pulp() { - Size = new Vector2(PULP_SIZE); + RelativePositionAxes = Axes.Both; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; Blending = BlendingMode.Additive; Colour = Color4.White.Opacity(0.9f); @@ -34,8 +33,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Radius = 5, - Colour = accentColour.Lighten(100), + Radius = 8, + Colour = accentColour.Darken(0.2f).Opacity(0.75f) }; } } diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs index cadf5b36b0..dbd5e5b36c 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests [Ignore("getting CI working")] public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer { - public TestCaseCatchPlayer() : base(typeof(CatchRuleset)) + public TestCaseCatchPlayer() : base(new CatchRuleset()) { } } diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs index fca07408b3..b9fa38f74e 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Catch.Tests public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer { public TestCaseCatchStacker() - : base(typeof(CatchRuleset)) + : base(new CatchRuleset()) { } diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs new file mode 100644 index 0000000000..d406231cc9 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs @@ -0,0 +1,104 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.MathUtils; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.Objects.Drawable; +using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; +using osu.Game.Tests.Visual; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Tests +{ + [Ignore("getting CI working")] + public class TestCaseFruitObjects : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(CatchHitObject), + typeof(Fruit), + typeof(Droplet), + typeof(DrawableCatchHitObject), + typeof(DrawableFruit), + typeof(DrawableDroplet), + typeof(Pulp), + }; + + public TestCaseFruitObjects() + { + Add(new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + createDrawable(0), + createDrawable(1), + createDrawable(2), + }, + new Drawable[] + { + createDrawable(3), + createDrawable(4), + createDrawable(5), + }, + } + }); + } + + private DrawableFruit createDrawable(int index) + { + var fruit = new Fruit + { + StartTime = 1000000000000, + IndexInBeatmap = index, + Scale = 1.5f, + }; + + fruit.ComboColour = colourForRrepesentation(fruit.VisualRepresentation); + + return new DrawableFruit(fruit) + { + Anchor = Anchor.Centre, + RelativePositionAxes = Axes.Both, + Position = Vector2.Zero, + Alpha = 1, + LifetimeStart = double.NegativeInfinity, + LifetimeEnd = double.PositiveInfinity, + }; + } + + private Color4 colourForRrepesentation(FruitVisualRepresentation representation) + { + switch (representation) + { + default: + case FruitVisualRepresentation.Pear: + return new Color4(17, 136, 170, 255); + case FruitVisualRepresentation.Grape: + return new Color4(204, 102, 0, 255); + case FruitVisualRepresentation.Raspberry: + return new Color4(121, 9, 13, 255); + case FruitVisualRepresentation.Pineapple: + return new Color4(102, 136, 0, 255); + case FruitVisualRepresentation.Banana: + switch (RNG.Next(0, 3)) + { + default: + return new Color4(255, 240, 0, 255); + case 1: + return new Color4(255, 192, 0, 255); + case 2: + return new Color4(214, 221, 28, 255); + } + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs index fd8309c2dc..59659b3d0d 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Catch.Tests public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer { public TestCaseHyperdash() - : base(typeof(CatchRuleset)) + : base(new CatchRuleset()) { } diff --git a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs index 0c66d8d80a..725eb5cf76 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() - : base(new CatchRuleset(new RulesetInfo())) + : base(new CatchRuleset()) { } } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 0737d1dc0c..dbc1e55f68 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -3,7 +3,6 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.UI; -using OpenTK; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; @@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.UI private readonly CatcherArea catcherArea; public CatchPlayfield(BeatmapDifficulty difficulty) - : base(Axes.Y) + : base(Axes.Y, BASE_WIDTH) { Container explodingFruitContainer; @@ -32,7 +31,10 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.TopCentre; Origin = Anchor.TopCentre; - InternalChildren = new Drawable[] + ScaledContent.Anchor = Anchor.BottomLeft; + ScaledContent.Origin = Anchor.BottomLeft; + + ScaledContent.AddRange(new Drawable[] { content = new Container { @@ -48,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, } - }; + }); } public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj); @@ -63,18 +65,6 @@ namespace osu.Game.Rulesets.Catch.UI fruit.CheckPosition = CheckIfWeCanCatch; } - public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) - { - if (judgement.IsHit) - { - Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre; - - // todo: don't do this - (judgedObject.Parent as Container)?.Remove(judgedObject); - (judgedObject.Parent as Container)?.Remove(judgedObject); - - catcherArea.Add(judgedObject, screenPosition); - } - } + public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) => catcherArea.OnJudgement((DrawableCatchHitObject)judgedObject, judgement); } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 99799415cf..e02849d0f5 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -12,6 +12,8 @@ using osu.Framework.Input.Bindings; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.Objects.Drawable; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; using OpenTK.Graphics; @@ -39,17 +41,34 @@ namespace osu.Game.Rulesets.Catch.UI }; } - public void Add(DrawableHitObject fruit, Vector2 absolutePosition) + public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement) { - fruit.RelativePositionAxes = Axes.None; - fruit.Position = new Vector2(MovableCatcher.ToLocalSpace(absolutePosition).X - MovableCatcher.DrawSize.X / 2, 0); + if (judgement.IsHit) + { + var screenSpacePosition = fruit.ScreenSpaceDrawQuad.Centre; - fruit.Anchor = Anchor.TopCentre; - fruit.Origin = Anchor.BottomCentre; - fruit.Scale *= 0.7f; - fruit.LifetimeEnd = double.MaxValue; + // todo: make this less ugly, somehow. + (fruit.Parent as Container)?.Remove(fruit); + (fruit.Parent as Container)?.Remove(fruit); - MovableCatcher.Add(fruit); + fruit.RelativePositionAxes = Axes.None; + fruit.Position = new Vector2(MovableCatcher.ToLocalSpace(screenSpacePosition).X - MovableCatcher.DrawSize.X / 2, 0); + + fruit.Anchor = Anchor.TopCentre; + fruit.Origin = Anchor.Centre; + fruit.Scale *= 0.7f; + fruit.LifetimeEnd = double.MaxValue; + + MovableCatcher.Add(fruit); + } + + if (fruit.HitObject.LastInCombo) + { + if (judgement.IsHit) + MovableCatcher.Explode(); + else + MovableCatcher.Drop(); + } } public bool AttemptCatch(CatchHitObject obj) => MovableCatcher.AttemptCatch(obj); @@ -84,12 +103,12 @@ namespace osu.Game.Rulesets.Catch.UI Children = new Drawable[] { - createCatcherSprite(), caughtFruit = new Container { Anchor = Anchor.TopCentre, Origin = Anchor.BottomCentre, - } + }, + createCatcherSprite(), }; } @@ -167,20 +186,23 @@ namespace osu.Game.Rulesets.Catch.UI /// The fruit that was caught. public void Add(DrawableHitObject fruit) { - float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; + float ourRadius = fruit.DrawSize.X / 2 * fruit.Scale.X; + float theirRadius = 0; - while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance)) + const float allowance = 6; + + while (caughtFruit.Any(f => + f.LifetimeEnd == double.MaxValue && + Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2))) { - fruit.X += RNG.Next(-5, 5); - fruit.Y -= RNG.Next(0, 5); + float diff = (ourRadius + theirRadius) / allowance; + fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff; + fruit.Y -= RNG.NextSingle() * diff; } + fruit.X = MathHelper.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2); + caughtFruit.Add(fruit); - - var catchObject = (CatchHitObject)fruit.HitObject; - - if (catchObject.LastInCombo) - explode(); } /// @@ -190,15 +212,15 @@ namespace osu.Game.Rulesets.Catch.UI /// Whether the catch is possible. public bool AttemptCatch(CatchHitObject fruit) { - const double relative_catcher_width = CATCHER_SIZE / 2; + double halfCatcherWidth = CATCHER_SIZE * Math.Abs(Scale.X) * 0.5f; // this stuff wil disappear once we move fruit to non-relative coordinate space in the future. var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH; var catcherPosition = Position.X * CatchPlayfield.BASE_WIDTH; var validCatch = - catchObjectPosition >= catcherPosition - relative_catcher_width / 2 && - catchObjectPosition <= catcherPosition + relative_catcher_width / 2; + catchObjectPosition >= catcherPosition - halfCatcherWidth && + catchObjectPosition <= catcherPosition + halfCatcherWidth; if (validCatch && fruit.HyperDash) { @@ -309,7 +331,35 @@ namespace osu.Game.Rulesets.Catch.UI X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); } - private void explode() + /// + /// Drop any fruit off the plate. + /// + public void Drop() + { + var fruit = caughtFruit.ToArray(); + + foreach (var f in fruit) + { + if (ExplodingFruitTarget != null) + { + f.Anchor = Anchor.TopLeft; + f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); + + caughtFruit.Remove(f); + + ExplodingFruitTarget.Add(f); + } + + f.MoveToY(f.Y + 75, 750, Easing.InSine); + f.FadeOut(750); + f.Expire(); + } + } + + /// + /// Explode any fruit off the plate. + /// + public void Explode() { var fruit = caughtFruit.ToArray(); diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index 6c42c4341f..566ec385fc 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -75,6 +75,7 @@ + diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 95708e4d11..b553879ef3 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Mania public override int LegacyID => 3; - public ManiaRuleset(RulesetInfo rulesetInfo) + public ManiaRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { } diff --git a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs index f611ae6f43..c76816db6a 100644 --- a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Tests public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() - : base(new ManiaRuleset(new RulesetInfo())) + : base(new ManiaRuleset()) { } } diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs index 03d44c31aa..4d03695186 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count; } - obj.ComboIndex = comboIndex++; + obj.IndexInCurrentCombo = comboIndex++; obj.ComboColour = beatmap.ComboColors[colourIndex]; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 143d54a0b6..61cf98e6cc 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables }, number = new NumberPiece { - Text = (HitObject.ComboIndex + 1).ToString(), + Text = (HitObject.IndexInCurrentCombo + 1).ToString(), }, ring = new RingPiece(), flash = new FlashPiece(), diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 9eaf1c80f8..bac513e0bb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { StartTime = s.StartTime, Position = s.StackedPosition, - ComboIndex = s.ComboIndex, + IndexInCurrentCombo = s.IndexInCurrentCombo, Scale = s.Scale, ComboColour = s.ComboColour, Samples = s.Samples, diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index a9c7effe53..40218fdfd8 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects public Color4 ComboColour { get; set; } = Color4.Gray; public virtual bool NewCombo { get; set; } - public int ComboIndex { get; set; } + public int IndexInCurrentCombo { get; set; } public double HitWindowFor(HitResult result) { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 1ba32f474d..b38f95694f 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Osu public override int LegacyID => 0; - public OsuRuleset(RulesetInfo rulesetInfo) + public OsuRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { } diff --git a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs index 4b3277a4e2..500347c874 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Tests public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() - : base(new OsuRuleset(new RulesetInfo())) + : base(new OsuRuleset()) { } } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 940fdf4fc9..50cc80db50 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko public override int LegacyID => 1; - public TaikoRuleset(RulesetInfo rulesetInfo) + public TaikoRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { } diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs index 639483b196..3d2d97b6d3 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Tests public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() - : base(new TaikoRuleset(new RulesetInfo())) + : base(new TaikoRuleset()) { } } diff --git a/osu.Game.Tests/Visual/TestCaseGamefield.cs b/osu.Game.Tests/Visual/TestCaseGamefield.cs index 0eebd29ffe..44f46dea18 100644 --- a/osu.Game.Tests/Visual/TestCaseGamefield.cs +++ b/osu.Game.Tests/Visual/TestCaseGamefield.cs @@ -56,25 +56,25 @@ namespace osu.Game.Tests.Visual Clock = new FramedClock(), Children = new Drawable[] { - new OsuRulesetContainer(new OsuRuleset(new RulesetInfo()), beatmap, false) + new OsuRulesetContainer(new OsuRuleset(), beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft }, - new TaikoRulesetContainer(new TaikoRuleset(new RulesetInfo()),beatmap, false) + new TaikoRulesetContainer(new TaikoRuleset(),beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.TopRight, Origin = Anchor.TopRight }, - new CatchRulesetContainer(new CatchRuleset(new RulesetInfo()),beatmap, false) + new CatchRulesetContainer(new CatchRuleset(),beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft }, - new ManiaRulesetContainer(new ManiaRuleset(new RulesetInfo()),beatmap, false) + new ManiaRulesetContainer(new ManiaRuleset(),beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.BottomRight, diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d7356cf100..d342e495e2 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -691,19 +691,19 @@ namespace osu.Game.Beatmaps protected override Storyboard GetStoryboard() { - if (BeatmapInfo?.Path == null && BeatmapSetInfo?.StoryboardFile == null) - return new Storyboard(); - try { - Decoder decoder; - using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo?.Path)))) - decoder = Decoder.GetDecoder(stream); - // try for .osb first and fall back to .osu - string storyboardFile = BeatmapSetInfo.StoryboardFile ?? BeatmapInfo.Path; - using (var stream = new StreamReader(store.GetStream(getPathForFile(storyboardFile)))) - return decoder.GetStoryboardDecoder().DecodeStoryboard(stream); + using (var beatmap = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + { + Decoder decoder = Decoder.GetDecoder(beatmap); + + if (BeatmapSetInfo?.StoryboardFile == null) + return decoder.GetStoryboardDecoder().DecodeStoryboard(beatmap); + + using (var storyboard = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) + return decoder.GetStoryboardDecoder().DecodeStoryboard(beatmap, storyboard); + } } catch { diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 0ae6637167..f4a3dacd53 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -64,7 +64,7 @@ namespace osu.Game.Beatmaps public override string ShortName => "dummy"; - public DummyRuleset(RulesetInfo rulesetInfo) + public DummyRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { } diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 8eeada66e8..1aae52208a 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -70,10 +70,11 @@ namespace osu.Game.Beatmaps.Formats protected abstract void ParseBeatmap(StreamReader stream, Beatmap beatmap); - public virtual Storyboard DecodeStoryboard(StreamReader stream) + public virtual Storyboard DecodeStoryboard(params StreamReader[] streams) { var storyboard = new Storyboard(); - ParseStoryboard(stream, storyboard); + foreach (StreamReader stream in streams) + ParseStoryboard(stream, storyboard); return storyboard; } diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index cfa52ef13c..f000e3334c 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -65,6 +65,7 @@ namespace osu.Game.Configuration // Gameplay Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01); + Set(OsuSetting.BlurLevel, 0, 0, 1, 0.01); Set(OsuSetting.ShowInterface, true); Set(OsuSetting.KeyOverlay, false); @@ -90,6 +91,7 @@ namespace osu.Game.Configuration GameplayCursorSize, AutoCursorSize, DimLevel, + BlurLevel, ShowStoryboard, KeyOverlay, FloatingComments, diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 648985e4b1..ec461b86fd 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -33,15 +33,6 @@ namespace osu.Game.Graphics.Containers // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceiveMouseInputAt(screenSpacePos); - protected override bool OnWheel(InputState state) - { - // always allow wheel to pass through to stuff outside our DrawRectangle. - if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position)) - return false; - - return BlockPassThroughMouse; - } - protected override bool OnClick(InputState state) { if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position)) diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs index 0649e4033f..2328533665 100644 --- a/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs @@ -3,12 +3,13 @@ using System; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface.Volume { - public class VolumeControlReceptor : Container, IKeyBindingHandler + public class VolumeControlReceptor : Container, IKeyBindingHandler, IHandleGlobalInput { public Func ActionRequested; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 6ce0157a9c..b60b0d9531 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -22,6 +22,12 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay Bindable = config.GetBindable(OsuSetting.DimLevel), KeyboardStep = 0.1f }, + new SettingsSlider + { + LabelText = "Background blur", + Bindable = config.GetBindable(OsuSetting.BlurLevel), + KeyboardStep = 0.1f + }, new SettingsCheckbox { LabelText = "Show score overlay", diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 6c5c272eac..4f256621fb 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -34,9 +34,9 @@ namespace osu.Game.Rulesets public Mod GetAutoplayMod() => GetAllMods().First(mod => mod is ModAutoplay); - protected Ruleset(RulesetInfo rulesetInfo) + protected Ruleset(RulesetInfo rulesetInfo = null) { - RulesetInfo = rulesetInfo; + RulesetInfo = rulesetInfo ?? createRulesetInfo(); } /// @@ -88,5 +88,17 @@ namespace osu.Game.Rulesets /// The variant. /// A descriptive name of the variant. public virtual string GetVariantName(int variant) => string.Empty; + + /// + /// Create a ruleset info based on this ruleset. + /// + /// A filled . + private RulesetInfo createRulesetInfo() => new RulesetInfo + { + Name = Description, + ShortName = ShortName, + InstantiationInfo = GetType().AssemblyQualifiedName, + ID = LegacyID + }; } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 76a4c99b86..01e3b6848f 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -58,30 +58,21 @@ namespace osu.Game.Rulesets { var context = GetContext(); - var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())).ToList(); + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { - var rulesetInfo = createRulesetInfo(r); - if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) - { - context.RulesetInfo.Add(rulesetInfo); - } + if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == r.RulesetInfo.ID) == null) + context.RulesetInfo.Add(r.RulesetInfo); } context.SaveChanges(); //add any other modes foreach (var r in instances.Where(r => r.LegacyID < 0)) - { - var us = createRulesetInfo(r); - - var existing = context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); - - if (existing == null) - context.RulesetInfo.Add(us); - } + if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) + context.RulesetInfo.Add(r.RulesetInfo); context.SaveChanges(); @@ -124,13 +115,5 @@ namespace osu.Game.Rulesets { } } - - private RulesetInfo createRulesetInfo(Ruleset ruleset) => new RulesetInfo - { - Name = ruleset.Description, - ShortName = ruleset.ShortName, - InstantiationInfo = ruleset.GetType().AssemblyQualifiedName, - ID = ruleset.LegacyID - }; } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 9b6fe36520..6274301a47 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -110,6 +110,12 @@ namespace osu.Game.Rulesets.UI //dividing by the customwidth will effectively scale our content to the required container size. protected override Vector2 DrawScale => CustomWidth.HasValue ? new Vector2(DrawSize.X / CustomWidth.Value) : base.DrawScale; + + protected override void Update() + { + base.Update(); + RelativeChildSize = new Vector2(DrawScale.X, RelativeChildSize.Y); + } } } } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index dd76ac5421..1ce84289b2 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.Transforms; using OpenTK; using osu.Game.Beatmaps; using osu.Game.Graphics.Backgrounds; @@ -19,10 +20,7 @@ namespace osu.Game.Screens.Backgrounds public WorkingBeatmap Beatmap { - get - { - return beatmap; - } + get { return beatmap; } set { if (beatmap == value && beatmap != null) @@ -56,11 +54,8 @@ namespace osu.Game.Screens.Backgrounds Beatmap = beatmap; } - public void BlurTo(Vector2 sigma, double duration, Easing easing = Easing.None) - { - background?.BlurTo(sigma, duration, easing); - blurTarget = sigma; - } + public TransformSequence BlurTo(Vector2 sigma, double duration, Easing easing = Easing.None) + => background?.BlurTo(blurTarget = sigma, duration, easing); public override bool Equals(BackgroundScreen other) { diff --git a/osu.Game/Screens/Play/HUD/VisualSettings.cs b/osu.Game/Screens/Play/HUD/VisualSettings.cs index 778978d26e..252aa8371e 100644 --- a/osu.Game/Screens/Play/HUD/VisualSettings.cs +++ b/osu.Game/Screens/Play/HUD/VisualSettings.cs @@ -33,10 +33,11 @@ namespace osu.Game.Screens.Play.HUD } } - private readonly TimeSpan hideTimeSpan = TimeSpan.FromSeconds(5); + private readonly TimeSpan hideTimeSpan = TimeSpan.FromSeconds(3); private Stopwatch hideStopWatch; private readonly ReplaySliderBar dimSliderBar; + private readonly ReplaySliderBar blurSliderBar; private readonly ReplayCheckbox showStoryboardToggle; private readonly ReplayCheckbox mouseWheelDisabledToggle; @@ -50,6 +51,11 @@ namespace osu.Game.Screens.Play.HUD }, dimSliderBar = new ReplaySliderBar(), new OsuSpriteText + { + Text = "Background blur:" + }, + blurSliderBar = new ReplaySliderBar(), + new OsuSpriteText { Text = "Toggles:" }, @@ -62,6 +68,7 @@ namespace osu.Game.Screens.Play.HUD private void load(OsuConfigManager config) { dimSliderBar.Bindable = config.GetBindable(OsuSetting.DimLevel); + blurSliderBar.Bindable = config.GetBindable(OsuSetting.BlurLevel); showStoryboardToggle.Bindable = config.GetBindable(OsuSetting.ShowStoryboard); mouseWheelDisabledToggle.Bindable = config.GetBindable(OsuSetting.MouseDisableWheel); @@ -91,7 +98,7 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); - if (Autohide && IsPresent && hideStopWatch.Elapsed > hideTimeSpan) this.FadeOut(100); + if (Autohide && IsPresent && hideStopWatch.Elapsed > hideTimeSpan) this.FadeOut(50); } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 39d436bdf2..3dcfd8b9c4 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -24,10 +24,10 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Ranking; using osu.Framework.Audio.Sample; using osu.Game.Beatmaps; +using osu.Game.Graphics; using osu.Game.Online.API; using osu.Game.Screens.Play.BreaksOverlay; using osu.Game.Storyboards.Drawables; -using OpenTK.Graphics; namespace osu.Game.Screens.Play { @@ -67,6 +67,7 @@ namespace osu.Game.Screens.Play #region User Settings private Bindable dimLevel; + private Bindable blurLevel; private Bindable showStoryboard; private Bindable mouseWheelDisabled; private Bindable userAudioOffset; @@ -90,6 +91,7 @@ namespace osu.Game.Screens.Play this.api = api; dimLevel = config.GetBindable(OsuSetting.DimLevel); + blurLevel = config.GetBindable(OsuSetting.BlurLevel); showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); @@ -318,10 +320,9 @@ namespace osu.Game.Screens.Play if (!loadedSuccessfully) return; - (Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1000, Easing.OutQuint); - - dimLevel.ValueChanged += dimLevel_ValueChanged; - showStoryboard.ValueChanged += showStoryboard_ValueChanged; + dimLevel.ValueChanged += _ => updateBackgroundElements(); + blurLevel.ValueChanged += _ => updateBackgroundElements(); + showStoryboard.ValueChanged += _ => updateBackgroundElements(); updateBackgroundElements(); Content.Alpha = 0; @@ -377,14 +378,12 @@ namespace osu.Game.Screens.Play return true; } - private void dimLevel_ValueChanged(double newValue) - => updateBackgroundElements(); - - private void showStoryboard_ValueChanged(bool newValue) - => updateBackgroundElements(); - private void updateBackgroundElements() { + if (!IsCurrentScreen) return; + + const float duration = 800; + var opacity = 1 - (float)dimLevel; if (showStoryboard && storyboard == null) @@ -393,17 +392,17 @@ namespace osu.Game.Screens.Play var beatmap = Beatmap.Value; var storyboardVisible = showStoryboard && beatmap.Storyboard.HasDrawable; - storyboardContainer.FadeColour(new Color4(opacity, opacity, opacity, 1), 800); - storyboardContainer.FadeTo(storyboardVisible && opacity > 0 ? 1 : 0); + storyboardContainer + .FadeColour(OsuColour.Gray(opacity), duration, Easing.OutQuint) + .FadeTo(storyboardVisible && opacity > 0 ? 1 : 0, duration, Easing.OutQuint); - Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? opacity : 0, 800, Easing.OutQuint); + (Background as BackgroundScreenBeatmap)? + .BlurTo(new Vector2((float)blurLevel.Value * 25), duration, Easing.OutQuint)? + .FadeTo(!storyboardVisible || beatmap.Background == null ? opacity : 0, duration, Easing.OutQuint); } private void fadeOut() { - dimLevel.ValueChanged -= dimLevel_ValueChanged; - showStoryboard.ValueChanged -= showStoryboard_ValueChanged; - const float fade_out_duration = 250; RulesetContainer?.FadeOut(fade_out_duration); diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 72c1fc7369..181ed5e0e6 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.IO; using System.Linq; using System.Text; @@ -18,24 +17,19 @@ namespace osu.Game.Tests.Visual { public abstract class TestCasePlayer : ScreenTestCase { - private readonly Type ruleset; + private readonly Ruleset ruleset; protected Player Player; private TestWorkingBeatmap working; - /// - /// Create a TestCase which runs through the Player screen. - /// - /// An optional ruleset type which we want to target. If not provided we'll allow all rulesets to be tested. - protected TestCasePlayer(Type ruleset) + protected TestCasePlayer(Ruleset ruleset) { this.ruleset = ruleset; } protected TestCasePlayer() { - } [BackgroundDependencyLoader] @@ -48,14 +42,21 @@ namespace osu.Game.Tests.Visual Depth = int.MaxValue }); - string instantiation = ruleset?.AssemblyQualifiedName; - - foreach (var r in rulesets.AvailableRulesets.Where(rs => instantiation == null || rs.InstantiationInfo == instantiation)) + if (ruleset != null) { Player p = null; - AddStep(r.Name, () => p = loadPlayerFor(r)); + AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => p.IsLoaded); } + else + { + foreach (var r in rulesets.AvailableRulesets) + { + Player p = null; + AddStep(r.Name, () => p = loadPlayerFor(r)); + AddUntilStep(() => p.IsLoaded); + } + } } protected virtual Beatmap CreateBeatmap() @@ -69,21 +70,21 @@ namespace osu.Game.Tests.Visual return beatmap; } - private Player loadPlayerFor(RulesetInfo r) + private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); + + private Player loadPlayerFor(Ruleset r) { var beatmap = CreateBeatmap(); - beatmap.BeatmapInfo.Ruleset = r; - - var instance = r.CreateInstance(); + beatmap.BeatmapInfo.Ruleset = r.RulesetInfo; working = new TestWorkingBeatmap(beatmap); - working.Mods.Value = new[] { instance.GetAllMods().First(m => m is ModNoFail) }; + working.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; if (Player != null) Remove(Player); - var player = CreatePlayer(working, instance); + var player = CreatePlayer(working, r); LoadComponentAsync(player, LoadScreen);