1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 04:02:59 +08:00

Merge from ppy/master

This commit is contained in:
TocoToucan 2017-10-10 21:07:36 +03:00
commit 8b01f8671f
49 changed files with 1649 additions and 600 deletions

View File

@ -10,6 +10,10 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestFixture]
public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
{
public TestCaseCatchPlayer() : base(typeof(CatchRuleset))
{
}
protected override Beatmap CreateBeatmap()
{
var beatmap = new Beatmap();

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(CatcherArea),
typeof(Catcher),
};
[BackgroundDependencyLoader]
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Tests
new CatchInputManager(rulesets.GetRuleset(2))
{
RelativeSizeAxes = Axes.Both,
Child = new CatcherArea
Child = new Catcher
{
RelativePositionAxes = Axes.Both,
RelativeSizeAxes = Axes.Both,

View File

@ -1,10 +1,12 @@
// 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.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
@ -15,11 +17,15 @@ namespace osu.Game.Rulesets.Catch.UI
{
protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content;
private readonly CatcherArea catcherArea;
private readonly Container catcherContainer;
private readonly Catcher catcher;
public CatchPlayfield()
: base(Axes.Y)
{
Container explodingFruitContainer;
Reversed.Value = true;
Size = new Vector2(1);
@ -33,16 +39,35 @@ namespace osu.Game.Rulesets.Catch.UI
{
RelativeSizeAxes = Axes.Both,
},
catcherArea = new CatcherArea
explodingFruitContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
catcherContainer = new Container
{
RelativeSizeAxes = Axes.X,
Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft,
Height = 0.3f
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 override void Add(DrawableHitObject h)
{
h.Depth = (float)h.HitObject.StartTime;
@ -50,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.UI
base.Add(h);
var fruit = (DrawableFruit)h;
fruit.CheckPosition = catcherArea.CheckIfWeCanCatch;
fruit.CheckPosition = CheckIfWeCanCatch;
}
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
@ -59,7 +84,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre;
Remove(judgedObject);
catcherArea.Add(judgedObject, screenPosition);
catcher.Add(judgedObject, screenPosition);
}
}
}

View File

@ -0,0 +1,193 @@
// 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

@ -1,229 +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 CatcherArea : Container
{
private Catcher catcher;
private Container explodingFruitContainer;
public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2;
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
explodingFruitContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
catcher = new Catcher
{
RelativePositionAxes = Axes.Both,
ExplodingFruitTarget = explodingFruitContainer,
Origin = Anchor.TopCentre,
X = 0.5f,
}
};
}
protected override void Update()
{
base.Update();
catcher.Size = new Vector2(DrawSize.Y);
}
private class Catcher : Container, IKeyBindingHandler<CatchAction>
{
private Texture texture;
private Container<DrawableHitObject> caughtFruit;
[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;
public Container ExplodingFruitTarget;
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;
((CatcherArea)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 AddToStack(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

@ -59,7 +59,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tests\TestCaseCatcher.cs" />
<Compile Include="Tests\TestCaseCatchPlayer.cs" />
<Compile Include="UI\CatcherArea.cs" />
<Compile Include="UI\Catcher.cs" />
<Compile Include="UI\CatchRulesetContainer.cs" />
<Compile Include="UI\CatchPlayfield.cs" />
<Compile Include="CatchRuleset.cs" />

View File

@ -10,7 +10,7 @@ using osu.Game.Tests.Visual;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Testing
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
internal class TestCaseManiaHitObjects : OsuTestCase

View File

@ -17,7 +17,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Timing;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Testing
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
internal class TestCaseManiaPlayfield : OsuTestCase

View File

@ -80,8 +80,8 @@
<Compile Include="Objects\Note.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ManiaInputManager.cs" />
<Compile Include="Testing\TestCaseManiaHitObjects.cs" />
<Compile Include="Testing\TestCaseManiaPlayfield.cs" />
<Compile Include="Tests\TestCaseManiaHitObjects.cs" />
<Compile Include="Tests\TestCaseManiaPlayfield.cs" />
<Compile Include="Timing\GravityScrollingContainer.cs" />
<Compile Include="Timing\ScrollingAlgorithm.cs" />
<Compile Include="UI\Column.cs" />

View File

@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public override bool RemoveWhenNotAlive => false;
public override bool DisplayJudgement => false;
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
{
this.sliderTick = sliderTick;

View File

@ -91,6 +91,9 @@ namespace osu.Game.Rulesets.Osu.UI
var osuJudgement = (OsuJudgement)judgement;
var osuObject = (OsuHitObject)judgedObject.HitObject;
if (!judgedObject.DisplayJudgement)
return;
DrawableOsuJudgement explosion = new DrawableOsuJudgement(osuJudgement)
{
Origin = Anchor.Centre,

View File

@ -55,14 +55,17 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
// Post processing step to transform hit objects with the same start time into strong hits
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
if (original.BeatmapInfo.RulesetInfoId == 3)
{
TaikoHitObject first = x.First();
if (x.Skip(1).Any())
first.IsStrong = true;
return first;
}).ToList();
// Post processing step to transform mania hit objects with the same start time into strong hits
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
{
TaikoHitObject first = x.First();
if (x.Skip(1).Any())
first.IsStrong = true;
return first;
}).ToList();
}
return converted;
}

View File

@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
FillMode = FillMode.Fit;
}
public override bool DisplayJudgement => false;
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -221,7 +221,7 @@ namespace osu.Game.Rulesets.Taiko.UI
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
if (judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
{
judgementContainer.Add(new DrawableTaikoJudgement(judgedObject, judgement)
{

View File

@ -58,6 +58,23 @@ namespace osu.Game.Beatmaps
ComboColors = original?.ComboColors ?? ComboColors;
HitObjects = original?.HitObjects ?? HitObjects;
Storyboard = original?.Storyboard ?? Storyboard;
if (original == null && Metadata == null)
{
// we may have no metadata in cases we weren't sourced from the database.
// let's fill it (and other related fields) so we don't need to null-check it in future usages.
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = @"Unknown",
Title = @"Unknown",
Author = @"Unknown Creator",
},
Version = @"Normal",
Difficulty = new BeatmapDifficulty()
};
}
}
}

View File

@ -31,6 +31,8 @@ namespace osu.Game.Beatmaps.Drawables
public Action<BeatmapInfo> HideDifficultyRequested;
public Action<BeatmapInfo> EditRequested;
public BeatmapSetHeader Header;
public List<BeatmapPanel> BeatmapPanels;
@ -87,7 +89,8 @@ namespace osu.Game.Beatmaps.Drawables
Alpha = 0,
GainedSelection = panelGainedSelection,
HideRequested = p => HideDifficultyRequested?.Invoke(p),
StartRequested = p => { StartRequested?.Invoke(p.Beatmap); },
StartRequested = p => StartRequested?.Invoke(p.Beatmap),
EditRequested = p => EditRequested?.Invoke(p.Beatmap),
RelativeSizeAxes = Axes.X,
}).ToList();

View File

@ -611,7 +611,7 @@ namespace osu.Game.Beatmaps.Formats
CommandTimelineGroup timelineGroup = null;
string line;
while ((line = stream.ReadLine()) != null)
while ((line = stream.ReadLine()?.Trim()) != null)
{
if (string.IsNullOrEmpty(line))
continue;

View File

@ -8,7 +8,7 @@ namespace osu.Game.Beatmaps.Timing
/// <summary>
/// The minimum duration required for a break to have any effect.
/// </summary>
private const double min_break_duration = 650;
public const double MIN_BREAK_DURATION = 650;
/// <summary>
/// The break start time.
@ -28,6 +28,6 @@ namespace osu.Game.Beatmaps.Timing
/// <summary>
/// Whether the break has any effect. Breaks that are too short are culled before they are added to the beatmap.
/// </summary>
public bool HasEffect => Duration >= min_break_duration;
public bool HasEffect => Duration >= MIN_BREAK_DURATION;
}
}
}

