1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-21 12:47:44 +08:00

Merge remote-tracking branch 'origin/master' into performance-calculator

This commit is contained in:
smoogipoo 2017-11-28 21:38:26 +09:00
commit a9cc156d7a
144 changed files with 1372 additions and 873 deletions

View File

@ -15,7 +15,9 @@ This is still heavily under development and is not intended for end-user use. Th
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu-framework/issues).
Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues).
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible.

@ -1 +1 @@
Subproject commit 83925a84072ec9da0d008c82256294b765321c0b
Subproject commit d92cec764538da2e7ed95bfb566f6bc81a9667c8

@ -1 +1 @@
Subproject commit 1750ab8f6761ab35592fd46da71fbe0c141bfd93
Subproject commit 4287ee8043fb1419017359bc3a5db5dc06bc643f

View File

@ -13,7 +13,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
<add key="ProjectName" value="osu.Desktop" />
<add key="NuSpecName" value="osu.Desktop\osu.nuspec" />
<add key="SolutionName" value="osu" />
<add key="TargetName" value="Client\osu.Desktop" />
<add key="TargetName" value="osu.Desktop" />
<add key="PackageName" value="osulazer" />
<add key="IconName" value="lazer.ico" />
<add key="CodeSigningCertificate" value="" />

View File