View File

@ -59,7 +59,7 @@ namespace osu.Game.Graphics.UserInterface
public class OsuTabItem : TabItem<T>, IHasAccentColour
{
protected readonly SpriteText Text;
private readonly Box box;
protected readonly Box Bar;
private Color4 accentColour;
public Color4 AccentColour
@ -77,13 +77,13 @@ namespace osu.Game.Graphics.UserInterface
private void fadeActive()
{
box.FadeIn(transition_length, Easing.OutQuint);
Bar.FadeIn(transition_length, Easing.OutQuint);
Text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeInactive()
{
box.FadeOut(transition_length, Easing.OutQuint);
Bar.FadeOut(transition_length, Easing.OutQuint);
Text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
@ -123,7 +123,7 @@ namespace osu.Game.Graphics.UserInterface
TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
box = new Box
Bar = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,

View File

@ -188,11 +188,11 @@ namespace osu.Game
GetToolbarHeight = () => ToolbarOffset,
Depth = -1
}, overlayContent.Add);
LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -2 }, mainContent.Add);
LoadComponentAsync(beatmapSetOverlay = new BeatmapSetOverlay { Depth = -2 }, mainContent.Add);
LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -3 }, mainContent.Add);
LoadComponentAsync(musicController = new MusicController
{
Depth = -3,
Depth = -4,
Position = new Vector2(0, Toolbar.HEIGHT),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
@ -200,7 +200,7 @@ namespace osu.Game
LoadComponentAsync(notificationOverlay = new NotificationOverlay
{
Depth = -3,
Depth = -4,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}, overlayContent.Add);

View File

@ -9,6 +9,9 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Game.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
namespace osu.Game.Overlays.BeatmapSet
{
@ -17,8 +20,11 @@ namespace osu.Game.Overlays.BeatmapSet
private const float height = 50;
private readonly UpdateableAvatar avatar;
private readonly ClickableArea clickableArea;
private readonly FillFlowContainer fields;
private UserProfileOverlay profile;
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
{
@ -31,6 +37,8 @@ namespace osu.Game.Overlays.BeatmapSet
var i = BeatmapSet.OnlineInfo;
avatar.User = i.Author;
clickableArea.Action = () => profile?.ShowUser(avatar.User);
fields.Children = new Drawable[]
{
new Field("made by", i.Author.Username, @"Exo2.0-RegularItalic"),
@ -58,11 +66,15 @@ namespace osu.Game.Overlays.BeatmapSet
Children = new Drawable[]
{
avatar = new UpdateableAvatar
clickableArea = new ClickableArea
{
Size = new Vector2(height),
AutoSizeAxes = Axes.Both,
CornerRadius = 3,
Masking = true,
Child = avatar = new UpdateableAvatar
{
Size = new Vector2(height),
},
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.25f),
@ -80,6 +92,13 @@ namespace osu.Game.Overlays.BeatmapSet
};
}
[BackgroundDependencyLoader(true)]
private void load(UserProfileOverlay profile)
{
this.profile = profile;
clickableArea.Action = () => profile?.ShowUser(avatar.User);
}
private class Field : FillFlowContainer
{
public Field(string first, string second, string secondFont)
@ -103,5 +122,10 @@ namespace osu.Game.Overlays.BeatmapSet
};
}
}
private class ClickableArea : OsuClickableContainer, IHasTooltip
{
public string TooltipText => @"View Profile";
}
}
}

View File

@ -1,7 +1,6 @@
// 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;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Containers;
@ -165,10 +164,8 @@ namespace osu.Game.Overlays
wavesContainer.Height = Math.Max(0, DrawHeight - (contentContainer.DrawHeight - contentContainer.Y));
}
private class Wave : Container, IStateful<Visibility>
private class Wave : VisibilityContainer
{
public event Action<Visibility> StateChanged;
public float FinalPosition;
public Wave()
@ -183,13 +180,7 @@ namespace osu.Game.Overlays
Radius = 20f,
};
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
},
};
Child = new Box { RelativeSizeAxes = Axes.Both };
}
protected override void Update()
@ -201,28 +192,8 @@ namespace osu.Game.Overlays
Height = Parent.Parent.DrawSize.Y * 1.5f;
}
private Visibility state;
public Visibility State
{
get { return state; }
set
{
state = value;
switch (value)
{
case Visibility.Hidden:
this.MoveToY(Parent.Parent.DrawSize.Y, DISAPPEAR_DURATION, easing_hide);
break;
case Visibility.Visible:
this.MoveToY(FinalPosition, APPEAR_DURATION, easing_show);
break;
}
StateChanged?.Invoke(State);
}
}
protected override void PopIn() => this.MoveToY(FinalPosition, APPEAR_DURATION, easing_show);
protected override void PopOut() => this.MoveToY(Parent.Parent.DrawSize.Y, DISAPPEAR_DURATION, easing_hide);
}
}
}

View File

@ -25,6 +25,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// </summary>
public virtual Color4 AccentColour { get; set; } = Color4.Gray;
/// <summary>
/// Whether a visible judgement should be displayed when this representation is hit.
/// </summary>
public virtual bool DisplayJudgement => true;
protected DrawableHitObject(HitObject hitObject)
{
HitObject = hitObject;

View File

@ -51,6 +51,11 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
public readonly BindableInt Combo = new BindableInt();
/// <summary>
/// The current rank.
/// </summary>
public readonly Bindable<ScoreRank> Rank = new Bindable<ScoreRank>(ScoreRank.X);
/// <summary>
/// THe highest combo achieved by this score.
/// </summary>
@ -74,6 +79,7 @@ namespace osu.Game.Rulesets.Scoring
protected ScoreProcessor()
{
Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
Accuracy.ValueChanged += delegate { Rank.Value = rankFrom(Accuracy.Value); };
}
private ScoreRank rankFrom(double acc)
@ -101,6 +107,7 @@ namespace osu.Game.Rulesets.Scoring
Accuracy.Value = 1;
Health.Value = 1;
Combo.Value = 0;
Rank.Value = ScoreRank.X;
HighestCombo.Value = 0;
alreadyFailed = false;
@ -142,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring
score.Combo = Combo;
score.MaxCombo = HighestCombo;
score.Accuracy = Accuracy;
score.Rank = rankFrom(Accuracy);
score.Rank = Rank;
score.Date = DateTimeOffset.Now;
score.Health = Health;
}

View File

@ -8,11 +8,15 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Menus;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Screens;
using osu.Game.Screens.Edit.Screens.Compose;
using osu.Game.Screens.Edit.Screens.Design;
namespace osu.Game.Screens.Edit
{
@ -23,209 +27,88 @@ namespace osu.Game.Screens.Edit
internal override bool ShowOverlays => false;
private readonly Box bottomBackground;
private readonly Container screenContainer;
private EditorScreen currentScreen;
public Editor()
{
Add(new Container
EditorMenuBar menuBar;
SummaryTimeline timeline;
Children = new[]
{
RelativeSizeAxes = Axes.X,
Height = 40,
Children = new Drawable[]
new Container
{
new Box
Name = "Screen container",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 40, Bottom = 60 },
Child = screenContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("111")
},
new EditorMenuBar
Masking = true
}
},
new Container
{
Name = "Top bar",
RelativeSizeAxes = Axes.X,
Height = 40,
Child = menuBar = new EditorMenuBar
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
X = 100,
RelativeSizeAxes = Axes.Both,
Items = new[]
{
new EditorMenuBarItem("File")
new MenuItem("File")
{
Items = new[]
{
new EditorMenuItem("Clear all notes"),
new EditorMenuItem("Open difficulty..."),
new EditorMenuItem("Save"),
new EditorMenuItem("Create new difficulty..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Revert to saved"),
new EditorMenuItem("Revert to saved (full"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Test beatmap"),
new EditorMenuItem("Open AiMod"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Upload Beatmap..."),
new EditorMenuItem("Export package"),
new EditorMenuItem("Export map package"),
new EditorMenuItem("Import from..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Open song folder"),
new EditorMenuItem("Open .osu in Notepad"),
new EditorMenuItem("Open .osb in Notepad"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Exit", MenuItemType.Standard, Exit)
}
},
new EditorMenuBarItem("Edit")
{
Items = new[]
{
new EditorMenuItem("Undo"),
new EditorMenuItem("Redo"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Cut"),
new EditorMenuItem("Copy"),
new EditorMenuItem("Paste"),
new EditorMenuItem("Delete"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Select all"),
new EditorMenuItem("Clone"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Reverse selection"),
new EditorMenuItem("Flip horizontally"),
new EditorMenuItem("Flip vertically"),
new EditorMenuItem("Rotate 90deg clockwise"),
new EditorMenuItem("Rotate 90deg anticlockwise"),
new EditorMenuItem("Rotate by..."),
new EditorMenuItem("Scale by..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Reset selected objects' samples"),
new EditorMenuItem("Reset all samples", MenuItemType.Destructive),
new EditorMenuItem("Reset combo colours", MenuItemType.Destructive),
new EditorMenuItem("Reset breaks", MenuItemType.Destructive),
new EditorMenuItemSpacer(),
new EditorMenuItem("Nudge backward"),
new EditorMenuItem("Nudge forward")
}
},
new EditorMenuBarItem("View")
{
Items = new[]
{
new EditorMenuItem("Compose"),
new EditorMenuItem("Design"),
new EditorMenuItem("Timing"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Song setup..."),
new EditorMenuItem("Timing setup..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Volume"),
new EditorMenuItem("Grid level"),
new EditorMenuItem("Show video"),
new EditorMenuItem("Show sample name"),
new EditorMenuItem("Snaking sliders"),
new EditorMenuItem("Hit animations"),
new EditorMenuItem("Follow points"),
new EditorMenuItem("Stacking")
}
},
new EditorMenuBarItem("Compose")
{
Items = new[]
{
new EditorMenuItem("Snap divisor"),
new EditorMenuItem("Audio rate"),
new EditorMenuItem("Grid snapping"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Create polygon cricles..."),
new EditorMenuItem("Convert slider to stream"),
new EditorMenuItem("Enable live mapping mode"),
new EditorMenuItem("Sample import")
}
},
new EditorMenuBarItem("Design")
{
Items = new[]
{
new EditorMenuItem("Move all elements in time...")
}
},
new EditorMenuBarItem("Timing")
{
Items = new[]
{
new EditorMenuItem("Time signature"),
new EditorMenuItem("Metronome clicks"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Add timing section"),
new EditorMenuItem("Add inheriting section"),
new EditorMenuItem("Reset current section"),
new EditorMenuItem("Delete timing section"),
new EditorMenuItem("Resnap current section"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Timing setup..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Resnap all notes", MenuItemType.Destructive),
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
new EditorMenuItem("Recalculate slider lengths", MenuItemType.Destructive),
new EditorMenuItem("Delete all timing sections", MenuItemType.Destructive),
new EditorMenuItemSpacer(),
new EditorMenuItem("Set current position as preview point")
}
},
new EditorMenuBarItem("Web")
{
Items = new[]
{
new EditorMenuItem("This Beatmap's information page"),
new EditorMenuItem("This Beatmap's thread"),
new EditorMenuItem("Quick reply")
}
},
new EditorMenuBarItem("Help")
{
Items = new[]
{
new EditorMenuItem("Show in-game help"),
new EditorMenuItem("View FAQ")
}
}
}
}
}
});
SummaryTimeline summaryTimeline;
Add(new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = 60,
Children = new Drawable[]
},
new Container
{
bottomBackground = new Box { RelativeSizeAxes = Axes.Both },
new Container
Name = "Bottom bar",
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = 60,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 10 },
Child = new FillFlowContainer
bottomBackground = new Box { RelativeSizeAxes = Axes.Both },
new Container
{
Name = "Bottom bar",
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Children = new[]
Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 10 },
Child = new FillFlowContainer
{
summaryTimeline = new SummaryTimeline
Name = "Bottom bar",
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Children = new[]
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.65f
timeline = new SummaryTimeline
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.65f
}
}
}
}
}
}
});
},
};
summaryTimeline.Beatmap.BindTo(Beatmap);
timeline.Beatmap.BindTo(Beatmap);
menuBar.Mode.ValueChanged += onModeChanged;
}
[BackgroundDependencyLoader]
@ -234,6 +117,27 @@ namespace osu.Game.Screens.Edit
bottomBackground.Colour = colours.Gray2;
}
private void onModeChanged(EditorScreenMode mode)
{
currentScreen?.Exit();
switch (mode)
{
case EditorScreenMode.Compose:
currentScreen = new Compose();
break;
case EditorScreenMode.Design:
currentScreen = new Design();
break;
default:
currentScreen = new EditorScreen();
break;
}
currentScreen.Beatmap.BindTo(Beatmap);
screenContainer.Add(currentScreen);
}
protected override void OnResuming(Screen last)
{
Beatmap.Value.Track?.Stop();

View File

@ -11,16 +11,42 @@ using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Configuration;
using osu.Game.Screens.Edit.Screens;
namespace osu.Game.Screens.Edit.Menus
{
public class EditorMenuBar : OsuMenu
{
public readonly Bindable<EditorScreenMode> Mode = new Bindable<EditorScreenMode>();
public EditorMenuBar()
: base(Direction.Horizontal, true)
{
ItemsContainer.Padding = new MarginPadding(0);
BackgroundColour = Color4.Transparent;
RelativeSizeAxes = Axes.X;
MaskingContainer.CornerRadius = 0;
ItemsContainer.Padding = new MarginPadding { Left = 100 };
BackgroundColour = OsuColour.FromHex("111");
ScreenSelectionTabControl tabControl;
AddRangeInternal(new Drawable[]
{
tabControl = new ScreenSelectionTabControl
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
X = -15
}
});
Mode.BindTo(tabControl.Current);
}
protected override void LoadComplete()
{
base.LoadComplete();
Mode.TriggerChange();
}
protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu();
@ -29,27 +55,35 @@ namespace osu.Game.Screens.Edit.Menus
private class DrawableEditorBarMenuItem : DrawableOsuMenuItem
{
private Color4 openedForegroundColour;
private Color4 openedBackgroundColour;
private BackgroundBox background;
public DrawableEditorBarMenuItem(MenuItem item)
: base(item)
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;
StateChanged += stateChanged;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
ForegroundColour = ForegroundColourHover = colours.BlueLight;
BackgroundColour = BackgroundColourHover = Color4.Transparent;
openedForegroundColour = Color4.White;
openedBackgroundColour = colours.Gray3;
ForegroundColour = colours.BlueLight;
BackgroundColour = Color4.Transparent;
ForegroundColourHover = Color4.White;
BackgroundColourHover = colours.Gray3;
}
public override void SetFlowDirection(Direction direction)
{
AutoSizeAxes = Axes.Both;
}
protected override void UpdateBackgroundColour()
{
if (State == MenuItemState.Selected)
Background.FadeColour(openedBackgroundColour);
Background.FadeColour(BackgroundColourHover);
else
base.UpdateBackgroundColour();
}
@ -57,24 +91,58 @@ namespace osu.Game.Screens.Edit.Menus
protected override void UpdateForegroundColour()
{
if (State == MenuItemState.Selected)
Foreground.FadeColour(openedForegroundColour);
Foreground.FadeColour(ForegroundColourHover);
else
base.UpdateForegroundColour();
}
protected override Drawable CreateBackground() => new Container
private void stateChanged(MenuItemState newState)
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Child = new Container
if (newState == MenuItemState.Selected)
background.Expand();
else
background.Contract();
}
protected override Drawable CreateBackground() => background = new BackgroundBox();
protected override DrawableOsuMenuItem.TextContainer CreateTextContainer() => new TextContainer();
private new class TextContainer : DrawableOsuMenuItem.TextContainer
{
public TextContainer()
{
RelativeSizeAxes = Axes.Both,
Height = 2,
Masking = true,
CornerRadius = 4,
Child = new Box { RelativeSizeAxes = Axes.Both }
NormalText.TextSize = BoldText.TextSize = 14;
NormalText.Margin = BoldText.Margin = new MarginPadding { Horizontal = 10, Vertical = MARGIN_VERTICAL };
}
};
}
private class BackgroundBox : CompositeDrawable
{
private readonly Container innerBackground;
public BackgroundBox()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
InternalChild = innerBackground = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
Child = new Box { RelativeSizeAxes = Axes.Both }
};
}
/// <summary>
/// Expands the background such that it doesn't show the bottom corners.
/// </summary>
public void Expand() => innerBackground.Height = 2;
/// <summary>
/// Contracts the background such that it shows the bottom corners.
/// </summary>
public void Contract() => innerBackground.Height = 1;
}
}
private class SubMenu : OsuMenu