@ -145,6 +145,8 @@ namespace osu.Desktop.Deploy
/// </summary>
private static void checkReleaseFiles()
{
if (!canGitHub) return;
var releaseLines = getReleaseLines();
//ensure we have all files necessary
@ -157,6 +159,8 @@ namespace osu.Desktop.Deploy
private static void pruneReleases()
{
if (!canGitHub) return;
write("Pruning RELEASES...");
var releaseLines = getReleaseLines().ToList();
@ -190,7 +194,7 @@ namespace osu.Desktop.Deploy
private static void uploadBuild(string version)
{
if (string.IsNullOrEmpty(GitHubAccessToken) || string.IsNullOrEmpty(codeSigningCertPath))
if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
return;
write("Publishing to GitHub...");
@ -228,8 +232,12 @@ namespace osu.Desktop.Deploy
private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
private static void checkGitHubReleases()
{
if (!canGitHub) return;
write("Checking GitHub releases...");
var req = new JsonWebRequest<List<GitHubRelease>>($"{GitHubApiEndpoint}");
req.AuthenticatedBlockingPerform();

View File

@ -11,14 +11,14 @@ using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps
{
internal class CatchBeatmapConverter : BeatmapConverter<CatchBaseHit>
internal class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
{
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
protected override IEnumerable<CatchBaseHit> ConvertHitObject(HitObject obj, Beatmap beatmap)
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, Beatmap beatmap)
{
var curveData = obj as IHasCurve;
var positionData = obj as IHasPosition;
var positionData = obj as IHasXPosition;
var comboData = obj as IHasCombo;
if (positionData == null)

View File

@ -6,9 +6,9 @@ using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps
{
internal class CatchBeatmapProcessor : BeatmapProcessor<CatchBaseHit>
internal class CatchBeatmapProcessor : BeatmapProcessor<CatchHitObject>
{
public override void PostProcess(Beatmap<CatchBaseHit> beatmap)
public override void PostProcess(Beatmap<CatchHitObject> beatmap)
{
if (beatmap.ComboColors.Count == 0)
return;
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
int comboIndex = 0;
int colourIndex = 0;
CatchBaseHit lastObj = null;
CatchHitObject lastObj = null;
foreach (var obj in beatmap.HitObjects)
{

View File

@ -8,7 +8,7 @@ using System.Collections.Generic;
namespace osu.Game.Rulesets.Catch
{
public class CatchDifficultyCalculator : DifficultyCalculator<CatchBaseHit>
public class CatchDifficultyCalculator : DifficultyCalculator<CatchHitObject>
{
public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
{
@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Catch
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
}
}

View File

@ -1,14 +1,18 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects
{
public abstract class CatchBaseHit : HitObject, IHasXPosition, IHasCombo
public abstract class CatchHitObject : HitObject, IHasXPosition, IHasCombo
{
public const double OBJECT_RADIUS = 44;
public float X { get; set; }
public Color4 ComboColour { get; set; } = Color4.Gray;
@ -20,5 +24,14 @@ namespace osu.Game.Rulesets.Catch.Objects
/// The next fruit starts a new combo. Used for explodey.
/// </summary>
public virtual bool LastInCombo { get; set; }
public float Scale { get; set; } = 1;
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(controlPointInfo, difficulty);
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
}
}
}

View File

@ -5,11 +5,12 @@ using System;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
where TObject : CatchBaseHit
where TObject : CatchHitObject
{
public new TObject HitObject;
@ -17,12 +18,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
: base(hitObject)
{
HitObject = hitObject;
Scale = new Vector2(HitObject.Scale);
}
}
public abstract class DrawableCatchHitObject : DrawableScrollingHitObject<CatchBaseHit>
public abstract class DrawableCatchHitObject : DrawableScrollingHitObject<CatchHitObject>
{
protected DrawableCatchHitObject(CatchBaseHit hitObject)
protected DrawableCatchHitObject(CatchHitObject hitObject)
: base(hitObject)
{
RelativePositionAxes = Axes.Both;
@ -30,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
Y = (float)HitObject.StartTime;
}
public Func<CatchBaseHit, bool> CheckPosition;
public Func<CatchHitObject, bool> CheckPosition;
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{

View File

@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
};
foreach (CatchBaseHit tick in s.Ticks)
foreach (CatchHitObject tick in s.Ticks)
{
TinyDroplet tiny = tick as TinyDroplet;
if (tiny != null)
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
}
}
protected override void AddNested(DrawableHitObject<CatchBaseHit> h)
protected override void AddNested(DrawableHitObject<CatchHitObject> h)
{
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
dropletContainer.Add(h);

View File

@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
{
public class Pulp : Circle, IHasAccentColour
{
public const float PULP_SIZE = 20;
public const float PULP_SIZE = (float)CatchHitObject.OBJECT_RADIUS / 2.2f;
public Pulp()
{

View File

@ -3,7 +3,7 @@
namespace osu.Game.Rulesets.Catch.Objects
{
public class Droplet : CatchBaseHit
public class Droplet : CatchHitObject
{
}
}

View File

@ -3,7 +3,7 @@
namespace osu.Game.Rulesets.Catch.Objects
{
public class Fruit : CatchBaseHit
public class Fruit : CatchHitObject
{
}
}

View File

@ -15,7 +15,7 @@ using osu.Framework.Lists;
namespace osu.Game.Rulesets.Catch.Objects
{
public class JuiceStream : CatchBaseHit, IHasCurve
public class JuiceStream : CatchHitObject, IHasCurve
{
/// <summary>
/// Positional distance that results in a duration of one second, before any speed adjustments.
@ -42,11 +42,11 @@ namespace osu.Game.Rulesets.Catch.Objects
TickDistance = scoringDistance / difficulty.SliderTickRate;
}
public IEnumerable<CatchBaseHit> Ticks
public IEnumerable<CatchHitObject> Ticks
{
get
{
SortedList<CatchBaseHit> ticks = new SortedList<CatchBaseHit>((a, b) => a.StartTime.CompareTo(b.StartTime));
SortedList<CatchHitObject> ticks = new SortedList<CatchHitObject>((a, b) => a.StartTime.CompareTo(b.StartTime));
if (TickDistance == 0)
return ticks;

View File

@ -10,14 +10,14 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch.Scoring
{
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit>
internal class CatchScoreProcessor : ScoreProcessor<CatchHitObject>
{
public CatchScoreProcessor(RulesetContainer<CatchBaseHit> rulesetContainer)
public CatchScoreProcessor(RulesetContainer<CatchHitObject> rulesetContainer)
: base(rulesetContainer)
{
}
protected override void SimulateAutoplay(Beatmap<CatchBaseHit> beatmap)
protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
{
foreach (var obj in beatmap.HitObjects)
{

View File

@ -11,16 +11,26 @@ namespace osu.Game.Rulesets.Catch.Tests
[Ignore("getting CI working")]
public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
{
public TestCaseCatchStacker() : base(typeof(CatchRuleset))
public TestCaseCatchStacker()
: base(typeof(CatchRuleset))
{
}
protected override Beatmap CreateBeatmap()
{
var beatmap = new Beatmap();
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty
{
CircleSize = 6,
}
}
};
for (int i = 0; i < 256; i++)
beatmap.HitObjects.Add(new Fruit { X = 0.5f, StartTime = i * 100, NewCombo = i % 8 == 0 });
for (int i = 0; i < 512; i++)
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
return beatmap;
}

View File

@ -1,44 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Tests.Visual;
using OpenTK;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
[Ignore("getting CI working")]
internal class TestCaseCatcher : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Catcher),
};
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
Children = new Drawable[]
{
new CatchInputManager(rulesets.GetRuleset(2))
{
RelativeSizeAxes = Axes.Both,
Child = new Catcher
{
RelativePositionAxes = Axes.Both,
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Size = new Vector2(1, 0.2f),
}
},
};
}
}
}

View File

@ -0,0 +1,50 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
[Ignore("getting CI working")]
internal class TestCaseCatcherArea : OsuTestCase
{
private RulesetInfo catchRuleset;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(CatcherArea),
};
public TestCaseCatcherArea()
{
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);
}
private void createCatcher(float size)
{
Child = new CatchInputManager(catchRuleset)
{
RelativeSizeAxes = Axes.Both,
Child = new CatcherArea(new BeatmapDifficulty { CircleSize = size })
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.BottomLeft
},
};
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
catchRuleset = rulesets.GetRuleset(2);
}
}
}

View File

@ -1,11 +1,11 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
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;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Judgements;
@ -20,10 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI
protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content;
private readonly Container catcherContainer;
private readonly Catcher catcher;
private readonly CatcherArea catcherArea;
public CatchPlayfield()
public CatchPlayfield(BeatmapDifficulty difficulty)
: base(Axes.Y)
{
Container explodingFruitContainer;
@ -43,30 +42,16 @@ namespace osu.Game.Rulesets.Catch.UI
{
RelativeSizeAxes = Axes.Both,
},
catcherContainer = new Container
catcherArea = new CatcherArea(difficulty)
{
RelativeSizeAxes = Axes.X,
ExplodingFruitTarget = explodingFruitContainer,
Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft,
Height = 180,
Child = catcher = new Catcher
{
ExplodingFruitTarget = explodingFruitContainer,
RelativePositionAxes = Axes.Both,
Origin = Anchor.TopCentre,
X = 0.5f,
}
}
};
}
protected override void Update()
{
base.Update();
catcher.Size = new Vector2(catcherContainer.DrawSize.Y);
}
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2;
public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.CanCatch(obj);
public override void Add(DrawableHitObject h)
{
@ -88,7 +73,7 @@ namespace osu.Game.Rulesets.Catch.UI
(judgedObject.Parent as Container<DrawableHitObject>)?.Remove(judgedObject);
(judgedObject.Parent as Container)?.Remove(judgedObject);
catcher.Add(judgedObject, screenPosition);
catcherArea.Add(judgedObject, screenPosition);
}
}
}

View File

@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch.UI
{
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchBaseHit>
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchHitObject>
{
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(ruleset, beatmap, isForCurrentRuleset)
@ -22,15 +22,15 @@ namespace osu.Game.Rulesets.Catch.UI
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
protected override BeatmapProcessor<CatchBaseHit> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
protected override BeatmapProcessor<CatchHitObject> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override Playfield CreatePlayfield() => new CatchPlayfield();
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty);
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
protected override DrawableHitObject<CatchBaseHit> GetVisualRepresentation(CatchBaseHit h)
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
{
var fruit = h as Fruit;
if (fruit != null)

View File

@ -1,193 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Catch.UI
{
public class Catcher : Container, IKeyBindingHandler<CatchAction>
{
private Texture texture;
private Container<DrawableHitObject> caughtFruit;
public Container ExplodingFruitTarget;
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
Children = new Drawable[]
{
createCatcherSprite(),
caughtFruit = new Container<DrawableHitObject>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
}
};
}
private int currentDirection;
private bool dashing;
protected bool Dashing
{
get { return dashing; }
set
{
if (value == dashing) return;
dashing = value;
if (dashing)
Schedule(addAdditiveSprite);
}
}
private void addAdditiveSprite()
{
if (!dashing) return;
var additive = createCatcherSprite();
additive.RelativePositionAxes = Axes.Both;
additive.Blending = BlendingMode.Additive;
additive.Position = Position;
additive.Scale = Scale;
((Container)Parent).Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire();
Scheduler.AddDelayed(addAdditiveSprite, 50);
}
private Sprite createCatcherSprite() => new Sprite
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
Texture = texture,
OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly.
};
public bool OnPressed(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection--;
return true;
case CatchAction.MoveRight:
currentDirection++;
return true;
case CatchAction.Dash:
Dashing = true;
return true;
}
return false;
}
public bool OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
return true;
case CatchAction.MoveRight:
currentDirection--;
return true;
case CatchAction.Dash:
Dashing = false;
return true;
}
return false;
}
/// <summary>
/// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable.
/// </summary>
private const double base_speed = 1.0 / 512;
protected override void Update()
{
base.Update();
if (currentDirection == 0) return;
double dashModifier = Dashing ? 1 : 0.5;
Scale = new Vector2(Math.Sign(currentDirection), 1);
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1);
}
public void Add(DrawableHitObject fruit, Vector2 absolutePosition)
{
fruit.RelativePositionAxes = Axes.None;
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
fruit.Anchor = Anchor.TopCentre;
fruit.Origin = Anchor.BottomCentre;
fruit.Scale *= 0.7f;
fruit.LifetimeEnd = double.MaxValue;
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
{
fruit.X += RNG.Next(-5, 5);
fruit.Y -= RNG.Next(0, 5);
}
caughtFruit.Add(fruit);
if (((CatchBaseHit)fruit.HitObject).LastInCombo)
explode();
}
private void explode()
{
var fruit = caughtFruit.ToArray();
foreach (var f in fruit)
{
var originalX = f.X * Scale.X;
if (ExplodingFruitTarget != null)
{
f.Anchor = Anchor.TopLeft;
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
caughtFruit.Remove(f);
ExplodingFruitTarget.Add(f);
}
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
.Then()
.MoveToY(f.Y + 50, 500, Easing.InSine);
f.MoveToX(f.X + originalX * 6, 1000);
f.FadeOut(750);
f.Expire();
}
}
}
}

View File

@ -0,0 +1,240 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Catch.UI
{
public class CatcherArea : Container
{
public const float CATCHER_SIZE = 172;
private readonly Catcher catcher;
public Container ExplodingFruitTarget
{
set { catcher.ExplodingFruitTarget = value; }
}
public CatcherArea(BeatmapDifficulty difficulty = null)
{
RelativeSizeAxes = Axes.X;
Height = CATCHER_SIZE;
Child = catcher = new Catcher(difficulty)
{
AdditiveTarget = this,
};
}
public void Add(DrawableHitObject fruit, Vector2 absolutePosition)
{
fruit.RelativePositionAxes = Axes.None;
fruit.Position = new Vector2(catcher.ToLocalSpace(absolutePosition).X - catcher.DrawSize.X / 2, 0);
fruit.Anchor = Anchor.TopCentre;
fruit.Origin = Anchor.BottomCentre;
fruit.Scale *= 0.7f;
fruit.LifetimeEnd = double.MaxValue;
catcher.Add(fruit);
}
public bool CanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X * Math.Abs(catcher.Scale.X) / DrawSize.X / 2;
public class Catcher : Container, IKeyBindingHandler<CatchAction>
{
private Texture texture;
private Container<DrawableHitObject> caughtFruit;
public Container ExplodingFruitTarget;
public Container AdditiveTarget;
public Catcher(BeatmapDifficulty difficulty = null)
{
RelativePositionAxes = Axes.X;
X = 0.5f;
Origin = Anchor.TopCentre;
Anchor = Anchor.TopLeft;
Size = new Vector2(CATCHER_SIZE);
if (difficulty != null)
Scale = new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
Children = new Drawable[]
{
createCatcherSprite(),
caughtFruit = new Container<DrawableHitObject>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
}
};
}
private int currentDirection;
private bool dashing;
protected bool Dashing
{
get { return dashing; }
set
{
if (value == dashing) return;
dashing = value;
if (dashing)
Schedule(addAdditiveSprite);
}
}
private void addAdditiveSprite()
{
if (!dashing || AdditiveTarget == null) return;
var additive = createCatcherSprite();
additive.Anchor = Anchor;
additive.OriginPosition = additive.OriginPosition + new Vector2(DrawWidth / 2, 0); // also temporary to align sprite correctly.
additive.Position = Position;
additive.Scale = Scale;
additive.RelativePositionAxes = RelativePositionAxes;
additive.Blending = BlendingMode.Additive;
AdditiveTarget.Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire();
Scheduler.AddDelayed(addAdditiveSprite, 50);
}
private Sprite createCatcherSprite() => new Sprite
{
Size = new Vector2(CATCHER_SIZE),
FillMode = FillMode.Fill,
Texture = texture,
OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly.
};
public void Add(DrawableHitObject fruit)
{
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
{
fruit.X += RNG.Next(-5, 5);
fruit.Y -= RNG.Next(0, 5);
}
caughtFruit.Add(fruit);
if (((CatchHitObject)fruit.HitObject).LastInCombo)
explode();
}
public bool OnPressed(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection--;
return true;
case CatchAction.MoveRight:
currentDirection++;
return true;
case CatchAction.Dash:
Dashing = true;
return true;
}
return false;
}
public bool OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
return true;
case CatchAction.MoveRight:
currentDirection--;
return true;
case CatchAction.Dash:
Dashing = false;
return true;
}
return false;
}
/// <summary>
/// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable.
/// </summary>
public const double BASE_SPEED = 1.0 / 512;
protected override void Update()
{
base.Update();
if (currentDirection == 0) return;
double dashModifier = Dashing ? 1 : 0.5;
Scale = new Vector2(Math.Abs(Scale.X) * Math.Sign(currentDirection), Scale.Y);
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1);
}
private void explode()
{
var fruit = caughtFruit.ToArray();
foreach (var f in fruit)
{
var originalX = f.X * Scale.X;
if (ExplodingFruitTarget != null)
{
f.Anchor = Anchor.TopLeft;
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
caughtFruit.Remove(f);
ExplodingFruitTarget.Add(f);
}
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
.Then()
.MoveToY(f.Y + 50, 500, Easing.InSine);
f.MoveToX(f.X + originalX * 6, 1000);
f.FadeOut(750);
f.Expire();
}
}
}
}
}