View File

@ -1,15 +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.UserInterface;
namespace osu.Game.Screens.Edit.Menus
{
public class EditorMenuBarItem : MenuItem
{
public EditorMenuBarItem(string text)
: base(text)
{
}
}
}

View File

@ -0,0 +1,75 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Screens;
using OpenTK;
namespace osu.Game.Screens.Edit.Menus
{
public class ScreenSelectionTabControl : OsuTabControl<EditorScreenMode>
{
public ScreenSelectionTabControl()
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
TabContainer.RelativeSizeAxes &= ~Axes.X;
TabContainer.AutoSizeAxes = Axes.X;
TabContainer.Padding = new MarginPadding();
Add(new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = 1,
Colour = Color4.White.Opacity(0.2f),
});
Current.Value = EditorScreenMode.Compose;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Yellow;
}
protected override Dropdown<EditorScreenMode> CreateDropdown() => null;
protected override TabItem<EditorScreenMode> CreateTabItem(EditorScreenMode value) => new TabItem(value);
private class TabItem : OsuTabItem
{
private const float transition_length = 250;
public TabItem(EditorScreenMode value)
: base(value)
{
Text.Margin = new MarginPadding();
Text.Anchor = Anchor.CentreLeft;
Text.Origin = Anchor.CentreLeft;
}
protected override void OnActivated()
{
base.OnActivated();
Bar.ScaleTo(new Vector2(1, 5), transition_length, Easing.OutQuint);
}
protected override void OnDeactivated()
{
base.OnDeactivated();
Bar.ScaleTo(Vector2.One, transition_length, Easing.OutQuint);
}
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Screens.Edit.Screens.Compose
{
public class Compose : EditorScreen
{
public Compose()
{
Children = new[]
{
new Container
{
Name = "Timeline",
RelativeSizeAxes = Axes.X,
Height = 110,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.5f)
},
new Container
{
Name = "Content",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 17, Vertical = 10 }
}
}
}
};
}
}
}

View File

@ -0,0 +1,52 @@
// 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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
namespace osu.Game.Screens.Edit.Screens.Design
{
internal class Design : EditorScreen
{
public Design()
{
Add(new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.35f
},
new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.5f
},
new Container
{
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
Child = new OsuSpriteText { Text = "Design screen" }
}
}
}
}
});
}
}
}

View File

@ -0,0 +1,41 @@
// 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.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
namespace osu.Game.Screens.Edit.Screens
{
public class EditorScreen : Container
{
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
protected override Container<Drawable> Content => content;
private readonly Container content;
public EditorScreen()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
InternalChild = content = new Container { RelativeSizeAxes = Axes.Both };
}
protected override void LoadComplete()
{
base.LoadComplete();
this.FadeTo(0)
.Then()
.FadeTo(1f, 250, Easing.OutQuint);
}
public void Exit()
{
this.FadeOut(250).Expire();
}
}
}

View File

@ -0,0 +1,19 @@
// 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;
namespace osu.Game.Screens.Edit.Screens
{
public enum EditorScreenMode
{
[Description("setup")]
SongSetup,
[Description("compose")]
Compose,
[Description("design")]
Design,
[Description("timing")]
Timing,
}
}

View File

@ -0,0 +1,103 @@
// 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.Containers;
using osu.Framework.Graphics;
using OpenTK;
using osu.Game.Graphics.Containers;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class ArrowsOverlay : VisibilityContainer
{
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private const int glow_icon_size = 60;
private const int glow_icon_blur_sigma = 10;
private const float glow_icon_final_offset = 0.22f;
private const float glow_icon_offscreen_offset = 0.6f;
private const int blurred_icon_blur_sigma = 20;
private const int blurred_icon_size = 130;
private const float blurred_icon_final_offset = 0.35f;
private const float blurred_icon_offscreen_offset = 0.7f;
private readonly GlowIcon leftGlowIcon;
private readonly GlowIcon rightGlowIcon;
private readonly BlurredIcon leftBlurredIcon;
private readonly BlurredIcon rightBlurredIcon;
public ArrowsOverlay()
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
leftGlowIcon = new GlowIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
X = -glow_icon_offscreen_offset,
Icon = Graphics.FontAwesome.fa_chevron_right,
BlurSigma = new Vector2(glow_icon_blur_sigma),
Size = new Vector2(glow_icon_size),
},
rightGlowIcon = new GlowIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
X = glow_icon_offscreen_offset,
Icon = Graphics.FontAwesome.fa_chevron_left,
BlurSigma = new Vector2(glow_icon_blur_sigma),
Size = new Vector2(glow_icon_size),
},
new ParallaxContainer
{
ParallaxAmount = -0.02f,
Children = new Drawable[]
{
leftBlurredIcon = new BlurredIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Alpha = 0.7f,
X = -blurred_icon_offscreen_offset,
Icon = Graphics.FontAwesome.fa_chevron_right,
BlurSigma = new Vector2(blurred_icon_blur_sigma),
Size = new Vector2(blurred_icon_size),
},
rightBlurredIcon = new BlurredIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
Alpha = 0.7f,
X = blurred_icon_offscreen_offset,
Icon = Graphics.FontAwesome.fa_chevron_left,
BlurSigma = new Vector2(blurred_icon_blur_sigma),
Size = new Vector2(blurred_icon_size),
},
}
}
};
}
protected override void PopIn()
{
leftGlowIcon.MoveToX(-glow_icon_final_offset, fade_duration, Easing.OutQuint);
rightGlowIcon.MoveToX(glow_icon_final_offset, fade_duration, Easing.OutQuint);
leftBlurredIcon.MoveToX(-blurred_icon_final_offset, fade_duration, Easing.OutQuint);
rightBlurredIcon.MoveToX(blurred_icon_final_offset, fade_duration, Easing.OutQuint);
}
protected override void PopOut()
{
leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, fade_duration, Easing.OutQuint);
rightGlowIcon.MoveToX(glow_icon_offscreen_offset, fade_duration, Easing.OutQuint);
leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint);
rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint);
}
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class BlurredIcon : BufferedContainer
{
private readonly SpriteIcon icon;
public FontAwesome Icon
{
set { icon.Icon = value; }
get { return icon.Icon; }
}
public override Vector2 Size
{
set
{
icon.Size = value;
base.Size = value + BlurSigma * 2.5f;
ForceRedraw();
}
get { return base.Size; }
}
public BlurredIcon()
{
RelativePositionAxes = Axes.X;
CacheDrawnFrameBuffer = true;
Child = icon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Shadow = false,
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.BlueLighter;
}
}
}

View File

@ -0,0 +1,151 @@
// 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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Scoring;
using System.Collections.Generic;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class BreakOverlay : Container
{
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private const float remaining_time_container_max_size = 0.3f;
private const int vertical_margin = 25;
private List<BreakPeriod> breaks;
public List<BreakPeriod> Breaks
{
set
{
breaks = value;
initializeBreaks();
}
get
{
return breaks;
}
}
private readonly bool letterboxing;
private readonly LetterboxOverlay letterboxOverlay;
private readonly Container remainingTimeAdjustmentBox;
private readonly Container remainingTimeBox;
private readonly RemainingTimeCounter remainingTimeCounter;
private readonly InfoContainer info;
private readonly ArrowsOverlay arrowsOverlay;
public BreakOverlay(bool letterboxing)
{
this.letterboxing = letterboxing;
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
letterboxOverlay = new LetterboxOverlay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
remainingTimeAdjustmentBox = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Width = 0,
Child = remainingTimeBox = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Height = 8,
CornerRadius = 4,
Masking = true,
Child = new Box { RelativeSizeAxes = Axes.Both }
}
},
remainingTimeCounter = new RemainingTimeCounter
{
Anchor = Anchor.Centre,
Origin = Anchor.BottomCentre,
Margin = new MarginPadding { Bottom = vertical_margin },
},
info = new InfoContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding { Top = vertical_margin },
},
arrowsOverlay = new ArrowsOverlay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
};
}
private void initializeBreaks()
{
FinishTransforms(true);
Scheduler.CancelDelayedTasks();
if (breaks == null)
return;
foreach (var b in breaks)
{
if (!b.HasEffect)
continue;
using (BeginAbsoluteSequence(b.StartTime))
{
Schedule(() => onBreakIn(b));
using (BeginDelayedSequence(b.Duration - fade_duration))
Schedule(onBreakOut);
}
}
}
private void onBreakIn(BreakPeriod b)
{
if (letterboxing)
letterboxOverlay.Show();
remainingTimeAdjustmentBox
.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint)
.Delay(b.Duration - fade_duration)
.ResizeWidthTo(0);
remainingTimeBox
.ResizeWidthTo(0, b.Duration - fade_duration)
.Then()
.ResizeWidthTo(1);
remainingTimeCounter.StartCounting(b.EndTime);
remainingTimeCounter.Show();
info.Show();
arrowsOverlay.Show();
}
private void onBreakOut()
{
if (letterboxing)
letterboxOverlay.Hide();
remainingTimeCounter.Hide();
info.Hide();
arrowsOverlay.Hide();
}
public void BindProcessor(ScoreProcessor processor)
{
info.AccuracyDisplay.Current.BindTo(processor.Accuracy);
info.GradeDisplay.Current.BindTo(processor.Rank);
}
}
}