View File

@ -57,17 +57,17 @@
<Compile Include="Objects\JuiceStream.cs" />
<Compile Include="Scoring\CatchScoreProcessor.cs" />
<Compile Include="Judgements\CatchJudgement.cs" />
<Compile Include="Objects\CatchBaseHit.cs" />
<Compile Include="Objects\CatchHitObject.cs" />
<Compile Include="Objects\Drawable\DrawableFruit.cs" />
<Compile Include="Objects\Droplet.cs" />
<Compile Include="Objects\Fruit.cs" />
<Compile Include="Objects\TinyDroplet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tests\TestCaseCatcher.cs" />
<Compile Include="Tests\TestCaseCatcherArea.cs" />
<Compile Include="Tests\TestCaseCatchStacker.cs" />
<Compile Include="Tests\TestCasePerformancePoints.cs" />
<Compile Include="Tests\TestCaseCatchPlayer.cs" />
<Compile Include="UI\Catcher.cs" />
<Compile Include="UI\CatcherArea.cs" />
<Compile Include="UI\CatchRulesetContainer.cs" />
<Compile Include="UI\CatchPlayfield.cs" />
<Compile Include="CatchRuleset.cs" />

View File

@ -138,8 +138,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
Pattern newPattern = conversion.Generate();
lastPattern = newPattern;
var stairPatternGenerator = (HitObjectPatternGenerator)conversion;
lastStair = stairPatternGenerator.StairType;
var stairPatternGenerator = conversion as HitObjectPatternGenerator;
lastStair = stairPatternGenerator?.StairType ?? lastStair;
return newPattern.HitObjects;
}