View File

@ -0,0 +1,65 @@
// 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.Containers;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using OpenTK;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class GlowIcon : Container
{
private readonly SpriteIcon spriteIcon;
private readonly BlurredIcon blurredIcon;
public override Vector2 Size
{
set
{
blurredIcon.Size = spriteIcon.Size = value;
blurredIcon.ForceRedraw();
}
get { return base.Size; }
}
public Vector2 BlurSigma
{
set { blurredIcon.BlurSigma = value; }
get { return blurredIcon.BlurSigma; }
}
public FontAwesome Icon
{
set { spriteIcon.Icon = blurredIcon.Icon = value; }
get { return spriteIcon.Icon; }
}
public GlowIcon()
{
RelativePositionAxes = Axes.X;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
blurredIcon = new BlurredIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
spriteIcon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Shadow = false,
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
blurredIcon.Colour = colours.Blue;
}
}
}

View File

@ -0,0 +1,58 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class InfoContainer : VisibilityContainer
{
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
public PercentageInfoLine AccuracyDisplay;
public InfoLine<int> RankDisplay;
public InfoLine<ScoreRank> GradeDisplay;
public InfoContainer()
{
AutoSizeAxes = Axes.Both;
Child = new FillFlowContainer
{
Direction = FillDirection.Vertical,
Spacing = new Vector2(5),
Children = new Drawable[]
{
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "current progress".ToUpper(),
TextSize = 15,
Font = "Exo2.0-Black",
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
AccuracyDisplay = new PercentageInfoLine("Accuracy"),
RankDisplay = new InfoLine<int>("Rank"),
GradeDisplay = new InfoLine<ScoreRank>("Grade"),
},
}
},
};
}
protected override void PopIn() => this.FadeIn(fade_duration);
protected override void PopOut() => this.FadeOut(fade_duration);
}
}

View File

@ -0,0 +1,82 @@
// 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.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class InfoLine<T> : Container
where T : struct
{
private const int margin = 2;
public Bindable<T> Current = new Bindable<T>();
private readonly OsuSpriteText text;
private readonly OsuSpriteText valueText;
private readonly string prefix;
public InfoLine(string name, string prefix = @"")
{
this.prefix = prefix;
AutoSizeAxes = Axes.Y;
Children = new Drawable[]
{
text = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Text = name,
TextSize = 17,
Margin = new MarginPadding { Right = margin }
},
valueText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
Text = prefix + @"-",
TextSize = 17,
Font = "Exo2.0-Bold",
Margin = new MarginPadding { Left = margin }
}
};
Current.ValueChanged += currentValueChanged;
}
private void currentValueChanged(T newValue)
{
var newText = prefix + Format(newValue);
if (valueText.Text == newText)
return;
valueText.Text = newText;
}
protected virtual string Format(T count) => count.ToString();
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
text.Colour = colours.Yellow;
valueText.Colour = colours.YellowLight;
}
}
public class PercentageInfoLine : InfoLine<double>
{
public PercentageInfoLine(string name, string prefix = "") : base(name, prefix)
{
}
protected override string Format(double count) => $@"{count:P2}";
}
}

View File

@ -0,0 +1,67 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class LetterboxOverlay : VisibilityContainer
{
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private const int height = 350;
private static readonly Color4 transparent_black = new Color4(0, 0, 0, 0);
public LetterboxOverlay()
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
new Container
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
RelativeSizeAxes = Axes.X,
Height = height,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = new ColourInfo
{
TopLeft = Color4.Black,
TopRight = Color4.Black,
BottomLeft = transparent_black,
BottomRight = transparent_black,
}
}
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = height,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = new ColourInfo
{
TopLeft = transparent_black,
TopRight = transparent_black,
BottomLeft = Color4.Black,
BottomRight = Color4.Black,
}
}
}
};
}
protected override void PopIn() => this.FadeIn(fade_duration);
protected override void PopOut() => this.FadeOut(fade_duration);
}
}

View File

@ -0,0 +1,65 @@
// 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.Containers;
using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics;
using System;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Screens.Play.BreaksOverlay
{
public class RemainingTimeCounter : VisibilityContainer
{
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private readonly OsuSpriteText counter;
private int? previousSecond;
private double endTime;
private bool isCounting;
public RemainingTimeCounter()
{
AutoSizeAxes = Axes.Both;
Child = counter = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = 33,
Font = "Venera",
};
}
public void StartCounting(double endTime)
{
this.endTime = endTime;
isCounting = true;
}
protected override void Update()
{
base.Update();
if (isCounting)
{
var currentTime = Clock.CurrentTime;
if (currentTime < endTime)
{
int currentSecond = (int)Math.Ceiling((endTime - Clock.CurrentTime) / 1000.0);
if (currentSecond != previousSecond)
{
counter.Text = currentSecond.ToString();
previousSecond = currentSecond;
}
}
else isCounting = false;
}
}
protected override void PopIn() => this.FadeIn(fade_duration);
protected override void PopOut() => this.FadeOut(fade_duration);
}
}

View File

@ -24,6 +24,7 @@ using osu.Game.Screens.Ranking;
using osu.Framework.Audio.Sample;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Screens.Play.BreaksOverlay;
using osu.Game.Storyboards.Drawables;
using OpenTK.Graphics;
@ -69,6 +70,7 @@ namespace osu.Game.Screens.Play
#endregion
private BreakOverlay breakOverlay;
private Container storyboardContainer;
private DrawableStoryboard storyboard;
@ -179,16 +181,20 @@ namespace osu.Game.Screens.Play
{
RelativeSizeAxes = Axes.Both,
Clock = offsetClock,
Children = new Drawable[]
{
RulesetContainer,
}
Child = RulesetContainer,
},
hudOverlay = new HUDOverlay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
breakOverlay = new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Clock = decoupledClock,
Breaks = beatmap.Breaks
},
}
},
failOverlay = new FailOverlay
@ -222,6 +228,8 @@ namespace osu.Game.Screens.Play
hudOverlay.ModDisplay.Current.BindTo(working.Mods);
breakOverlay.BindProcessor(scoreProcessor);
// Bind ScoreProcessor to ourselves
scoreProcessor.AllJudged += onCompletion;
scoreProcessor.Failed += onFail;

View File

@ -177,6 +177,8 @@ namespace osu.Game.Screens.Select
public Action<BeatmapSetInfo> RestoreRequested;
public Action<BeatmapInfo> EditRequested;
public Action<BeatmapInfo> HideDifficultyRequested;
public void SelectNext(int direction = 1, bool skipDifficulties = true)
@ -347,6 +349,7 @@ namespace osu.Game.Screens.Select
StartRequested = b => StartRequested?.Invoke(),
DeleteRequested = b => DeleteRequested?.Invoke(b),
RestoreHiddenRequested = s => RestoreRequested?.Invoke(s),
EditRequested = b => EditRequested?.Invoke(b),
HideDifficultyRequested = b => HideDifficultyRequested?.Invoke(b),
State = BeatmapGroupState.Collapsed
};

View File

@ -19,6 +19,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Select.Options;
namespace osu.Game.Screens.Select
@ -108,6 +109,7 @@ namespace osu.Game.Screens.Select
BeatmapsChanged = carouselBeatmapsLoaded,
DeleteRequested = promptDelete,
RestoreRequested = s => { foreach (var b in s.Beatmaps) manager.Restore(b); },
EditRequested = editRequested,
HideDifficultyRequested = b => manager.Hide(b),
StartRequested = () => carouselRaisedStart(),
});
@ -195,6 +197,12 @@ namespace osu.Game.Screens.Select
carousel.AllowSelection = !Beatmap.Disabled;
}
private void editRequested(BeatmapInfo beatmap)
{
Beatmap.Value = manager.GetWorkingBeatmap(beatmap, Beatmap);
Push(new Editor());
}
private void onBeatmapRestored(BeatmapInfo b) => carousel.UpdateBeatmap(b);
private void onBeatmapHidden(BeatmapInfo b) => carousel.UpdateBeatmap(b);

View File

@ -0,0 +1,91 @@
// 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.Timing;
using osu.Game.Beatmaps.Timing;
using osu.Game.Screens.Play.BreaksOverlay;
using System.Collections.Generic;
namespace osu.Game.Tests.Visual
{
internal class TestCaseBreakOverlay : OsuTestCase
{
public override string Description => @"Tests breaks behavior";
private readonly BreakOverlay breakOverlay;
public TestCaseBreakOverlay()
{
Clock = new FramedClock();
Child = breakOverlay = new BreakOverlay(true);
AddStep("2s break", () => startBreak(2000));
AddStep("5s break", () => startBreak(5000));
AddStep("10s break", () => startBreak(10000));
AddStep("15s break", () => startBreak(15000));
AddStep("2s, 2s", startMultipleBreaks);
AddStep("0.5s, 0.7s, 1s, 2s", startAnotherMultipleBreaks);
}
private void startBreak(double duration)
{
breakOverlay.Breaks = new List<BreakPeriod>
{
new BreakPeriod
{
StartTime = Clock.CurrentTime,
EndTime = Clock.CurrentTime + duration,
}
};
}
private void startMultipleBreaks()
{
double currentTime = Clock.CurrentTime;
breakOverlay.Breaks = new List<BreakPeriod>
{
new BreakPeriod
{
StartTime = currentTime,
EndTime = currentTime + 2000,
},
new BreakPeriod
{
StartTime = currentTime + 4000,
EndTime = currentTime + 6000,
}
};
}
private void startAnotherMultipleBreaks()
{
double currentTime = Clock.CurrentTime;
breakOverlay.Breaks = new List<BreakPeriod>
{
new BreakPeriod // Duration is less than 650 - too short to appear
{
StartTime = currentTime,
EndTime = currentTime + 500,
},
new BreakPeriod
{
StartTime = currentTime + 1500,
EndTime = currentTime + 2200,
},
new BreakPeriod
{
StartTime = currentTime + 3200,
EndTime = currentTime + 4200,
},
new BreakPeriod
{
StartTime = currentTime + 5200,
EndTime = currentTime + 7200,
}
};
}
}
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Graphics.Cursor;
namespace osu.Game.Tests.Visual
{
@ -23,32 +24,32 @@ namespace osu.Game.Tests.Visual
public TestCaseContextMenu()
{
Add(container = new MyContextMenuContainer
Add(new OsuContextMenuContainer
{
Size = new Vector2(200),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
container = new MyContextMenuContainer
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Green,
}
}
});
Add(new AnotherContextMenuContainer
{
Size = new Vector2(200),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Children = new Drawable[]
{
new Box
Size = new Vector2(200),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Green,
}
},
new AnotherContextMenuContainer
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red,
Size = new Vector2(200),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red,
}
}
}
});

View File

@ -0,0 +1,47 @@
// 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 osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Screens;
namespace osu.Game.Tests.Visual
{
public class TestCaseEditor : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Editor), typeof(EditorScreen) };
private readonly Random rng;
private BeatmapManager beatmaps;
private OsuGameBase osuGame;
public TestCaseEditor()
{
rng = new Random(1337);
Add(new Editor());
AddStep("Next beatmap", nextBeatmap);
}
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGame, BeatmapManager beatmaps)
{
this.osuGame = osuGame;
this.beatmaps = beatmaps;
}
private void nextBeatmap()
{
var sets = beatmaps.GetAllUsableBeatmapSets();
if (sets.Count == 0)
return;
BeatmapInfo info = sets[rng.Next(0, sets.Count)].Beatmaps[0];
osuGame.Beatmap.Value = beatmaps.GetWorkingBeatmap(info);
}
}
}

View File