View File

@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Tests
private const double start_time = 500;
private const double duration = 500;
public override string Description => @"Mania playfield";
protected override double TimePerAction => 200;
private RulesetInfo maniaRuleset;

View File

@ -30,8 +30,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
private const double default_duration = 1000;
private const float scroll_time = 1000;
public override string Description => "Taiko playfield";
protected override double TimePerAction => default_duration * 2;
private readonly Random rng = new Random(1337);

View File

@ -5,6 +5,5 @@ namespace osu.Game.Tests.Visual
{
public class TestCaseAllPlayers : TestCasePlayer
{
public override string Description => @"Showing everything to play the game.";
}
}

View File

@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseBeatSyncedContainer : OsuTestCase
{
public override string Description => @"Tests beat synced containers.";
private readonly MusicController mc;
public TestCaseBeatSyncedContainer()

View File

@ -9,10 +9,9 @@ using OpenTK;
namespace osu.Game.Tests.Visual
{
[TestFixture]
[System.ComponentModel.Description("PlaySongSelect leaderboard/details area")]
internal class TestCaseBeatmapDetailArea : OsuTestCase
{
public override string Description => @"Beatmap details in song select";
public TestCaseBeatmapDetailArea()
{
Add(new BeatmapDetailArea
@ -23,4 +22,4 @@ namespace osu.Game.Tests.Visual
});
}
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
@ -8,10 +9,9 @@ using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual
{
[Description("PlaySongSelect beatmap details")]
internal class TestCaseBeatmapDetails : OsuTestCase
{
public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
public TestCaseBeatmapDetails()
{
BeatmapDetails details;

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Game.Graphics;
using osu.Game.Screens.Select.Options;
using OpenTK.Graphics;
@ -8,10 +9,9 @@ using OpenTK.Input;
namespace osu.Game.Tests.Visual
{
[Description("bottom beatmap details")]
internal class TestCaseBeatmapOptionsOverlay : OsuTestCase
{
public override string Description => @"Beatmap options in song select";
public TestCaseBeatmapOptionsOverlay()
{
var overlay = new BeatmapOptionsOverlay();

View File

@ -3,7 +3,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
@ -14,13 +13,13 @@ using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using System.Collections.Generic;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Tests.Visual
{
[System.ComponentModel.Description("in BeatmapOverlay")]
public class TestCaseBeatmapScoresContainer : OsuTestCase
{
public override string Description => "BeatmapOverlay scores container";
private readonly IEnumerable<OnlineScore> scores;
private readonly IEnumerable<OnlineScore> anotherScores;
private readonly OnlineScore topScore;

View File

@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseBeatmapSetOverlay : OsuTestCase
{
public override string Description => @"view online beatmap sets";
private readonly BeatmapSetOverlay overlay;
public TestCaseBeatmapSetOverlay()

View File

@ -8,8 +8,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseBreadcrumbs : OsuTestCase
{
public override string Description => @"breadcrumb > control";
public TestCaseBreadcrumbs()
{
BreadcrumbControl<BreadcrumbTab> c;

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseBreakOverlay : OsuTestCase
{
public override string Description => @"Tests breaks behavior";
private readonly BreakOverlay breakOverlay;
public TestCaseBreakOverlay()
@ -88,4 +86,4 @@ namespace osu.Game.Tests.Visual
};
}
}
}
}

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
internal class TestCaseButtonSystem : OsuTestCase
{
public TestCaseButtonSystem()
{
OsuLogo logo;
ButtonSystem buttons;
Children = new Drawable[]
{
new Box
{
Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
RelativeSizeAxes = Axes.Both,
},
buttons = new ButtonSystem(),
logo = new OsuLogo()
};
buttons.SetOsuLogo(logo);
}
}
}

View File

@ -1,15 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
namespace osu.Game.Tests.Visual
{
[Description("Testing chat api and overlay")]
internal class TestCaseChatDisplay : OsuTestCase
{
public override string Description => @"Testing chat api and overlay";
public TestCaseChatDisplay()
{
Add(new ChatOverlay

View File

@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseContextMenu : OsuTestCase
{
public override string Description => @"Menu visible on right click";
private const int start_time = 0;
private const int duration = 1000;

View File

@ -9,8 +9,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseDialogOverlay : OsuTestCase
{
public override string Description => @"Display dialogs";
public TestCaseDialogOverlay()
{
DialogOverlay overlay;

View File

@ -11,8 +11,6 @@ namespace osu.Game.Tests.Visual
{
public class TestCaseDirect : OsuTestCase
{
public override string Description => @"osu!direct overlay";
private DirectOverlay direct;
private RulesetStore rulesets;

View File

@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseDrawableRoom : OsuTestCase
{
public override string Description => @"Select your favourite room";
private RulesetStore rulesets;
protected override void LoadComplete()

View File

@ -2,15 +2,15 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.ComponentModel;
using osu.Game.Screens.Tournament;
using osu.Game.Screens.Tournament.Teams;
namespace osu.Game.Tests.Visual
{
[Description("for tournament use")]
internal class TestCaseDrawings : OsuTestCase
{
public override string Description => "Tournament drawings";
public TestCaseDrawings()
{
Add(new Drawings

View File

@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseGamefield : OsuTestCase
{
public override string Description => @"Showing hitobjects and what not.";
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseGraph : OsuTestCase
{
public override string Description => "graph";
public TestCaseGraph()
{
BarGraph graph;
@ -36,4 +34,4 @@ namespace osu.Game.Tests.Visual
AddStep("Right to left", () => graph.Direction = BarDirection.RightToLeft);
}
}
}
}

View File

@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual
{
public class TestCaseIconButton : OsuTestCase
{
public override string Description => "Various display modes of icon buttons";
public TestCaseIconButton()
{
Child = new FillFlowContainer

View File

@ -9,8 +9,6 @@ namespace osu.Game.Tests.Visual
{
private readonly KeyBindingOverlay overlay;
public override string Description => @"Key configuration";
public TestCaseKeyConfiguration()
{
Child = overlay = new KeyBindingOverlay();

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseKeyCounter : OsuTestCase
{
public override string Description => @"Tests key counter";
public TestCaseKeyCounter()
{
KeyCounterCollection kc = new KeyCounterCollection

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select.Leaderboards;
@ -9,10 +10,9 @@ using OpenTK;
namespace osu.Game.Tests.Visual
{
[Description("PlaySongSelect leaderboard")]
internal class TestCaseLeaderboard : OsuTestCase
{
public override string Description => @"From song select";
private readonly Leaderboard leaderboard;
private void newScores()

View File

@ -11,8 +11,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseMedalOverlay : OsuTestCase
{
public override string Description => @"medal get!";
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(MedalOverlay),

View File

@ -1,25 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
internal class TestCaseMenuButtonSystem : OsuTestCase
{
public override string Description => @"Main menu button system";
public TestCaseMenuButtonSystem()
{
Add(new Box
{
Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
RelativeSizeAxes = Framework.Graphics.Axes.Both,
});
Add(new ButtonSystem());
}
}
}

View File

@ -1,16 +1,16 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
{
[Description("player pause/fail screens")]
internal class TestCaseMenuOverlays : OsuTestCase
{
public override string Description => @"Tests pause and fail overlays";
public TestCaseMenuOverlays()
{
FailOverlay failOverlay;

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Overlays.Mods;
@ -10,10 +11,9 @@ using OpenTK;
namespace osu.Game.Tests.Visual
{
[Description("mod select and icon display")]
internal class TestCaseMods : OsuTestCase
{
public override string Description => @"Mod select overlay and in-game display";
private ModSelectOverlay modSelect;
private ModDisplay modDisplay;

View File

@ -13,8 +13,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseMusicController : OsuTestCase
{
public override string Description => @"Tests music controller ui.";
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
public TestCaseMusicController()

View File

@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
[TestFixture]
internal class TestCaseNotificationOverlay : OsuTestCase
{
public override string Description => @"I handle notifications";
private readonly NotificationOverlay manager;
public TestCaseNotificationOverlay()

View File

@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
private FrameworkConfigManager config;
private Bindable<FrameSync> frameSyncMode;
public override string Description => @"Make it easier to see setting changes";
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -22,8 +22,6 @@ namespace osu.Game.Tests.Visual
{
private BeatmapManager manager;
public override string Description => @"with fake data";
private RulesetStore rulesets;
private DependencyContainer dependencies;

View File

@ -0,0 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Components;
using osu.Game.Tests.Beatmaps;
using OpenTK;
namespace osu.Game.Tests.Visual
{
public class TestCasePlaybackControl : OsuTestCase
{
public TestCasePlaybackControl()
{
var playback = new PlaybackControl
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200,100)
};
playback.Beatmap.Value = new TestWorkingBeatmap(new Beatmap());
Add(playback);
}
}
}

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseReplay : TestCasePlayer
{
public override string Description => @"Testing replay playback.";
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
{
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseReplaySettingsOverlay : OsuTestCase
{
public override string Description => @"Settings visible in replay/auto";
public TestCaseReplaySettingsOverlay()
{
ExampleContainer container;
@ -24,7 +22,7 @@ namespace osu.Game.Tests.Visual
Add(container = new ExampleContainer());
AddStep(@"Add button", () => container.Add(new OsuButton
AddStep(@"Add button", () => container.Add(new TriangleButton
{
RelativeSizeAxes = Axes.X,
Text = @"Button",

View File

@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
{
private BeatmapManager beatmaps;
public override string Description => @"Results after playing.";
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps)
{

View File

@ -13,8 +13,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseRoomInspector : OsuTestCase
{
public override string Description => @"from the multiplayer lobby";
private RulesetStore rulesets;
protected override void LoadComplete()

View File

@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseScoreCounter : OsuTestCase
{
public override string Description => @"Tests multiple counters";
public TestCaseScoreCounter()
{
int numerator = 0, denominator = 0;

View File

@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseSettings : OsuTestCase
{
public override string Description => @"Tests the settings overlay";
private readonly SettingsOverlay settings;
public TestCaseSettings()

View File

@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseSkipButton : OsuTestCase
{
public override string Description => @"Skip skip skippediskip";
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -8,8 +8,6 @@ namespace osu.Game.Tests.Visual
{
public class TestCaseSocial : OsuTestCase
{
public override string Description => @"social browser overlay";
public TestCaseSocial()
{
SocialOverlay s = new SocialOverlay

View File

@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseSongProgress : OsuTestCase
{
public override string Description => @"With fake data";
private readonly SongProgress progress;
private readonly SongProgressGraph graph;

View File

@ -16,8 +16,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseStoryboard : OsuTestCase
{
public override string Description => @"Tests storyboards.";
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
private readonly Container<DrawableStoryboard> storyboardContainer;

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
@ -9,10 +10,9 @@ using OpenTK;
namespace osu.Game.Tests.Visual
{
[Description("SongSelect filter control")]
public class TestCaseTabControl : OsuTestCase
{
public override string Description => @"Filter for song select";
public TestCaseTabControl()
{
OsuSpriteText text;

View File

@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseTextAwesome : OsuTestCase
{
public override string Description => @"Tests display of icons";
public TestCaseTextAwesome()
{
FillFlowContainer flow;

View File

@ -1,14 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Tests.Visual
{
[Description("mostly back button")]
internal class TestCaseTwoLayerButton : OsuTestCase
{
public override string Description => @"Mostly back button";
public TestCaseTwoLayerButton()
{
Add(new BackButton());

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseUserPanel : OsuTestCase
{
public override string Description => @"Panels for displaying a user's status";
public TestCaseUserPanel()
{
UserPanel flyte;

View File

@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseUserProfile : OsuTestCase
{
public override string Description => "Tests user's profile page.";
public TestCaseUserProfile()
{
var profile = new UserProfileOverlay();

View File

@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
{
internal class TestCaseUserRanks : OsuTestCase
{
public override string Description => "showing your latest achievements";
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableScore), typeof(RanksSection) };
public TestCaseUserRanks()

View File

@ -116,7 +116,7 @@
<Compile Include="Visual\TestCaseKeyCounter.cs" />
<Compile Include="Visual\TestCaseLeaderboard.cs" />
<Compile Include="Visual\TestCaseMedalOverlay.cs" />
<Compile Include="Visual\TestCaseMenuButtonSystem.cs" />
<Compile Include="Visual\TestCaseButtonSystem.cs" />
<Compile Include="Visual\TestCaseMenuOverlays.cs" />
<Compile Include="Visual\TestCaseMods.cs" />
<Compile Include="Visual\TestCaseMusicController.cs" />
@ -124,6 +124,7 @@
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
<Compile Include="Visual\TestCaseAllPlayers.cs" />
<Compile Include="Visual\TestCaseOsuGame.cs" />
<Compile Include="Visual\TestCasePlaybackControl.cs" />
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
<Compile Include="Visual\TestCaseReplay.cs" />
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />

View File

@ -80,6 +80,7 @@ namespace osu.Game.Beatmaps
/// <summary>
/// Performs the conversion of a hit object.
/// This method is generally executed sequentially for all objects in a beatmap.
/// </summary>
/// <param name="original">The hit object to convert.</param>
/// <param name="beatmap">The un-converted Beatmap.</param>

View File

@ -18,6 +18,7 @@ using osu.Framework.Platform;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.IO;
using osu.Game.IPC;
using osu.Game.Online.API;
@ -52,6 +53,11 @@ namespace osu.Game.Beatmaps
/// </summary>
public event Action<BeatmapInfo> BeatmapRestored;
/// <summary>
/// Fired when a beatmap download begins.
/// </summary>
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadBegan;
/// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary>
@ -165,7 +171,7 @@ namespace osu.Game.Beatmaps
catch (Exception e)
{
e = e.InnerException ?? e;
Logger.Error(e, @"Could not import beatmap set");
Logger.Error(e, $@"Could not import beatmap set ({Path.GetFileName(path)})");
}
}
@ -221,21 +227,29 @@ namespace osu.Game.Beatmaps
/// Downloads a beatmap.
/// </summary>
/// <param name="beatmapSetInfo">The <see cref="BeatmapSetInfo"/> to be downloaded.</param>
/// <returns>A new <see cref="DownloadBeatmapSetRequest"/>, or an existing one if a download is already in progress.</returns>
public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo)
/// <param name="noVideo">Whether the beatmap should be downloaded without video. Defaults to false.</param>
public void Download(BeatmapSetInfo beatmapSetInfo, bool noVideo = false)
{
var existing = GetExistingDownload(beatmapSetInfo);
if (existing != null) return existing;
if (existing != null || api == null) return;
if (api == null) return null;
if (!api.LocalUser.Value.IsSupporter)
{
PostNotification?.Invoke(new SimpleNotification
{
Icon = FontAwesome.fa_superpowers,
Text = "You gotta be a supporter to download for now 'yo"
});
return;
}
ProgressNotification downloadNotification = new ProgressNotification
{
Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
};
var request = new DownloadBeatmapSetRequest(beatmapSetInfo);
var request = new DownloadBeatmapSetRequest(beatmapSetInfo, noVideo);
request.DownloadProgressed += progress =>
{
@ -280,8 +294,7 @@ namespace osu.Game.Beatmaps
// don't run in the main api queue as this is a long-running task.
Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning);
return request;
BeatmapDownloadBegan?.Invoke(request);
}
/// <summary>

View File

@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps
public class BeatmapMetrics
{
/// <summary>
/// Total vote counts of user ratings on a scale of 0..length.
/// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?).
/// </summary>
public IEnumerable<int> Ratings { get; set; }

View File

@ -11,7 +11,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Shapes;
@ -28,10 +27,8 @@ namespace osu.Game.Beatmaps.Drawables
public Action<BeatmapSetInfo> RestoreHiddenRequested;
private readonly SpriteText title;
private readonly SpriteText artist;
private readonly WorkingBeatmap beatmap;
private readonly FillFlowContainer difficultyIcons;
public BeatmapSetHeader(WorkingBeatmap beatmap)
@ -41,44 +38,10 @@ namespace osu.Game.Beatmaps.Drawables
this.beatmap = beatmap;
Children = new Drawable[]
difficultyIcons = new FillFlowContainer
{
new DelayedLoadWrapper(
new PanelBackground(beatmap)
{
RelativeSizeAxes = Axes.Both,
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
}
)
{
TimeBeforeLoad = 300,
},
new FillFlowContainer
{
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Top = 5, Left = 18, Right = 10, Bottom = 10 },
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
title = new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
TextSize = 22,
Shadow = true,
},
artist = new OsuSpriteText
{
Font = @"Exo2.0-SemiBoldItalic",
TextSize = 17,
Shadow = true,
},
difficultyIcons = new FillFlowContainer
{
Margin = new MarginPadding { Top = 5 },
AutoSizeAxes = Axes.Both,
}
}
}
Margin = new MarginPadding { Top = 5 },
AutoSizeAxes = Axes.Both,
};
}
@ -94,8 +57,39 @@ namespace osu.Game.Beatmaps.Drawables
if (localisation == null)
throw new ArgumentNullException(nameof(localisation));
title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title);
artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist);
Children = new Drawable[]
{
new DelayedLoadWrapper(
new PanelBackground(beatmap)
{
RelativeSizeAxes = Axes.Both,
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
}, 300),
new FillFlowContainer
{
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Top = 5, Left = 18, Right = 10, Bottom = 10 },
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title),
TextSize = 22,
Shadow = true,
},
new OsuSpriteText
{
Font = @"Exo2.0-SemiBoldItalic",
Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist),
TextSize = 17,
Shadow = true,
},
difficultyIcons
}
}
};
}
private class PanelBackground : BufferedContainer
@ -185,4 +179,4 @@ namespace osu.Game.Beatmaps.Drawables
}
}
}
}
}

View File

@ -3,12 +3,18 @@
using System;
using osu.Framework;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.MathUtils;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
@ -22,6 +28,10 @@ namespace osu.Game.Beatmaps.Drawables
private readonly Container nestedContainer;
private readonly Container borderContainer;
private readonly Box hoverLayer;
protected override Container<Drawable> Content => nestedContainer;
protected Panel()
@ -29,20 +39,56 @@ namespace osu.Game.Beatmaps.Drawables
Height = MAX_HEIGHT;
RelativeSizeAxes = Axes.X;
AddInternal(nestedContainer = new Container
AddInternal(borderContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 10,
BorderColour = new Color4(221, 255, 255, 255),
Children = new Drawable[]
{
nestedContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
hoverLayer = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
Blending = BlendingMode.Additive,
},
}
});
Alpha = 0;
}
private SampleChannel sampleHover;
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
sampleHover = audio.Sample.Get($@"SongSelect/song-ping-variation-{RNG.Next(1, 5)}");
hoverLayer.Colour = colours.Blue.Opacity(0.1f);
}
protected override bool OnHover(InputState state)
{
sampleHover?.Play();
hoverLayer.FadeIn(100, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hoverLayer.FadeOut(1000, Easing.OutQuint);
base.OnHoverLost(state);
}
public void SetMultiplicativeAlpha(float alpha)
{
nestedContainer.Alpha = alpha;
borderContainer.Alpha = alpha;
}
protected override void LoadComplete()
@ -94,8 +140,8 @@ namespace osu.Game.Beatmaps.Drawables
protected virtual void Selected()
{
nestedContainer.BorderThickness = 2.5f;
nestedContainer.EdgeEffect = new EdgeEffectParameters
borderContainer.BorderThickness = 2.5f;
borderContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = new Color4(130, 204, 255, 150),
@ -106,8 +152,8 @@ namespace osu.Game.Beatmaps.Drawables
protected virtual void Deselected()
{
nestedContainer.BorderThickness = 0;
nestedContainer.EdgeEffect = new EdgeEffectParameters
borderContainer.BorderThickness = 0;
borderContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(1),

View File

@ -8,6 +8,7 @@ using osu.Game.Rulesets.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace osu.Game.Beatmaps
{
@ -29,10 +30,10 @@ namespace osu.Game.Beatmaps
Mods.ValueChanged += mods => applyRateAdjustments();
beatmap = new Lazy<Beatmap>(populateBeatmap);
background = new Lazy<Texture>(populateBackground);
track = new Lazy<Track>(populateTrack);
waveform = new Lazy<Waveform>(populateWaveform);
beatmap = new AsyncLazy<Beatmap>(populateBeatmap);
background = new AsyncLazy<Texture>(populateBackground);
track = new AsyncLazy<Track>(populateTrack);
waveform = new AsyncLazy<Waveform>(populateWaveform);
}
protected abstract Beatmap GetBeatmap();
@ -41,8 +42,10 @@ namespace osu.Game.Beatmaps
protected virtual Waveform GetWaveform() => new Waveform();
public bool BeatmapLoaded => beatmap.IsValueCreated;
public Beatmap Beatmap => beatmap.Value;
private readonly Lazy<Beatmap> beatmap;
public Beatmap Beatmap => beatmap.Value.Result;
public async Task<Beatmap> GetBeatmapAsync() => await beatmap.Value;
private readonly AsyncLazy<Beatmap> beatmap;
private Beatmap populateBeatmap()
{
@ -55,14 +58,16 @@ namespace osu.Game.Beatmaps
}
public bool BackgroundLoaded => background.IsValueCreated;
public Texture Background => background.Value;
private Lazy<Texture> background;
public Texture Background => background.Value.Result;
public async Task<Texture> GetBackgroundAsync() => await background.Value;
private AsyncLazy<Texture> background;
private Texture populateBackground() => GetBackground();
public bool TrackLoaded => track.IsValueCreated;
public Track Track => track.Value;
private Lazy<Track> track;
public Track Track => track.Value.Result;
public async Task<Track> GetTrackAsync() => await track.Value;
private AsyncLazy<Track> track;
private Track populateTrack()
{
@ -73,8 +78,9 @@ namespace osu.Game.Beatmaps
}
public bool WaveformLoaded => waveform.IsValueCreated;
public Waveform Waveform => waveform.Value;
private readonly Lazy<Waveform> waveform;
public Waveform Waveform => waveform.Value.Result;
public async Task<Waveform> GetWaveformAsync() => await waveform.Value;
private readonly AsyncLazy<Waveform> waveform;
private Waveform populateWaveform() => GetWaveform();
@ -107,5 +113,13 @@ namespace osu.Game.Beatmaps
foreach (var mod in Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(t);
}
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory)
: base(() => Task.Run(valueFactory))
{
}
}
}
}

View File

@ -16,12 +16,13 @@ namespace osu.Game.Configuration
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details);
Set(OsuSetting.ShowConvertedBeatmaps, true);
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01);
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
// Online settings
Set(OsuSetting.Username, string.Empty);
@ -112,6 +113,7 @@ namespace osu.Game.Configuration
SnakingOutSliders,
ShowFpsDisplay,
ChatDisplayHeight,
Version
Version,
ShowConvertedBeatmaps
}
}

View File

@ -35,6 +35,7 @@ namespace osu.Game.Database
var id = obj.ID;
obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
context.Entry(obj).Reload();
}
/// <summary>

View File

@ -2,34 +2,39 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Containers
{
public class OsuClickableContainer : ClickableContainer
{
protected SampleChannel SampleClick, SampleHover;
private readonly HoverSampleSet sampleSet;
private readonly Container content = new Container { RelativeSizeAxes = Axes.Both };
protected override Container<Drawable> Content => content;
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
this.sampleSet = sampleSet;
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
private void load()
{
SampleHover = audio.Sample.Get(@"UI/generic-hover");
SampleClick = audio.Sample.Get(@"UI/generic-click");
}
if (AutoSizeAxes != Axes.None)
{
content.RelativeSizeAxes = RelativeSizeAxes;
content.AutoSizeAxes = AutoSizeAxes;
}
protected override bool OnHover(InputState state)
{
SampleHover?.Play();
return base.OnHover(state);
}
protected override bool OnClick(InputState state)
{
SampleClick?.Play();
return base.OnClick(state);
InternalChildren = new Drawable[]
{
content,
new HoverClickSounds(sampleSet)
};
}
}
}

View File

@ -16,8 +16,8 @@ namespace osu.Game.Graphics.Containers
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
samplePopIn = audio.Sample.Get(@"UI/melodic-5");
samplePopOut = audio.Sample.Get(@"UI/melodic-4");
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
StateChanged += onStateChanged;
}

View File

@ -57,19 +57,31 @@ namespace osu.Game.Graphics
private void load(FontStore store)
{
this.store = store;
updateTexture();
}
protected override void LoadComplete()
{
base.LoadComplete();
updateTexture();
}
private FontAwesome loadedIcon;
private void updateTexture()
{
var texture = store?.Get(((char)icon).ToString());
var loadableIcon = icon;
if (loadableIcon == loadedIcon) return;
var texture = store?.Get(((char)loadableIcon).ToString());
spriteMain.Texture = texture;
spriteShadow.Texture = texture;
if (Size == Vector2.Zero)
Size = new Vector2(texture?.DisplayWidth ?? 0, texture?.DisplayHeight ?? 0);
loadedIcon = loadableIcon;
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)

View File

@ -20,6 +20,7 @@ namespace osu.Game.Graphics.UserInterface
private const Easing easing = Easing.InOutCubic;
private float length;
/// <summary>
/// Length of the bar, ranges from 0 to 1
/// </summary>
@ -134,4 +135,4 @@ namespace osu.Game.Graphics.UserInterface
Vertical = TopToBottom | BottomToTop,
Horizontal = LeftToRight | RightToLeft,
}
}
}

View File

@ -0,0 +1,36 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Adds hover and click sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverClickSounds : HoverSounds
{
private SampleChannel sampleClick;
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) : base(sampleSet)
{
}
protected override bool OnClick(InputState state)
{
sampleClick?.Play();
return base.OnClick(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}");
}
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Adds hover sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverSounds : CompositeDrawable
{
private SampleChannel sampleHover;
protected readonly HoverSampleSet SampleSet;
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
SampleSet = sampleSet;
RelativeSizeAxes = Axes.Both;
}
protected override bool OnHover(InputState state)
{
sampleHover?.Play();
return base.OnHover(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
}
}
public enum HoverSampleSet
{
[Description("")]
Loud,
[Description("-soft")]
Normal,
[Description("-softer")]
Soft
}
}

View File

@ -1,126 +1,18 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuButton : Button, IFilterable
/// <summary>
/// A button with added default sound effects.
/// </summary>
public class OsuButton : Button
{
private Box hover;
private SampleChannel sampleClick;
private SampleChannel sampleHover;
protected Triangles Triangles;
public OsuButton()
{
Height = 40;
}
protected override SpriteText CreateText() => new OsuSpriteText
{
Depth = -1,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Font = @"Exo2.0-Bold",
};
public override bool HandleInput => Action != null;
[BackgroundDependencyLoader]
private void load(OsuColour colours, AudioManager audio)
{
if (Action == null)
Colour = OsuColour.Gray(0.5f);
BackgroundColour = colours.BlueDark;
Content.Masking = true;
Content.CornerRadius = 5;
AddRange(new Drawable[]
{
Triangles = new Triangles
{
RelativeSizeAxes = Axes.Both,
ColourDark = colours.BlueDarker,
ColourLight = colours.Blue,
},
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive,
Colour = Color4.White.Opacity(0.1f),
Alpha = 0,
},
});
sampleClick = audio.Sample.Get(@"UI/generic-click");
sampleHover = audio.Sample.Get(@"UI/generic-hover");
Enabled.ValueChanged += enabled_ValueChanged;
Enabled.TriggerChange();
}
private void enabled_ValueChanged(bool enabled)
{
this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
}
protected override bool OnClick(InputState state)
{
sampleClick?.Play();
return base.OnClick(state);
}
protected override bool OnHover(InputState state)
{
sampleHover?.Play();
hover.FadeIn(200);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(200);
base.OnHoverLost(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Content.ScaleTo(0.9f, 4000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
public IEnumerable<string> FilterTerms => new[] { Text };
public bool MatchingFilter
{
set
{
this.FadeTo(value ? 1 : 0);
}
Add(new HoverClickSounds(HoverSampleSet.Loud));
}
}
}

View File

@ -70,7 +70,8 @@ namespace osu.Game.Graphics.UserInterface
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 5 },
}
},
new HoverClickSounds()
};
Nub.Current.BindTo(Current);

View File

@ -33,7 +33,6 @@ namespace osu.Game.Graphics.UserInterface
if (accentColour == default(Color4))
accentColour = colours.PinkDarker;
updateAccentColour();
}
private void updateAccentColour()
@ -137,6 +136,8 @@ namespace osu.Game.Graphics.UserInterface
nonAccentHoverColour = colours.PinkDarker;
nonAccentSelectedColour = Color4.Black.Opacity(0.5f);
updateColours();
AddInternal(new HoverClickSounds(HoverSampleSet.Soft));
}
protected override void UpdateForegroundColour()
@ -183,7 +184,7 @@ namespace osu.Game.Graphics.UserInterface
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
}
},
};
}
}
@ -237,8 +238,10 @@ namespace osu.Game.Graphics.UserInterface
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 4 },
Size = new Vector2(20),
}
},
};
AddInternal(new HoverClickSounds());
}
[BackgroundDependencyLoader]

View File

@ -72,7 +72,7 @@ namespace osu.Game.Graphics.UserInterface
private void load(AudioManager audio)
{
sampleHover = audio.Sample.Get(@"UI/generic-hover");
sampleClick = audio.Sample.Get(@"UI/generic-click");
sampleClick = audio.Sample.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent;
BackgroundColourHover = OsuColour.FromHex(@"172023");

View File

@ -88,7 +88,8 @@ namespace osu.Game.Graphics.UserInterface
{
Origin = Anchor.TopCentre,
Expanded = true,
}
},
new HoverClickSounds()
};
Current.DisabledChanged += disabled =>

View File

@ -131,7 +131,8 @@ namespace osu.Game.Graphics.UserInterface
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
},
new HoverClickSounds()
};
}

View File

@ -57,6 +57,7 @@ namespace osu.Game.Graphics.UserInterface
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new HoverClickSounds()
};
}

View File

@ -0,0 +1,108 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
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.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A button with moving triangles in the background.
/// </summary>
public class TriangleButton : OsuButton, IFilterable
{
private Box hover;
protected Triangles Triangles;
public TriangleButton()
{
Height = 40;
}
protected override SpriteText CreateText() => new OsuSpriteText
{
Depth = -1,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Font = @"Exo2.0-Bold",
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.BlueDark;
Content.Masking = true;
Content.CornerRadius = 5;
AddRange(new Drawable[]
{
Triangles = new Triangles
{
RelativeSizeAxes = Axes.Both,
ColourDark = colours.BlueDarker,
ColourLight = colours.Blue,
},
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive,
Colour = Color4.White.Opacity(0.1f),
Alpha = 0,
},
});
Enabled.ValueChanged += enabled_ValueChanged;
Enabled.TriggerChange();
}
private void enabled_ValueChanged(bool enabled)
{
this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(200);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(200);
base.OnHoverLost(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Content.ScaleTo(0.9f, 4000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
public IEnumerable<string> FilterTerms => new[] { Text };
public bool MatchingFilter
{
set
{
this.FadeTo(value ? 1 : 0);
}
}
}
}

View File

@ -12,13 +12,16 @@ namespace osu.Game.Online.API.Requests
public Action<float> DownloadProgressed;
public DownloadBeatmapSetRequest(BeatmapSetInfo set)
private readonly bool noVideo;
public DownloadBeatmapSetRequest(BeatmapSetInfo set, bool noVideo)
{
this.noVideo = noVideo;
BeatmapSet = set;
Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total);
}
protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download";
protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
}
}

View File

@ -109,7 +109,7 @@ namespace osu.Game
dependencies.Cache(this);
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value);
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
}

View File

@ -5,6 +5,7 @@ using System;
using System.Diagnostics;
using System.Reflection;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Configuration;
using osu.Framework.Development;
using osu.Framework.Graphics;
@ -137,6 +138,10 @@ namespace osu.Game
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
BeatmapManager.DefaultBeatmap = defaultBeatmap;
// tracks play so loud our samples can't keep up.
// this adds a global reduction of track volume for the time being.
Audio.Track.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8));
Beatmap.ValueChanged += b =>
{
var trackLoaded = lastBeatmap?.TrackLoaded ?? false;

Some files were not shown because too many files have changed in this diff Show More