@ -1,7 +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 System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Menus;
@ -9,74 +13,82 @@ namespace osu.Game.Tests.Visual
{
public class TestCaseEditorMenuBar : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(EditorMenuBar), typeof(ScreenSelectionTabControl) };
public TestCaseEditorMenuBar()
{
Add(new EditorMenuBar
Add(new Container
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Height = 50,
Y = 50,
Items = new[]
Child = new EditorMenuBar
{
new EditorMenuBarItem("File")
RelativeSizeAxes = Axes.Both,
Items = new[]
{
Items = new[]
new MenuItem("File")
{
new EditorMenuItem("Clear All Notes"),
new EditorMenuItem("Open Difficulty..."),
new EditorMenuItem("Save"),
new EditorMenuItem("Create a new Difficulty..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Revert to Saved"),
new EditorMenuItem("Revert to Saved (Full)"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Test Beatmap"),
new EditorMenuItem("Open AiMod"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Upload Beatmap..."),
new EditorMenuItem("Export Package"),
new EditorMenuItem("Export Map Package"),
new EditorMenuItem("Import from..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Open Song Folder"),
new EditorMenuItem("Open .osu in Notepad"),
new EditorMenuItem("Open .osb in Notepad"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Exit"),
}
},
new EditorMenuBarItem("Timing")
{
Items = new[]
Items = new[]
{
new EditorMenuItem("Clear All Notes"),
new EditorMenuItem("Open Difficulty..."),
new EditorMenuItem("Save"),
new EditorMenuItem("Create a new Difficulty..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Revert to Saved"),
new EditorMenuItem("Revert to Saved (Full)"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Test Beatmap"),
new EditorMenuItem("Open AiMod"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Upload Beatmap..."),
new EditorMenuItem("Export Package"),
new EditorMenuItem("Export Map Package"),
new EditorMenuItem("Import from..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Open Song Folder"),
new EditorMenuItem("Open .osu in Notepad"),
new EditorMenuItem("Open .osb in Notepad"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Exit"),
}
},
new MenuItem("Timing")
{
new EditorMenuItem("Time Signature"),
new EditorMenuItem("Metronome Clicks"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Add Timing Section"),
new EditorMenuItem("Add Inheriting Section"),
new EditorMenuItem("Reset Current Section"),
new EditorMenuItem("Delete Timing Section"),
new EditorMenuItem("Resnap Current Section"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Timing Setup"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
new EditorMenuItemSpacer(),
new EditorMenuItem("Set Current Position as Preview Point"),
}
},
new EditorMenuBarItem("Testing")
{
Items = new[]
Items = new[]
{
new EditorMenuItem("Time Signature"),
new EditorMenuItem("Metronome Clicks"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Add Timing Section"),
new EditorMenuItem("Add Inheriting Section"),
new EditorMenuItem("Reset Current Section"),
new EditorMenuItem("Delete Timing Section"),
new EditorMenuItem("Resnap Current Section"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Timing Setup"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
new EditorMenuItemSpacer(),
new EditorMenuItem("Set Current Position as Preview Point"),
}
},
new MenuItem("Testing")
{
new EditorMenuItem("Item 1"),
new EditorMenuItem("Item 2"),
new EditorMenuItem("Item 3"),
}
},
Items = new[]
{
new EditorMenuItem("Item 1"),
new EditorMenuItem("Item 2"),
new EditorMenuItem("Item 3"),
}
},
}
}
});
}

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;
using System.IO;
using System.Linq;
using System.Text;
@ -18,32 +19,39 @@ namespace osu.Game.Tests.Visual
{
public class TestCasePlayer : OsuTestCase
{
private readonly Type ruleset;
protected Player Player;
private RulesetStore rulesets;
public override string Description => @"Showing everything to play the game.";
/// <summary>
/// Create a TestCase which runs through the Player screen.
/// </summary>
/// <param name="ruleset">An optional ruleset type which we want to target. If not provided we'll allow all rulesets to be tested.</param>
protected TestCasePlayer(Type ruleset)
{
this.ruleset = ruleset;
}
public TestCasePlayer()
{
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
this.rulesets = rulesets;
}
protected override void LoadComplete()
{
base.LoadComplete();
Add(new Box
{
RelativeSizeAxes = Framework.Graphics.Axes.Both,
Colour = Color4.Black,
});
var queryRulesets = rulesets.QueryRulesets(r=>true);
foreach (var r in queryRulesets)
AddStep(r.Name, () => loadPlayerFor(r));
string instantiation = ruleset?.AssemblyQualifiedName;
loadPlayerFor(queryRulesets.First());
foreach (var r in rulesets.QueryRulesets(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation)))
AddStep(r.Name, () => loadPlayerFor(r));
}
protected virtual Beatmap CreateBeatmap()

View File

@ -334,6 +334,14 @@
<Compile Include="Beatmaps\Formats\OsuLegacyDecoder.cs" />
<Compile Include="Beatmaps\IO\ArchiveReader.cs" />
<Compile Include="Beatmaps\IO\LegacyFilesystemReader.cs" />
<Compile Include="Screens\Play\BreaksOverlay\ArrowsOverlay.cs" />
<Compile Include="Screens\Play\BreaksOverlay\BlurredIcon.cs" />
<Compile Include="Screens\Play\BreaksOverlay\BreakOverlay.cs" />
<Compile Include="Screens\Play\BreaksOverlay\GlowIcon.cs" />
<Compile Include="Screens\Play\BreaksOverlay\InfoContainer.cs" />
<Compile Include="Screens\Play\BreaksOverlay\InfoLine.cs" />
<Compile Include="Screens\Play\BreaksOverlay\LetterboxOverlay.cs" />
<Compile Include="Screens\Play\BreaksOverlay\RemainingTimeCounter.cs" />
<Compile Include="Beatmaps\IO\OszArchiveReader.cs" />
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
<Compile Include="Beatmaps\RankStatus.cs" />
@ -678,10 +686,14 @@
<Compile Include="Screens\Edit\Components\Timelines\Summary\Visualisations\DurationVisualisation.cs" />
<Compile Include="Screens\Edit\Components\Timelines\Summary\Visualisations\PointVisualisation.cs" />
<Compile Include="Screens\Edit\Components\Timelines\Summary\SummaryTimeline.cs" />
<Compile Include="Screens\Edit\Screens\EditorScreenMode.cs" />
<Compile Include="Screens\Edit\Menus\EditorMenuBar.cs" />
<Compile Include="Screens\Edit\Menus\EditorMenuBarItem.cs" />
<Compile Include="Screens\Edit\Menus\EditorMenuItem.cs" />
<Compile Include="Screens\Edit\Menus\EditorMenuItemSpacer.cs" />
<Compile Include="Screens\Edit\Menus\ScreenSelectionTabControl.cs" />
<Compile Include="Screens\Edit\Screens\Design\Design.cs" />
<Compile Include="Screens\Edit\Screens\EditorScreen.cs" />
<Compile Include="Screens\Edit\Screens\Compose\Compose.cs" />
<Compile Include="Screens\Loader.cs" />
<Compile Include="Screens\Menu\Button.cs" />
<Compile Include="Screens\Menu\ButtonSystem.cs" />
@ -800,12 +812,14 @@
<Compile Include="Tests\Visual\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Tests\Visual\TestCaseBeatSyncedContainer.cs" />
<Compile Include="Tests\Visual\TestCaseBreadcrumbs.cs" />
<Compile Include="Tests\Visual\TestCaseBreakOverlay.cs" />
<Compile Include="Tests\Visual\TestCaseChatDisplay.cs" />
<Compile Include="Tests\Visual\TestCaseContextMenu.cs" />
<Compile Include="Tests\Visual\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\Visual\TestCaseDirect.cs" />
<Compile Include="Tests\Visual\TestCaseDrawableRoom.cs" />
<Compile Include="Tests\Visual\TestCaseDrawings.cs" />
<Compile Include="Tests\Visual\TestCaseEditor.cs" />
<Compile Include="Tests\Visual\TestCaseEditorMenuBar.cs" />
<Compile Include="Tests\Visual\TestCaseEditorSummaryTimeline.cs" />
<Compile Include="Tests\Visual\TestCaseGamefield.cs" />