mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 02:02:53 +08:00
Merge https://github.com/ppy/osu into osu-direct-search
This commit is contained in:
commit
84701846ec
@ -1 +1 @@
|
||||
Subproject commit 3ad1dd52ae511b816fb928f70ef811ec605c5c18
|
||||
Subproject commit 768a775b688d7a008d8933275b48ed0d2d491f12
|
@ -1 +1 @@
|
||||
Subproject commit b348c1e540edbb3325a8da9bca452c9dce2938d6
|
||||
Subproject commit 76656c51f281e7934159e9ed4414378fef24d130
|
@ -31,6 +31,10 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.17.1.0" newVersion="0.17.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
@ -49,10 +49,6 @@
|
||||
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@ -73,15 +69,19 @@
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\NuGet.Squirrel.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress, Version=0.17.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Squirrel, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll</HintPath>
|
||||
<Reference Include="Squirrel, Version=1.7.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\Squirrel.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
|
@ -7,7 +7,8 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net452" />
|
||||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" />
|
||||
<package id="NuGet.CommandLine" version="3.5.0" targetFramework="net452" developmentDependency="true" />
|
||||
<package id="NuGet.CommandLine" version="4.1.0" targetFramework="net452" developmentDependency="true" />
|
||||
<package id="SharpCompress" version="0.17.1" targetFramework="net452" />
|
||||
<package id="Splat" version="2.0.0" targetFramework="net452" />
|
||||
<package id="squirrel.windows" version="1.5.2" targetFramework="net452" />
|
||||
<package id="squirrel.windows" version="1.7.5" targetFramework="net452" />
|
||||
</packages>
|
11
osu.Desktop.Tests/app.config
Normal file
11
osu.Desktop.Tests/app.config
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
@ -37,8 +37,9 @@
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.6.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Reference Include="nunit.framework, Version=3.7.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@ -100,6 +101,7 @@
|
||||
<None Include="..\osu.licenseheader">
|
||||
<Link>osu.licenseheader</Link>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -5,7 +5,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
-->
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" />
|
||||
<package id="NUnit" version="3.6.1" targetFramework="net45" />
|
||||
<package id="NUnit" version="3.7.1" targetFramework="net45" />
|
||||
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
|
||||
|
206
osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
Normal file
206
osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
Normal file
@ -0,0 +1,206 @@
|
||||
// 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.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Lists;
|
||||
using System;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseBeatSyncedContainer : TestCase
|
||||
{
|
||||
public override string Description => @"Tests beat synced containers.";
|
||||
|
||||
private readonly MusicController mc;
|
||||
|
||||
public TestCaseBeatSyncedContainer()
|
||||
{
|
||||
Clock = new FramedClock();
|
||||
Clock.ProcessFrame();
|
||||
|
||||
Add(new BeatContainer
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
});
|
||||
|
||||
Add(mc = new MusicController
|
||||
{
|
||||
Origin = Anchor.TopRight,
|
||||
Anchor = Anchor.TopRight,
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
mc.ToggleVisibility();
|
||||
}
|
||||
|
||||
private class BeatContainer : BeatSyncedContainer
|
||||
{
|
||||
private const int flash_layer_heigth = 150;
|
||||
|
||||
private readonly InfoString timingPointCount;
|
||||
private readonly InfoString currentTimingPoint;
|
||||
private readonly InfoString beatCount;
|
||||
private readonly InfoString currentBeat;
|
||||
private readonly InfoString beatsPerMinute;
|
||||
private readonly InfoString adjustedBeatLength;
|
||||
private readonly InfoString timeUntilNextBeat;
|
||||
private readonly InfoString timeSinceLastBeat;
|
||||
|
||||
private readonly Box flashLayer;
|
||||
|
||||
public BeatContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Name = @"Info Layer",
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Bottom = flash_layer_heigth },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(150),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
timingPointCount = new InfoString(@"Timing points amount"),
|
||||
currentTimingPoint = new InfoString(@"Current timing point"),
|
||||
beatCount = new InfoString(@"Beats amount (in the current timing point)"),
|
||||
currentBeat = new InfoString(@"Current beat"),
|
||||
beatsPerMinute = new InfoString(@"BPM"),
|
||||
adjustedBeatLength = new InfoString(@"Adjusted beat length"),
|
||||
timeUntilNextBeat = new InfoString(@"Time until next beat"),
|
||||
timeSinceLastBeat = new InfoString(@"Time since last beat"),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = @"Color indicator",
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = flash_layer_heigth,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
flashLayer = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.White,
|
||||
Alpha = 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Beatmap.ValueChanged += delegate
|
||||
{
|
||||
timingPointCount.Value = 0;
|
||||
currentTimingPoint.Value = 0;
|
||||
beatCount.Value = 0;
|
||||
currentBeat.Value = 0;
|
||||
beatsPerMinute.Value = 0;
|
||||
adjustedBeatLength.Value = 0;
|
||||
timeUntilNextBeat.Value = 0;
|
||||
timeSinceLastBeat.Value = 0;
|
||||
};
|
||||
}
|
||||
|
||||
private SortedList<TimingControlPoint> timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints;
|
||||
private TimingControlPoint getNextTimingPoint(TimingControlPoint current)
|
||||
{
|
||||
if (timingPoints[timingPoints.Count - 1] == current)
|
||||
return current;
|
||||
|
||||
return timingPoints[timingPoints.IndexOf(current) + 1];
|
||||
}
|
||||
|
||||
private int calculateBeatCount(TimingControlPoint current)
|
||||
{
|
||||
if (timingPoints[timingPoints.Count - 1] == current)
|
||||
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);
|
||||
|
||||
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
timeUntilNextBeat.Value = TimeUntilNextBeat;
|
||||
timeSinceLastBeat.Value = TimeSinceLastBeat;
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||
{
|
||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||
|
||||
timingPointCount.Value = timingPoints.Count;
|
||||
currentTimingPoint.Value = timingPoints.IndexOf(timingPoint);
|
||||
beatCount.Value = calculateBeatCount(timingPoint);
|
||||
currentBeat.Value = beatIndex;
|
||||
beatsPerMinute.Value = 60000 / timingPoint.BeatLength;
|
||||
adjustedBeatLength.Value = timingPoint.BeatLength;
|
||||
|
||||
flashLayer.ClearTransforms();
|
||||
flashLayer.FadeTo(1);
|
||||
flashLayer.FadeTo(0, timingPoint.BeatLength);
|
||||
}
|
||||
}
|
||||
|
||||
private class InfoString : FillFlowContainer
|
||||
{
|
||||
private const int text_size = 20;
|
||||
private const int margin = 7;
|
||||
|
||||
private readonly OsuSpriteText valueText;
|
||||
|
||||
public double Value
|
||||
{
|
||||
set { valueText.Text = $"{value:G}"; }
|
||||
}
|
||||
|
||||
public InfoString(string header)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Direction = FillDirection.Horizontal;
|
||||
Add(new OsuSpriteText { Text = header + @": ", TextSize = text_size });
|
||||
Add(valueText = new OsuSpriteText() { TextSize = text_size });
|
||||
Margin = new MarginPadding(margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,10 +12,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Beatmap details in song select";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseBeatmapDetailArea()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new BeatmapDetailArea
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
|
@ -13,12 +13,10 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
|
||||
|
||||
private BeatmapDetails details;
|
||||
private readonly BeatmapDetails details;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseBeatmapDetails()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(details = new BeatmapDetails
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -41,7 +39,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
StarDifficulty = 5.3f,
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Ratings = Enumerable.Range(0,10),
|
||||
Ratings = Enumerable.Range(0, 10),
|
||||
Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6),
|
||||
Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6),
|
||||
},
|
||||
|
@ -13,10 +13,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Beatmap options in song select";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseBeatmapOptionsOverlay()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
var overlay = new BeatmapOptionsOverlay();
|
||||
|
||||
overlay.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, Color4.Purple, null, Key.Number1);
|
||||
|
@ -11,10 +11,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"breadcrumb > control";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseBreadcrumbs()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
BreadcrumbControl<BreadcrumbTab> c;
|
||||
Add(c = new BreadcrumbControl<BreadcrumbTab>
|
||||
{
|
||||
|
@ -11,10 +11,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Testing chat api and overlay";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseChatDisplay()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new ChatOverlay
|
||||
{
|
||||
State = Visibility.Visible
|
||||
|
105
osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
Normal file
105
osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
Normal file
@ -0,0 +1,105 @@
|
||||
// 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 OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseContextMenu : TestCase
|
||||
{
|
||||
public override string Description => @"Menu visible on right click";
|
||||
|
||||
private const int start_time = 0;
|
||||
private const int duration = 1000;
|
||||
|
||||
private readonly Container container;
|
||||
|
||||
public TestCaseContextMenu()
|
||||
{
|
||||
Add(container = new MyContextMenuContainer
|
||||
{
|
||||
Size = new Vector2(200),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Green,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Add(new AnotherContextMenuContainer
|
||||
{
|
||||
Size = new Vector2(200),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Red,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
using (container.BeginLoopedSequence())
|
||||
{
|
||||
container.MoveTo(new Vector2(0, 100), duration);
|
||||
using (container.BeginDelayedSequence(duration))
|
||||
{
|
||||
container.MoveTo(new Vector2(100, 100), duration);
|
||||
using (container.BeginDelayedSequence(duration))
|
||||
{
|
||||
container.MoveTo(new Vector2(100, 0), duration);
|
||||
using (container.BeginDelayedSequence(duration))
|
||||
container.MoveTo(Vector2.Zero, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyContextMenuContainer : Container, IHasContextMenu
|
||||
{
|
||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
||||
{
|
||||
new OsuContextMenuItem(@"Some option"),
|
||||
new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
||||
new OsuContextMenuItem(@"Another option"),
|
||||
new OsuContextMenuItem(@"Choose me please"),
|
||||
new OsuContextMenuItem(@"And me too"),
|
||||
new OsuContextMenuItem(@"Trying to fill"),
|
||||
new OsuContextMenuItem(@"Destructive option", MenuItemType.Destructive),
|
||||
};
|
||||
}
|
||||
|
||||
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
||||
{
|
||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
||||
{
|
||||
new OsuContextMenuItem(@"Simple option"),
|
||||
new OsuContextMenuItem(@"Simple very very long option"),
|
||||
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => ResizeWidthTo(Width * 2, 100, EasingTypes.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => ResizeHeightTo(Height * 2, 100, EasingTypes.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => ResizeWidthTo(Width / 2, 100, EasingTypes.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => ResizeHeightTo(Height / 2, 100, EasingTypes.OutQuint) },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -12,11 +12,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Display dialogs";
|
||||
|
||||
private DialogOverlay overlay;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseDialogOverlay()
|
||||
{
|
||||
base.Reset();
|
||||
DialogOverlay overlay;
|
||||
|
||||
Add(overlay = new DialogOverlay());
|
||||
|
||||
|
@ -16,9 +16,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
private DirectOverlay direct;
|
||||
private RulesetDatabase rulesets;
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
Add(direct = new DirectOverlay());
|
||||
newBeatmaps();
|
||||
|
@ -15,9 +15,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Select your favourite room";
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
DrawableRoom first;
|
||||
DrawableRoom second;
|
||||
@ -36,14 +36,28 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
});
|
||||
|
||||
first.Room.Name.Value = @"Great Room Right Here";
|
||||
first.Room.Host.Value = new User { Username = @"Naeferith", Id = 9492835, Country = new Country { FlagName = @"FR" }};
|
||||
first.Room.Host.Value = new User { Username = @"Naeferith", Id = 9492835, Country = new Country { FlagName = @"FR" } };
|
||||
first.Room.Status.Value = new RoomStatusOpen();
|
||||
first.Room.Beatmap.Value = new BeatmapMetadata { Title = @"Seiryu", Artist = @"Critical Crystal" };
|
||||
first.Room.Beatmap.Value = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Seiryu",
|
||||
Artist = @"Critical Crystal",
|
||||
},
|
||||
};
|
||||
|
||||
second.Room.Name.Value = @"Relax It's The Weekend";
|
||||
second.Room.Host.Value = new User { Username = @"peppy", Id = 2, Country = new Country { FlagName = @"AU" }};
|
||||
second.Room.Host.Value = new User { Username = @"peppy", Id = 2, Country = new Country { FlagName = @"AU" } };
|
||||
second.Room.Status.Value = new RoomStatusPlaying();
|
||||
second.Room.Beatmap.Value = new BeatmapMetadata { Title = @"ZAQ", Artist = @"Serendipity" };
|
||||
second.Room.Beatmap.Value = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Serendipity",
|
||||
Artist = @"ZAQ",
|
||||
},
|
||||
};
|
||||
|
||||
AddStep(@"change state", () =>
|
||||
{
|
||||
|
@ -12,10 +12,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => "Tournament drawings";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseDrawings()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new Drawings
|
||||
{
|
||||
TeamList = new TestTeamList(),
|
||||
|
@ -34,9 +34,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
List<HitObject> objects = new List<HitObject>();
|
||||
|
||||
|
@ -13,11 +13,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => "graph";
|
||||
|
||||
private BarGraph graph;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseGraph()
|
||||
{
|
||||
base.Reset();
|
||||
BarGraph graph;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
@ -30,7 +28,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
},
|
||||
};
|
||||
|
||||
AddStep("values from 1-10", () => graph.Values = Enumerable.Range(1,10).Select(i => (float)i));
|
||||
AddStep("values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Select(i => (float)i));
|
||||
AddStep("values from 1-100", () => graph.Values = Enumerable.Range(1, 100).Select(i => (float)i));
|
||||
AddStep("reversed values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Reverse().Select(i => (float)i));
|
||||
AddStep("Bottom to top", () => graph.Direction = BarDirection.BottomToTop);
|
||||
|
@ -29,15 +29,58 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
var rateAdjustClock = new StopwatchClock(true);
|
||||
framedClock = new FramedClock(rateAdjustClock);
|
||||
playbackSpeed.ValueChanged += delegate { rateAdjustClock.Rate = playbackSpeed.Value; };
|
||||
|
||||
playbackSpeed.TriggerChange();
|
||||
|
||||
AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle));
|
||||
AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider));
|
||||
AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
|
||||
|
||||
AddToggleStep(@"auto", state => { auto = state; loadHitobjects(mode); });
|
||||
|
||||
BasicSliderBar<double> sliderBar;
|
||||
Add(new Container
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SpriteText { Text = "Playback Speed" },
|
||||
sliderBar = new BasicSliderBar<double>
|
||||
{
|
||||
Width = 150,
|
||||
Height = 10,
|
||||
SelectionColor = Color4.Orange,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sliderBar.Current.BindTo(playbackSpeed);
|
||||
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
var clockAdjustContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = framedClock,
|
||||
Children = new[]
|
||||
{
|
||||
playfieldContainer = new Container { RelativeSizeAxes = Axes.Both },
|
||||
approachContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
};
|
||||
|
||||
Add(clockAdjustContainer);
|
||||
}
|
||||
|
||||
private HitObjectType mode = HitObjectType.Slider;
|
||||
|
||||
private readonly BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 };
|
||||
private Container playfieldContainer;
|
||||
private Container approachContainer;
|
||||
private readonly Container playfieldContainer;
|
||||
private readonly Container approachContainer;
|
||||
|
||||
private void load(HitObjectType mode)
|
||||
private void loadHitobjects(HitObjectType mode)
|
||||
{
|
||||
this.mode = mode;
|
||||
|
||||
@ -83,54 +126,6 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
playbackSpeed.TriggerChange();
|
||||
|
||||
AddStep(@"circles", () => load(HitObjectType.Circle));
|
||||
AddStep(@"slider", () => load(HitObjectType.Slider));
|
||||
AddStep(@"spinner", () => load(HitObjectType.Spinner));
|
||||
|
||||
AddToggleStep(@"auto", state => { auto = state; load(mode); });
|
||||
|
||||
BasicSliderBar<double> sliderBar;
|
||||
Add(new Container
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SpriteText { Text = "Playback Speed" },
|
||||
sliderBar = new BasicSliderBar<double>
|
||||
{
|
||||
Width = 150,
|
||||
Height = 10,
|
||||
SelectionColor = Color4.Orange,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sliderBar.Current.BindTo(playbackSpeed);
|
||||
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
var clockAdjustContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = framedClock,
|
||||
Children = new[]
|
||||
{
|
||||
playfieldContainer = new Container { RelativeSizeAxes = Axes.Both },
|
||||
approachContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
};
|
||||
|
||||
Add(clockAdjustContainer);
|
||||
}
|
||||
|
||||
private int depth;
|
||||
|
||||
private void add(DrawableOsuHitObject h)
|
||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
@ -19,10 +20,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Tests key counter";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseKeyCounter()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
KeyCounterCollection kc = new KeyCounterCollection
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
@ -54,7 +53,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SpriteText { Text = "FadeTime" },
|
||||
sliderBar =new TestSliderBar<int>
|
||||
sliderBar = new TestSliderBar<int>
|
||||
{
|
||||
Width = 150,
|
||||
Height = 10,
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"From song select";
|
||||
|
||||
private Leaderboard leaderboard;
|
||||
private readonly Leaderboard leaderboard;
|
||||
|
||||
private void newScores()
|
||||
{
|
||||
@ -207,10 +207,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
leaderboard.Scores = scores;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseLeaderboard()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(leaderboard = new Leaderboard
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -13,10 +13,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseManiaHitObjects : TestCase
|
||||
{
|
||||
public override void Reset()
|
||||
public TestCaseManiaHitObjects()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
|
@ -6,14 +6,16 @@ using osu.Framework.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Framework.Configuration;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -23,14 +25,12 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
protected override double TimePerAction => 200;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseManiaPlayfield()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) =>
|
||||
{
|
||||
Clear();
|
||||
Add(new ManiaPlayfield(cols, new List<TimingChange>())
|
||||
Add(new ManiaPlayfield(cols)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -39,37 +39,22 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
});
|
||||
};
|
||||
|
||||
Action<int, SpecialColumnPosition> createPlayfieldWithNotes = (cols, pos) =>
|
||||
const double start_time = 500;
|
||||
const double duration = 500;
|
||||
|
||||
Func<double, bool, SpeedAdjustmentContainer> createTimingChange = (time, gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
|
||||
{
|
||||
TimingPoint = { BeatLength = 1000 }
|
||||
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
|
||||
|
||||
Action<bool> createPlayfieldWithNotes = gravity =>
|
||||
{
|
||||
Clear();
|
||||
|
||||
ManiaPlayfield playField;
|
||||
Add(playField = new ManiaPlayfield(cols, new List<TimingChange> { new TimingChange { BeatLength = 200 } })
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
SpecialColumnPosition = pos,
|
||||
Scale = new Vector2(1, -1)
|
||||
});
|
||||
|
||||
for (int i = 0; i < cols; i++)
|
||||
{
|
||||
playField.Add(new DrawableNote(new Note
|
||||
{
|
||||
StartTime = Time.Current + 1000,
|
||||
Column = i
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
Action createPlayfieldWithNotesAcceptingInput = () =>
|
||||
{
|
||||
Clear();
|
||||
|
||||
var rateAdjustClock = new StopwatchClock(true) { Rate = 0.5 };
|
||||
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
|
||||
|
||||
ManiaPlayfield playField;
|
||||
Add(playField = new ManiaPlayfield(4, new List<TimingChange> { new TimingChange { BeatLength = 200 } })
|
||||
Add(playField = new ManiaPlayfield(4)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -77,14 +62,23 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
Clock = new FramedClock(rateAdjustClock)
|
||||
});
|
||||
|
||||
for (int t = 1000; t <= 2000; t += 100)
|
||||
if (!gravity)
|
||||
playField.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
|
||||
|
||||
for (double t = start_time; t <= start_time + duration; t += 100)
|
||||
{
|
||||
if (gravity)
|
||||
playField.Columns.ElementAt(0).Add(createTimingChange(t, true));
|
||||
|
||||
playField.Add(new DrawableNote(new Note
|
||||
{
|
||||
StartTime = t,
|
||||
Column = 0
|
||||
}, new Bindable<Key>(Key.D)));
|
||||
|
||||
if (gravity)
|
||||
playField.Columns.ElementAt(3).Add(createTimingChange(t, true));
|
||||
|
||||
playField.Add(new DrawableNote(new Note
|
||||
{
|
||||
StartTime = t,
|
||||
@ -92,17 +86,23 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
}, new Bindable<Key>(Key.K)));
|
||||
}
|
||||
|
||||
playField.Add(new DrawableHoldNote(new HoldNote
|
||||
{
|
||||
StartTime = 1000,
|
||||
Duration = 1000,
|
||||
Column = 1
|
||||
}, new Bindable<Key>(Key.F)));
|
||||
if (gravity)
|
||||
playField.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
|
||||
|
||||
playField.Add(new DrawableHoldNote(new HoldNote
|
||||
{
|
||||
StartTime = 1000,
|
||||
Duration = 1000,
|
||||
StartTime = start_time,
|
||||
Duration = duration,
|
||||
Column = 1
|
||||
}, new Bindable<Key>(Key.F)));
|
||||
|
||||
if (gravity)
|
||||
playField.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
|
||||
|
||||
playField.Add(new DrawableHoldNote(new HoldNote
|
||||
{
|
||||
StartTime = start_time,
|
||||
Duration = duration,
|
||||
Column = 2
|
||||
}, new Bindable<Key>(Key.J)));
|
||||
};
|
||||
@ -116,16 +116,11 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
|
||||
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
|
||||
|
||||
AddStep("Normal special style", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
||||
AddStep("Notes with input", () => createPlayfieldWithNotes(false));
|
||||
AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction));
|
||||
|
||||
AddStep("Notes", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Normal));
|
||||
AddWaitStep(10);
|
||||
AddStep("Left special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Left));
|
||||
AddWaitStep(10);
|
||||
AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
|
||||
AddWaitStep(10);
|
||||
|
||||
AddStep("Notes with input", () => createPlayfieldWithNotesAcceptingInput());
|
||||
AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
|
||||
AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction));
|
||||
}
|
||||
|
||||
private void triggerKeyDown(Column column)
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
@ -13,10 +13,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Main menu button system";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseMenuButtonSystem()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
ColourInfo = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
|
||||
|
@ -12,15 +12,12 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Tests pause and fail overlays";
|
||||
|
||||
private PauseContainer.PauseOverlay pauseOverlay;
|
||||
private FailOverlay failOverlay;
|
||||
private int retryCount;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseMenuOverlays()
|
||||
{
|
||||
base.Reset();
|
||||
FailOverlay failOverlay;
|
||||
PauseContainer.PauseOverlay pauseOverlay;
|
||||
|
||||
retryCount = 0;
|
||||
var retryCount = 0;
|
||||
|
||||
Add(pauseOverlay = new PauseContainer.PauseOverlay
|
||||
{
|
||||
@ -34,14 +31,16 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
OnQuit = () => Logger.Log(@"Quit"),
|
||||
});
|
||||
|
||||
AddStep(@"Pause", delegate {
|
||||
if(failOverlay.State == Visibility.Visible)
|
||||
AddStep(@"Pause", delegate
|
||||
{
|
||||
if (failOverlay.State == Visibility.Visible)
|
||||
{
|
||||
failOverlay.Hide();
|
||||
}
|
||||
pauseOverlay.Show();
|
||||
});
|
||||
AddStep("Fail", delegate {
|
||||
AddStep("Fail", delegate
|
||||
{
|
||||
if (pauseOverlay.State == Visibility.Visible)
|
||||
{
|
||||
pauseOverlay.Hide();
|
||||
|
@ -27,9 +27,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
Add(modSelect = new ModSelectOverlay
|
||||
{
|
||||
|
@ -13,18 +13,11 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Tests music controller ui.";
|
||||
|
||||
private MusicController mc;
|
||||
|
||||
public TestCaseMusicController()
|
||||
{
|
||||
Clock = new FramedClock();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
Clock.ProcessFrame();
|
||||
mc = new MusicController
|
||||
var mc = new MusicController
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre
|
||||
|
@ -16,12 +16,10 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"I handle notifications";
|
||||
|
||||
private NotificationManager manager;
|
||||
private readonly NotificationManager manager;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseNotificationManager()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
progressingNotifications.Clear();
|
||||
|
||||
Content.Add(manager = new NotificationManager
|
||||
|
@ -15,9 +15,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
public override string Description => @"Make it easier to see setting changes";
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
Add(new OnScreenDisplay());
|
||||
|
||||
|
@ -13,20 +13,19 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCasePlaySongSelect : TestCase
|
||||
{
|
||||
private BeatmapDatabase db;
|
||||
private TestStorage storage;
|
||||
private PlaySongSelect songSelect;
|
||||
private readonly BeatmapDatabase db;
|
||||
|
||||
public override string Description => @"with fake data";
|
||||
|
||||
private RulesetDatabase rulesets;
|
||||
private readonly RulesetDatabase rulesets;
|
||||
|
||||
public override void Reset()
|
||||
public TestCasePlaySongSelect()
|
||||
{
|
||||
base.Reset();
|
||||
PlaySongSelect songSelect;
|
||||
|
||||
if (db == null)
|
||||
{
|
||||
storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||
var storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||
|
||||
var backingDatabase = storage.GetDatabase(@"client");
|
||||
|
||||
|
@ -2,12 +2,10 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@ -15,71 +13,61 @@ using osu.Game.Screens.Play;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Desktop.VisualTests.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCasePlayer : TestCase
|
||||
{
|
||||
protected Player Player;
|
||||
private BeatmapDatabase db;
|
||||
private RulesetDatabase rulesets;
|
||||
|
||||
public override string Description => @"Showing everything to play the game.";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapDatabase db, RulesetDatabase rulesets)
|
||||
private void load(RulesetDatabase rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
WorkingBeatmap beatmap = null;
|
||||
var objects = new List<HitObject>();
|
||||
|
||||
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
|
||||
if (beatmapInfo != null)
|
||||
beatmap = db.GetWorkingBeatmap(beatmapInfo);
|
||||
|
||||
if (beatmap?.Track == null)
|
||||
int time = 1500;
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
var objects = new List<HitObject>();
|
||||
|
||||
int time = 1500;
|
||||
for (int i = 0; i < 50; i++)
|
||||
objects.Add(new HitCircle
|
||||
{
|
||||
objects.Add(new HitCircle
|
||||
{
|
||||
StartTime = time,
|
||||
Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : OsuPlayfield.BASE_SIZE.X,
|
||||
i % 4 < 2 ? 0 : OsuPlayfield.BASE_SIZE.Y),
|
||||
NewCombo = i % 4 == 0
|
||||
});
|
||||
StartTime = time,
|
||||
Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : OsuPlayfield.BASE_SIZE.X,
|
||||
i % 4 < 2 ? 0 : OsuPlayfield.BASE_SIZE.Y),
|
||||
NewCombo = i % 4 == 0
|
||||
});
|
||||
|
||||
time += 500;
|
||||
}
|
||||
|
||||
Beatmap b = new Beatmap
|
||||
{
|
||||
HitObjects = objects,
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
Difficulty = new BeatmapDifficulty(),
|
||||
Ruleset = rulesets.Query<RulesetInfo>().First(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = @"Unknown",
|
||||
Title = @"Sample Beatmap",
|
||||
Author = @"peppy",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
beatmap = new TestWorkingBeatmap(b);
|
||||
time += 500;
|
||||
}
|
||||
|
||||
Beatmap b = new Beatmap
|
||||
{
|
||||
HitObjects = objects,
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
Difficulty = new BeatmapDifficulty(),
|
||||
Ruleset = rulesets.Query<RulesetInfo>().First(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = @"Unknown",
|
||||
Title = @"Sample Beatmap",
|
||||
Author = @"peppy",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WorkingBeatmap beatmap = new TestWorkingBeatmap(b);
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
RelativeSizeAxes = Framework.Graphics.Axes.Both,
|
||||
|
@ -13,13 +13,11 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Settings visible in replay/auto";
|
||||
|
||||
private ExampleContainer container;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseReplaySettingsOverlay()
|
||||
{
|
||||
base.Reset();
|
||||
ExampleContainer container;
|
||||
|
||||
Add(new ReplaySettingsOverlay()
|
||||
Add(new ReplaySettingsOverlay
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
|
@ -28,9 +28,9 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
private WorkingBeatmap beatmap;
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
if (beatmap == null)
|
||||
{
|
||||
@ -39,8 +39,6 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
beatmap = db.GetWorkingBeatmap(beatmapInfo);
|
||||
}
|
||||
|
||||
base.Reset();
|
||||
|
||||
Add(new Results(new Score
|
||||
{
|
||||
TotalScore = 2845370,
|
||||
|
143
osu.Desktop.VisualTests/Tests/TestCaseRoomInspector.cs
Normal file
143
osu.Desktop.VisualTests/Tests/TestCaseRoomInspector.cs
Normal file
@ -0,0 +1,143 @@
|
||||
// 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.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Multiplayer;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
internal class TestCaseRoomInspector : TestCase
|
||||
{
|
||||
public override string Description => @"from the multiplayer lobby";
|
||||
|
||||
private RulesetDatabase rulesets;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
var room = new Room
|
||||
{
|
||||
Name = { Value = @"My Awesome Room" },
|
||||
Host = { Value = new User { Username = @"flyte", Id = 3103765, Country = new Country { FlagName = @"JP" } } },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Type = { Value = new GameTypeTeamVersus() },
|
||||
Beatmap =
|
||||
{
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 3.7,
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Platina",
|
||||
Artist = @"Maaya Sakamoto",
|
||||
Author = @"uwutm8",
|
||||
},
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover2x = @"https://assets.ppy.sh//beatmaps/560573/covers/cover.jpg?1492722343",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
MaxParticipants = { Value = 200 },
|
||||
Participants =
|
||||
{
|
||||
Value = new[]
|
||||
{
|
||||
new User { Username = @"flyte", Id = 3103765, GlobalRank = 1425 },
|
||||
new User { Username = @"Cookiezi", Id = 124493, GlobalRank = 5466 },
|
||||
new User { Username = @"Angelsim", Id = 1777162, GlobalRank = 2873 },
|
||||
new User { Username = @"Rafis", Id = 2558286, GlobalRank = 4687 },
|
||||
new User { Username = @"hvick225", Id = 50265, GlobalRank = 3258 },
|
||||
new User { Username = @"peppy", Id = 2, GlobalRank = 6251 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RoomInspector inspector;
|
||||
Add(inspector = new RoomInspector
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Room = room,
|
||||
});
|
||||
|
||||
AddStep(@"change title", () => room.Name.Value = @"A Better Room Than The Above");
|
||||
AddStep(@"change host", () => room.Host.Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } });
|
||||
AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying());
|
||||
AddStep(@"change type", () => room.Type.Value = new GameTypeTag());
|
||||
AddStep(@"change beatmap", () => room.Beatmap.Value = null);
|
||||
AddStep(@"change max participants", () => room.MaxParticipants.Value = null);
|
||||
AddStep(@"change participants", () => room.Participants.Value = new[]
|
||||
{
|
||||
new User { Username = @"filsdelama", Id = 2831793, GlobalRank = 8542 },
|
||||
new User { Username = @"_index", Id = 652457, GlobalRank = 15024 }
|
||||
});
|
||||
|
||||
AddStep(@"change room", () =>
|
||||
{
|
||||
var newRoom = new Room
|
||||
{
|
||||
Name = { Value = @"My New, Better Than Ever Room" },
|
||||
Host = { Value = new User { Username = @"Angelsim", Id = 1777162, Country = new Country { FlagName = @"KR" } } },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Type = { Value = new GameTypeTagTeam() },
|
||||
Beatmap =
|
||||
{
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 7.07,
|
||||
Ruleset = rulesets.GetRuleset(0),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"xi",
|
||||
Artist = @"FREEDOM DIVE",
|
||||
Author = @"Nakagawa-Kanon",
|
||||
},
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover2x = @"https://assets.ppy.sh//beatmaps/39804/covers/cover.jpg?1456506845",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MaxParticipants = { Value = 10 },
|
||||
Participants =
|
||||
{
|
||||
Value = new[]
|
||||
{
|
||||
new User { Username = @"Angelsim", Id = 1777162, GlobalRank = 4 },
|
||||
new User { Username = @"HappyStick", Id = 256802, GlobalRank = 752 },
|
||||
new User { Username = @"-Konpaku-", Id = 2258797, GlobalRank = 571 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inspector.Room = newRoom;
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetDatabase rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,10 +15,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Tests multiple counters";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseScoreCounter()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
int numerator = 0, denominator = 0;
|
||||
|
||||
ScoreCounter score = new ScoreCounter(7)
|
||||
@ -79,7 +77,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
score.Current.Value += 300 + (ulong)(300.0 * (comboCounter.Current > 0 ? comboCounter.Current - 1 : 0) / 25.0);
|
||||
comboCounter.Increment();
|
||||
numerator++; denominator++;
|
||||
numerator++;
|
||||
denominator++;
|
||||
accuracyCounter.SetFraction(numerator, denominator);
|
||||
});
|
||||
|
||||
|
210
osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
Normal file
210
osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
Normal file
@ -0,0 +1,210 @@
|
||||
// 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 OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
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.Testing;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public class TestCaseScrollingHitObjects : TestCase
|
||||
{
|
||||
public override string Description => "SpeedAdjustmentContainer/DrawableTimingSection";
|
||||
|
||||
private readonly BindableDouble timeRangeBindable;
|
||||
private readonly OsuSpriteText bottomLabel;
|
||||
private readonly SpriteText topTime;
|
||||
private readonly SpriteText bottomTime;
|
||||
|
||||
public TestCaseScrollingHitObjects()
|
||||
{
|
||||
OsuSpriteText timeRangeText;
|
||||
SpeedAdjustmentCollection adjustmentCollection;
|
||||
|
||||
timeRangeBindable = new BindableDouble(2000)
|
||||
{
|
||||
MinValue = 200,
|
||||
MaxValue = 4000,
|
||||
};
|
||||
|
||||
SliderBar<double> timeRange;
|
||||
Add(timeRange = new BasicSliderBar<double>
|
||||
{
|
||||
Size = new Vector2(200, 20),
|
||||
SelectionColor = Color4.Pink,
|
||||
KeyboardStep = 100
|
||||
});
|
||||
|
||||
Add(timeRangeText = new OsuSpriteText
|
||||
{
|
||||
X = 210,
|
||||
TextSize = 16,
|
||||
});
|
||||
|
||||
timeRange.Current.BindTo(timeRangeBindable);
|
||||
timeRangeBindable.ValueChanged += v => timeRangeText.Text = $"Visible Range: {v:#,#.#}";
|
||||
timeRangeBindable.ValueChanged += v => bottomLabel.Text = $"t minus {v:#,#}";
|
||||
|
||||
Add(new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(100, 500),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.25f
|
||||
},
|
||||
adjustmentCollection = new SpeedAdjustmentCollection(Axes.Y)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
VisibleTimeRange = timeRangeBindable,
|
||||
Masking = true,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "t minus 0",
|
||||
Margin = new MarginPadding(2),
|
||||
TextSize = 14,
|
||||
Anchor = Anchor.TopRight,
|
||||
},
|
||||
bottomLabel = new OsuSpriteText
|
||||
{
|
||||
Text = "t minus x",
|
||||
Margin = new MarginPadding(2),
|
||||
TextSize = 14,
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomLeft,
|
||||
},
|
||||
topTime = new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding(2),
|
||||
TextSize = 14,
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopRight,
|
||||
},
|
||||
bottomTime = new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding(2),
|
||||
TextSize = 14,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomRight,
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
timeRangeBindable.TriggerChange();
|
||||
|
||||
adjustmentCollection.Add(new TestSpeedAdjustmentContainer(new MultiplierControlPoint()));
|
||||
|
||||
AddStep("Add hit object", () => adjustmentCollection.Add(new TestDrawableHitObject(new HitObject { StartTime = Time.Current + 2000 })));
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
topTime.Text = Time.Current.ToString("#,#");
|
||||
bottomTime.Text = (Time.Current + timeRangeBindable.Value).ToString("#,#");
|
||||
}
|
||||
|
||||
private class TestSpeedAdjustmentContainer : SpeedAdjustmentContainer
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
public TestSpeedAdjustmentContainer(MultiplierControlPoint controlPoint)
|
||||
: base(controlPoint)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DrawableTimingSection CreateTimingSection() => new TestDrawableTimingSection(ControlPoint);
|
||||
|
||||
private class TestDrawableTimingSection : DrawableTimingSection
|
||||
{
|
||||
private readonly MultiplierControlPoint controlPoint;
|
||||
|
||||
public TestDrawableTimingSection(MultiplierControlPoint controlPoint)
|
||||
{
|
||||
this.controlPoint = controlPoint;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Y = (float)(controlPoint.StartTime - Time.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDrawableHitObject : DrawableHitObject, IScrollingHitObject
|
||||
{
|
||||
private readonly Box background;
|
||||
private const float height = 14;
|
||||
|
||||
public BindableDouble LifetimeOffset { get; } = new BindableDouble();
|
||||
|
||||
public TestDrawableHitObject(HitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
RelativePositionAxes = Axes.Y;
|
||||
|
||||
Y = (float)hitObject.StartTime;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = height,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Colour = Color4.Cyan,
|
||||
Height = 1,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = Color4.Black,
|
||||
TextSize = height,
|
||||
Font = @"Exo2.0-BoldItalic",
|
||||
Text = $"{hitObject.StartTime:#,#}"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
FadeInFromZero(250, EasingTypes.OutQuint);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
if (Time.Current >= HitObject.StartTime)
|
||||
background.Colour = Color4.Red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,13 +10,16 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Tests the settings overlay";
|
||||
|
||||
private SettingsOverlay settings;
|
||||
private readonly SettingsOverlay settings;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseSettings()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Children = new[] { settings = new SettingsOverlay() };
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
settings.ToggleVisibility();
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,10 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Skip skip skippediskip";
|
||||
|
||||
public override void Reset()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.Reset();
|
||||
base.LoadComplete();
|
||||
|
||||
Add(new SkipButton(Clock.CurrentTime + 5000));
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"social browser overlay";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseSocial()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
SocialOverlay s = new SocialOverlay
|
||||
{
|
||||
Users = new[]
|
||||
|
@ -15,15 +15,13 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"With fake data";
|
||||
|
||||
private SongProgress progress;
|
||||
private SongProgressGraph graph;
|
||||
private readonly SongProgress progress;
|
||||
private readonly SongProgressGraph graph;
|
||||
|
||||
private StopwatchClock clock;
|
||||
private readonly StopwatchClock clock;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseSongProgress()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
clock = new StopwatchClock(true);
|
||||
|
||||
Add(progress = new SongProgress
|
||||
|
@ -14,10 +14,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Filter for song select";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseTabControl()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
OsuSpriteText text;
|
||||
OsuTabControl<GroupMode> filter;
|
||||
Add(filter = new OsuTabControl<GroupMode>
|
||||
|
@ -16,10 +16,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
private bool kiai;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseTaikoHitObjects()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
AddToggleStep("Kiai", b =>
|
||||
{
|
||||
kiai = !kiai;
|
||||
|
@ -26,13 +26,11 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
protected override double TimePerAction => default_duration * 2;
|
||||
|
||||
private readonly Random rng = new Random(1337);
|
||||
private TaikoPlayfield playfield;
|
||||
private Container playfieldContainer;
|
||||
private readonly TaikoPlayfield playfield;
|
||||
private readonly Container playfieldContainer;
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseTaikoPlayfield()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
AddStep("Hit!", addHitJudgement);
|
||||
AddStep("Miss :(", addMissJudgement);
|
||||
AddStep("DrumRoll", () => addDrumRoll(false));
|
||||
|
@ -16,10 +16,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Tests display of icons";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseTextAwesome()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
FillFlowContainer flow;
|
||||
|
||||
Add(flow = new FillFlowContainer
|
||||
|
@ -10,10 +10,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Mostly back button";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseTwoLayerButton()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new BackButton());
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,8 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
public override string Description => @"Panels for displaying a user's status";
|
||||
|
||||
public override void Reset()
|
||||
public TestCaseUserPanel()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
UserPanel flyte;
|
||||
UserPanel peppy;
|
||||
Add(new FillFlowContainer
|
||||
|
@ -87,11 +87,13 @@
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress, Version=0.15.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SharpCompress.0.15.2\lib\net45\SharpCompress.dll</HintPath>
|
||||
<Reference Include="SharpCompress, Version=0.17.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@ -185,8 +187,10 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AutomatedVisualTestGame.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Tests\TestCaseBeatSyncedContainer.cs" />
|
||||
<Compile Include="Tests\TestCaseChatDisplay.cs" />
|
||||
<Compile Include="Tests\TestCaseBeatmapDetails.cs" />
|
||||
<Compile Include="Tests\TestCaseContextMenu.cs" />
|
||||
<Compile Include="Tests\TestCaseDrawings.cs" />
|
||||
<Compile Include="Tests\TestCaseGamefield.cs" />
|
||||
<Compile Include="Tests\TestCaseGraph.cs" />
|
||||
@ -204,6 +208,7 @@
|
||||
<Compile Include="Tests\TestCaseReplay.cs" />
|
||||
<Compile Include="Tests\TestCaseResults.cs" />
|
||||
<Compile Include="Tests\TestCaseScoreCounter.cs" />
|
||||
<Compile Include="Tests\TestCaseScrollingHitObjects.cs" />
|
||||
<Compile Include="Tests\TestCaseSkipButton.cs" />
|
||||
<Compile Include="Tests\TestCaseTabControl.cs" />
|
||||
<Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
|
||||
@ -226,6 +231,7 @@
|
||||
<Compile Include="Tests\TestCaseDirect.cs" />
|
||||
<Compile Include="Tests\TestCaseSocial.cs" />
|
||||
<Compile Include="Tests\TestCaseBreadcrumbs.cs" />
|
||||
<Compile Include="Tests\TestCaseRoomInspector.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
|
@ -5,8 +5,8 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
-->
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
|
||||
<package id="SharpCompress" version="0.15.2" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" />
|
||||
<package id="SharpCompress" version="0.17.1" targetFramework="net45" />
|
||||
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
|
||||
|
@ -11,6 +11,7 @@ using System.Reflection;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Desktop
|
||||
@ -22,18 +23,22 @@ namespace osu.Desktop
|
||||
public OsuGameDesktop(string[] args = null)
|
||||
: base(args)
|
||||
{
|
||||
versionManager = new VersionManager { Depth = int.MinValue };
|
||||
versionManager = new VersionManager
|
||||
{
|
||||
Depth = int.MinValue,
|
||||
State = Visibility.Hidden
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
LoadComponentAsync(versionManager);
|
||||
LoadComponentAsync(versionManager, Add);
|
||||
ScreenChanged += s =>
|
||||
{
|
||||
if (!versionManager.IsAlive && s is Intro)
|
||||
Add(versionManager);
|
||||
if (!versionManager.IsPresent && s is Intro)
|
||||
versionManager.State = Visibility.Visible;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using Squirrel;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
@ -92,12 +93,6 @@ namespace osu.Desktop.Overlays
|
||||
checkForUpdateAsync();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
State = Visibility.Visible;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
@ -121,18 +121,23 @@
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\NuGet.Squirrel.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress, Version=0.17.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Squirrel, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll</HintPath>
|
||||
<Reference Include="Squirrel, Version=1.7.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\Squirrel.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
|
@ -7,7 +7,8 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
|
||||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" />
|
||||
<package id="SharpCompress" version="0.17.1" targetFramework="net45" />
|
||||
<package id="Splat" version="2.0.0" targetFramework="net45" />
|
||||
<package id="squirrel.windows" version="1.5.2" targetFramework="net45" />
|
||||
<package id="squirrel.windows" version="1.7.5" targetFramework="net45" />
|
||||
</packages>
|
@ -5,18 +5,17 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
internal class DrawableFruit : Sprite
|
||||
{
|
||||
private readonly CatchBaseHit h;
|
||||
//private readonly CatchBaseHit h;
|
||||
|
||||
public DrawableFruit(CatchBaseHit h)
|
||||
{
|
||||
this.h = h;
|
||||
//this.h = h;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
Scale = new Vector2(0.1f);
|
||||
@ -29,10 +28,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
Texture = textures.Get(@"Menu/logo");
|
||||
|
||||
const double duration = 0;
|
||||
|
||||
Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) });
|
||||
Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
|
||||
//Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) });
|
||||
//Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
|
||||
Expire(true);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
|
@ -33,8 +33,9 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
|
@ -5,5 +5,5 @@ Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" />
|
||||
</packages>
|
@ -448,7 +448,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
return curveData.RepeatSamples[index];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and adds a note to a pattern.
|
||||
/// </summary>
|
||||
@ -480,7 +479,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
Tail = { Samples = sampleInfoListAt(endTime) }
|
||||
};
|
||||
|
||||
|
||||
newObject = holdNote;
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
new ModCinema(),
|
||||
},
|
||||
},
|
||||
new ManiaModGravity()
|
||||
};
|
||||
|
||||
default:
|
||||
|
@ -87,6 +87,5 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
bitIndex++;
|
||||
return ((bitBuffer >>= 1) & 1) == 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
23
osu.Game.Rulesets.Mania/Mods/IGenerateSpeedAdjustments.cs
Normal file
23
osu.Game.Rulesets.Mania/Mods/IGenerateSpeedAdjustments.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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 osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
/// <summary>
|
||||
/// A type of mod which generates speed adjustments that scroll the hit objects and bar lines.
|
||||
/// </summary>
|
||||
internal interface IGenerateSpeedAdjustments
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies this mod to a hit renderer.
|
||||
/// </summary>
|
||||
/// <param name="hitRenderer">The hit renderer to apply to.</param>
|
||||
/// <param name="hitObjectTimingChanges">The per-column list of speed adjustments for hit objects.</param>
|
||||
/// <param name="barlineTimingChanges">The list of speed adjustments for bar lines.</param>
|
||||
void ApplyToHitRenderer(ManiaHitRenderer hitRenderer, ref List<SpeedAdjustmentContainer>[] hitObjectTimingChanges, ref List<SpeedAdjustmentContainer> barlineTimingChanges);
|
||||
}
|
||||
}
|
46
osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
Normal file
46
osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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 osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModGravity : Mod, IGenerateSpeedAdjustments
|
||||
{
|
||||
public override string Name => "Gravity";
|
||||
|
||||
public override double ScoreMultiplier => 0;
|
||||
|
||||
public override FontAwesome Icon => FontAwesome.fa_sort_desc;
|
||||
|
||||
public void ApplyToHitRenderer(ManiaHitRenderer hitRenderer, ref List<SpeedAdjustmentContainer>[] hitObjectTimingChanges, ref List<SpeedAdjustmentContainer> barlineTimingChanges)
|
||||
{
|
||||
// We have to generate one speed adjustment per hit object for gravity
|
||||
foreach (ManiaHitObject obj in hitRenderer.Objects)
|
||||
{
|
||||
MultiplierControlPoint controlPoint = hitRenderer.CreateControlPointAt(obj.StartTime);
|
||||
// Beat length has too large of an effect for gravity, so we'll force it to a constant value for now
|
||||
controlPoint.TimingPoint.BeatLength = 1000;
|
||||
|
||||
hitObjectTimingChanges[obj.Column].Add(new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Gravity));
|
||||
}
|
||||
|
||||
// Like with hit objects, we need to generate one speed adjustment per bar line
|
||||
foreach (DrawableBarLine barLine in hitRenderer.BarLines)
|
||||
{
|
||||
var controlPoint = hitRenderer.CreateControlPointAt(barLine.HitObject.StartTime);
|
||||
// Beat length has too large of an effect for gravity, so we'll force it to a constant value for now
|
||||
controlPoint.TimingPoint.BeatLength = 1000;
|
||||
|
||||
barlineTimingChanges.Add(new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Gravity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
@ -55,6 +55,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
tickContainer = new Container<DrawableHoldNoteTick>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime),
|
||||
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
|
||||
},
|
||||
head = new DrawableHeadNote(this, key)
|
||||
@ -76,9 +77,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
HoldStartTime = () => holdStartTime
|
||||
};
|
||||
|
||||
// To make the ticks relative to ourselves we need to offset them backwards
|
||||
drawableTick.Y -= (float)HitObject.StartTime;
|
||||
|
||||
tickContainer.Add(drawableTick);
|
||||
AddNested(drawableTick);
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
base.AccentColour = value;
|
||||
|
||||
glowContainer.EdgeEffect = new EdgeEffect
|
||||
glowContainer.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 2f,
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject, ManiaJudgement>
|
||||
public abstract class DrawableManiaHitObject<TObject> : DrawableScrollingHitObject<ManiaHitObject, ManiaJudgement>
|
||||
where TObject : ManiaHitObject
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
public DrawableNote(Note hitObject, Bindable<Key> key = null)
|
||||
: base(hitObject, key)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 100;
|
||||
|
||||
Add(headPiece = new NotePiece
|
||||
|
@ -4,7 +4,7 @@
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
|
@ -5,7 +5,7 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
|
@ -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.Game.Rulesets.Timing;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="DrawableTimingSection"/> which scrolls relative to the control point start time.
|
||||
/// </summary>
|
||||
internal class BasicScrollingDrawableTimingSection : DrawableTimingSection
|
||||
{
|
||||
private readonly MultiplierControlPoint controlPoint;
|
||||
|
||||
public BasicScrollingDrawableTimingSection(MultiplierControlPoint controlPoint)
|
||||
{
|
||||
this.controlPoint = controlPoint;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Y = (float)(controlPoint.StartTime - Time.Current);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,156 +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 System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
/// <summary>
|
||||
/// A container in which added drawables are put into a relative coordinate space spanned by a length of time.
|
||||
/// <para>
|
||||
/// This container contains <see cref="ControlPoint"/>s which scroll inside this container.
|
||||
/// Drawables added to this container are moved inside the relevant <see cref="ControlPoint"/>,
|
||||
/// and as such, will scroll along with the <see cref="ControlPoint"/>s.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class ControlPointContainer : Container<Drawable>
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount of time which this container spans.
|
||||
/// </summary>
|
||||
public double TimeSpan { get; set; }
|
||||
|
||||
private readonly List<DrawableControlPoint> drawableControlPoints;
|
||||
|
||||
public ControlPointContainer(IEnumerable<TimingChange> timingChanges)
|
||||
{
|
||||
drawableControlPoints = timingChanges.Select(t => new DrawableControlPoint(t)).ToList();
|
||||
Children = drawableControlPoints;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a drawable to this container. Note that the drawable added must have its Y-position be
|
||||
/// an absolute unit of time that is _not_ relative to <see cref="TimeSpan"/>.
|
||||
/// </summary>
|
||||
/// <param name="drawable">The drawable to add.</param>
|
||||
public override void Add(Drawable drawable)
|
||||
{
|
||||
// Always add timing sections to ourselves
|
||||
if (drawable is DrawableControlPoint)
|
||||
{
|
||||
base.Add(drawable);
|
||||
return;
|
||||
}
|
||||
|
||||
var controlPoint = drawableControlPoints.LastOrDefault(t => t.CanContain(drawable)) ?? drawableControlPoints.FirstOrDefault();
|
||||
|
||||
if (controlPoint == null)
|
||||
throw new InvalidOperationException("Could not find suitable timing section to add object to.");
|
||||
|
||||
controlPoint.Add(drawable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A container that contains drawables within the time span of a timing section.
|
||||
/// <para>
|
||||
/// The content of this container will scroll relative to the current time.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private class DrawableControlPoint : Container
|
||||
{
|
||||
private readonly TimingChange timingChange;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a drawable control point. The height of this container will be proportional
|
||||
/// to the beat length of the control point it is initialized with such that, e.g. a beat length
|
||||
/// of 500ms results in this container being twice as high as its parent, which further means that
|
||||
/// the content container will scroll at twice the normal rate.
|
||||
/// </summary>
|
||||
/// <param name="timingChange">The control point to create the drawable control point for.</param>
|
||||
public DrawableControlPoint(TimingChange timingChange)
|
||||
{
|
||||
this.timingChange = timingChange;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
AddInternal(content = new AutoTimeRelativeContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Y = (float)timingChange.Time
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
var parent = (ControlPointContainer)Parent;
|
||||
|
||||
// Adjust our height to account for the speed changes
|
||||
Height = (float)(1000 / timingChange.BeatLength / timingChange.SpeedMultiplier);
|
||||
RelativeChildSize = new Vector2(1, (float)parent.TimeSpan);
|
||||
|
||||
// Scroll the content
|
||||
content.Y = (float)(timingChange.Time - Time.Current);
|
||||
}
|
||||
|
||||
public override void Add(Drawable drawable)
|
||||
{
|
||||
// The previously relatively-positioned drawable will now become relative to content, but since the drawable has no knowledge of content,
|
||||
// we need to offset it back by content's position position so that it becomes correctly relatively-positioned to content
|
||||
// This can be removed if hit objects were stored such that either their StartTime or their "beat offset" was relative to the timing change
|
||||
// they belonged to, but this requires a radical change to the beatmap format which we're not ready to do just yet
|
||||
drawable.Y -= (float)timingChange.Time;
|
||||
|
||||
base.Add(drawable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this control point can contain a drawable. This control point can contain a drawable if the drawable is positioned "after" this control point.
|
||||
/// </summary>
|
||||
/// <param name="drawable">The drawable to check.</param>
|
||||
public bool CanContain(Drawable drawable) => content.Y <= drawable.Y;
|
||||
|
||||
/// <summary>
|
||||
/// A container which always keeps its height and relative coordinate space "auto-sized" to its children.
|
||||
/// <para>
|
||||
/// This is used in the case where children are relatively positioned/sized to time values (e.g. notes/bar lines) to keep
|
||||
/// such children wrapped inside a container, otherwise they would disappear due to container flattening.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private class AutoTimeRelativeContainer : Container
|
||||
{
|
||||
protected override IComparer<Drawable> DepthComparer => new HitObjectReverseStartTimeComparer();
|
||||
|
||||
public override void InvalidateFromChild(Invalidation invalidation)
|
||||
{
|
||||
// We only want to re-compute our size when a child's size or position has changed
|
||||
if ((invalidation & Invalidation.Geometry) == 0)
|
||||
{
|
||||
base.InvalidateFromChild(invalidation);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Children.Any())
|
||||
return;
|
||||
|
||||
float height = Children.Select(child => child.Y + child.Height).Max();
|
||||
|
||||
Height = height;
|
||||
RelativeChildSize = new Vector2(1, height);
|
||||
|
||||
base.InvalidateFromChild(invalidation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
// 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.Rulesets.Timing;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="DrawableTimingSection"/> that emulates a form of gravity where hit objects speed up over time.
|
||||
/// </summary>
|
||||
internal class GravityScrollingDrawableTimingSection : DrawableTimingSection
|
||||
{
|
||||
private readonly MultiplierControlPoint controlPoint;
|
||||
|
||||
public GravityScrollingDrawableTimingSection(MultiplierControlPoint controlPoint)
|
||||
{
|
||||
this.controlPoint = controlPoint;
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
// The gravity-adjusted start position
|
||||
float startPos = (float)computeGravityTime(controlPoint.StartTime);
|
||||
// The gravity-adjusted end position
|
||||
float endPos = (float)computeGravityTime(controlPoint.StartTime + RelativeChildSize.Y);
|
||||
|
||||
Y = startPos;
|
||||
Height = endPos - startPos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies gravity to a time value based on the current time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time value gravity should be applied to.</param>
|
||||
/// <returns>The time after gravity is applied to <paramref name="time"/>.</returns>
|
||||
private double computeGravityTime(double time)
|
||||
{
|
||||
double relativeTime = relativeTimeAt(time);
|
||||
|
||||
// The sign of the relative time, this is used to apply backwards acceleration leading into startTime
|
||||
double sign = relativeTime < 0 ? -1 : 1;
|
||||
|
||||
return VisibleTimeRange - acceleration * relativeTime * relativeTime * sign;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The acceleration due to "gravity" of the content of this container.
|
||||
/// </summary>
|
||||
private double acceleration => 1 / VisibleTimeRange;
|
||||
|
||||
/// <summary>
|
||||
/// Computes the current time relative to <paramref name="time"/>, accounting for <see cref="DrawableTimingSection.VisibleTimeRange"/>.
|
||||
/// </summary>
|
||||
/// <param name="time">The non-offset time.</param>
|
||||
/// <returns>The current time relative to <paramref name="time"/> - <see cref="DrawableTimingSection.VisibleTimeRange"/>. </returns>
|
||||
private double relativeTimeAt(double time) => Time.Current - time + VisibleTimeRange;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// 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.Rulesets.Timing;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
public class ManiaSpeedAdjustmentContainer : SpeedAdjustmentContainer
|
||||
{
|
||||
private readonly ScrollingAlgorithm scrollingAlgorithm;
|
||||
|
||||
public ManiaSpeedAdjustmentContainer(MultiplierControlPoint timingSection, ScrollingAlgorithm scrollingAlgorithm)
|
||||
: base(timingSection)
|
||||
{
|
||||
this.scrollingAlgorithm = scrollingAlgorithm;
|
||||
}
|
||||
|
||||
protected override DrawableTimingSection CreateTimingSection()
|
||||
{
|
||||
switch (scrollingAlgorithm)
|
||||
{
|
||||
default:
|
||||
case ScrollingAlgorithm.Basic:
|
||||
return new BasicScrollingDrawableTimingSection(ControlPoint);
|
||||
case ScrollingAlgorithm.Gravity:
|
||||
return new GravityScrollingDrawableTimingSection(ControlPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
osu.Game.Rulesets.Mania/Timing/ScrollingAlgorithm.cs
Normal file
17
osu.Game.Rulesets.Mania/Timing/ScrollingAlgorithm.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
public enum ScrollingAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic scrolling algorithm based on the timing section time. This is the default algorithm.
|
||||
/// </summary>
|
||||
Basic,
|
||||
/// <summary>
|
||||
/// Emulating a form of gravity where hit objects speed up over time.
|
||||
/// </summary>
|
||||
Gravity
|
||||
}
|
||||
}
|
@ -1,23 +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
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing
|
||||
{
|
||||
public class TimingChange
|
||||
{
|
||||
/// <summary>
|
||||
/// The time at which this timing change happened.
|
||||
/// </summary>
|
||||
public double Time;
|
||||
|
||||
/// <summary>
|
||||
/// The beat length.
|
||||
/// </summary>
|
||||
public double BeatLength = 500;
|
||||
|
||||
/// <summary>
|
||||
/// The speed multiplier.
|
||||
/// </summary>
|
||||
public double SpeedMultiplier = 1;
|
||||
}
|
||||
}
|
@ -7,17 +7,14 @@ using OpenTK.Input;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using System;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -33,6 +30,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private const float column_width = 45;
|
||||
private const float special_column_width = 70;
|
||||
|
||||
private readonly BindableDouble visibleTimeRange = new BindableDouble();
|
||||
public BindableDouble VisibleTimeRange
|
||||
{
|
||||
get { return visibleTimeRange; }
|
||||
set { visibleTimeRange.BindTo(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key that will trigger input actions for this column and hit objects contained inside it.
|
||||
/// </summary>
|
||||
@ -42,9 +46,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private readonly Container hitTargetBar;
|
||||
private readonly Container keyIcon;
|
||||
|
||||
public readonly ControlPointContainer ControlPointContainer;
|
||||
private readonly SpeedAdjustmentCollection speedAdjustments;
|
||||
|
||||
public Column(IEnumerable<TimingChange> timingChanges)
|
||||
public Column()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = column_width;
|
||||
@ -61,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
Name = "Hit target + hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION},
|
||||
Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
@ -93,10 +97,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
},
|
||||
ControlPointContainer = new ControlPointContainer(timingChanges)
|
||||
speedAdjustments = new SpeedAdjustmentCollection(Axes.Y)
|
||||
{
|
||||
Name = "Hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
VisibleTimeRange = VisibleTimeRange
|
||||
},
|
||||
// For column lighting, we need to capture input events before the notes
|
||||
new InputTarget
|
||||
@ -171,14 +176,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
background.Colour = accentColour;
|
||||
|
||||
hitTargetBar.EdgeEffect = new EdgeEffect
|
||||
hitTargetBar.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
Colour = accentColour.Opacity(0.5f),
|
||||
};
|
||||
|
||||
keyIcon.EdgeEffect = new EdgeEffect
|
||||
keyIcon.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
@ -187,10 +192,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject)
|
||||
public void Add(SpeedAdjustmentContainer speedAdjustment) => speedAdjustments.Add(speedAdjustment);
|
||||
public void Add(DrawableHitObject hitObject)
|
||||
{
|
||||
hitObject.AccentColour = AccentColour;
|
||||
ControlPointContainer.Add(hitObject);
|
||||
speedAdjustments.Add(hitObject);
|
||||
}
|
||||
|
||||
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
||||
|
@ -8,6 +8,7 @@ using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Framework.MathUtils;
|
||||
@ -16,6 +17,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
@ -23,78 +25,44 @@ using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaHitRenderer : HitRenderer<ManiaHitObject, ManiaJudgement>
|
||||
public class ManiaHitRenderer : SpeedAdjustedHitRenderer<ManiaHitObject, ManiaJudgement>
|
||||
{
|
||||
public int? Columns;
|
||||
/// <summary>
|
||||
/// Preferred column count. This will only have an effect during the initialization of the play field.
|
||||
/// </summary>
|
||||
public int PreferredColumns;
|
||||
|
||||
public IEnumerable<DrawableBarLine> BarLines;
|
||||
|
||||
/// <summary>
|
||||
/// Per-column timing changes.
|
||||
/// </summary>
|
||||
private readonly List<SpeedAdjustmentContainer>[] hitObjectSpeedAdjustments;
|
||||
|
||||
/// <summary>
|
||||
/// Bar line timing changes.
|
||||
/// </summary>
|
||||
private readonly List<SpeedAdjustmentContainer> barLineSpeedAdjustments = new List<SpeedAdjustmentContainer>();
|
||||
|
||||
public ManiaHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(beatmap, isForCurrentRuleset)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield()
|
||||
{
|
||||
double lastSpeedMultiplier = 1;
|
||||
double lastBeatLength = 500;
|
||||
|
||||
// Merge timing + difficulty points
|
||||
var allPoints = new SortedList<ControlPoint>(Comparer<ControlPoint>.Default);
|
||||
allPoints.AddRange(Beatmap.ControlPointInfo.TimingPoints);
|
||||
allPoints.AddRange(Beatmap.ControlPointInfo.DifficultyPoints);
|
||||
|
||||
// Generate the timing points, making non-timing changes use the previous timing change
|
||||
var timingChanges = allPoints.Select(c =>
|
||||
{
|
||||
var timingPoint = c as TimingControlPoint;
|
||||
var difficultyPoint = c as DifficultyControlPoint;
|
||||
|
||||
if (timingPoint != null)
|
||||
lastBeatLength = timingPoint.BeatLength;
|
||||
|
||||
if (difficultyPoint != null)
|
||||
lastSpeedMultiplier = difficultyPoint.SpeedMultiplier;
|
||||
|
||||
return new TimingChange
|
||||
{
|
||||
Time = c.Time,
|
||||
BeatLength = lastBeatLength,
|
||||
SpeedMultiplier = lastSpeedMultiplier
|
||||
};
|
||||
});
|
||||
|
||||
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||
|
||||
// Perform some post processing of the timing changes
|
||||
timingChanges = timingChanges
|
||||
// Collapse sections after the last hit object
|
||||
.Where(s => s.Time <= lastObjectTime)
|
||||
// Collapse sections with the same start time
|
||||
.GroupBy(s => s.Time).Select(g => g.Last()).OrderBy(s => s.Time)
|
||||
// Collapse sections with the same beat length
|
||||
.GroupBy(s => s.BeatLength * s.SpeedMultiplier).Select(g => g.First())
|
||||
.ToList();
|
||||
|
||||
return new ManiaPlayfield(Columns ?? (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize), timingChanges)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
// Invert by default for now (should be moved to config/skin later)
|
||||
Scale = new Vector2(1, -1)
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var maniaPlayfield = (ManiaPlayfield)Playfield;
|
||||
// Generate the speed adjustment container lists
|
||||
hitObjectSpeedAdjustments = new List<SpeedAdjustmentContainer>[PreferredColumns];
|
||||
for (int i = 0; i < PreferredColumns; i++)
|
||||
hitObjectSpeedAdjustments[i] = new List<SpeedAdjustmentContainer>();
|
||||
|
||||
// Generate the bar lines
|
||||
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||
|
||||
SortedList<TimingControlPoint> timingPoints = Beatmap.ControlPointInfo.TimingPoints;
|
||||
var barLines = new List<DrawableBarLine>();
|
||||
|
||||
for (int i = 0; i < timingPoints.Count; i++)
|
||||
{
|
||||
TimingControlPoint point = timingPoints[i];
|
||||
@ -105,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
int index = 0;
|
||||
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
|
||||
{
|
||||
maniaPlayfield.Add(new DrawableBarLine(new BarLine
|
||||
barLines.Add(new DrawableBarLine(new BarLine
|
||||
{
|
||||
StartTime = t,
|
||||
ControlPoint = point,
|
||||
@ -113,17 +81,78 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
BarLines = barLines;
|
||||
|
||||
// Generate speed adjustments from mods first
|
||||
bool useDefaultSpeedAdjustments = true;
|
||||
|
||||
if (Mods != null)
|
||||
{
|
||||
foreach (var speedAdjustmentMod in Mods.OfType<IGenerateSpeedAdjustments>())
|
||||
{
|
||||
useDefaultSpeedAdjustments = false;
|
||||
speedAdjustmentMod.ApplyToHitRenderer(this, ref hitObjectSpeedAdjustments, ref barLineSpeedAdjustments);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the default speed adjustments
|
||||
if (useDefaultSpeedAdjustments)
|
||||
generateDefaultSpeedAdjustments();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var maniaPlayfield = (ManiaPlayfield)Playfield;
|
||||
|
||||
BarLines.ForEach(maniaPlayfield.Add);
|
||||
}
|
||||
|
||||
protected override void ApplyBeatmap()
|
||||
{
|
||||
base.ApplyBeatmap();
|
||||
|
||||
PreferredColumns = (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize);
|
||||
}
|
||||
|
||||
protected override void ApplySpeedAdjustments()
|
||||
{
|
||||
var maniaPlayfield = (ManiaPlayfield)Playfield;
|
||||
|
||||
for (int i = 0; i < PreferredColumns; i++)
|
||||
foreach (var change in hitObjectSpeedAdjustments[i])
|
||||
maniaPlayfield.Columns.ElementAt(i).Add(change);
|
||||
|
||||
foreach (var change in barLineSpeedAdjustments)
|
||||
maniaPlayfield.Add(change);
|
||||
}
|
||||
|
||||
private void generateDefaultSpeedAdjustments()
|
||||
{
|
||||
DefaultControlPoints.ForEach(c =>
|
||||
{
|
||||
foreach (List<SpeedAdjustmentContainer> t in hitObjectSpeedAdjustments)
|
||||
t.Add(new ManiaSpeedAdjustmentContainer(c, ScrollingAlgorithm.Basic));
|
||||
barLineSpeedAdjustments.Add(new ManiaSpeedAdjustmentContainer(c, ScrollingAlgorithm.Basic));
|
||||
});
|
||||
}
|
||||
|
||||
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(PreferredColumns)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
// Invert by default for now (should be moved to config/skin later)
|
||||
Scale = new Vector2(1, -1)
|
||||
};
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
||||
|
||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
|
||||
|
||||
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)
|
||||
{
|
||||
var maniaPlayfield = Playfield as ManiaPlayfield;
|
||||
if (maniaPlayfield == null)
|
||||
return null;
|
||||
var maniaPlayfield = (ManiaPlayfield)Playfield;
|
||||
|
||||
Bindable<Key> key = maniaPlayfield.Columns.ElementAt(h.Column).Key;
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
@ -15,13 +14,14 @@ using osu.Framework.Allocation;
|
||||
using OpenTK.Input;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Timing;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -29,10 +29,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public const float HIT_TARGET_POSITION = 50;
|
||||
|
||||
private const float time_span_default = 5000;
|
||||
private const float time_span_min = 10;
|
||||
private const float time_span_max = 50000;
|
||||
private const float time_span_step = 200;
|
||||
private const double time_span_default = 1500;
|
||||
private const double time_span_min = 50;
|
||||
private const double time_span_max = 10000;
|
||||
private const double time_span_step = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Default column keys, expanding outwards from the middle as more column are added.
|
||||
@ -58,14 +58,20 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private readonly FlowContainer<Column> columns;
|
||||
public IEnumerable<Column> Columns => columns.Children;
|
||||
|
||||
private readonly ControlPointContainer barLineContainer;
|
||||
private readonly BindableDouble visibleTimeRange = new BindableDouble(time_span_default)
|
||||
{
|
||||
MinValue = time_span_min,
|
||||
MaxValue = time_span_max
|
||||
};
|
||||
|
||||
private readonly SpeedAdjustmentCollection barLineContainer;
|
||||
|
||||
private List<Color4> normalColumnColours = new List<Color4>();
|
||||
private Color4 specialColumnColour;
|
||||
|
||||
private readonly int columnCount;
|
||||
|
||||
public ManiaPlayfield(int columnCount, IEnumerable<TimingChange> timingChanges)
|
||||
public ManiaPlayfield(int columnCount)
|
||||
{
|
||||
this.columnCount = columnCount;
|
||||
|
||||
@ -116,12 +122,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
Padding = new MarginPadding { Top = HIT_TARGET_POSITION },
|
||||
Children = new[]
|
||||
{
|
||||
barLineContainer = new ControlPointContainer(timingChanges)
|
||||
barLineContainer = new SpeedAdjustmentCollection(Axes.Y)
|
||||
{
|
||||
Name = "Bar lines",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
VisibleTimeRange = visibleTimeRange
|
||||
// Width is set in the Update method
|
||||
}
|
||||
}
|
||||
@ -131,9 +138,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
};
|
||||
|
||||
for (int i = 0; i < columnCount; i++)
|
||||
columns.Add(new Column(timingChanges));
|
||||
|
||||
TimeSpan = time_span_default;
|
||||
columns.Add(new Column { VisibleTimeRange = visibleTimeRange });
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -208,6 +213,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> h) => Columns.ElementAt(h.HitObject.Column).Add(h);
|
||||
public void Add(DrawableBarLine barline) => barLineContainer.Add(barline);
|
||||
public void Add(SpeedAdjustmentContainer speedAdjustment) => barLineContainer.Add(speedAdjustment);
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
@ -216,10 +222,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
switch (args.Key)
|
||||
{
|
||||
case Key.Minus:
|
||||
transformTimeSpanTo(TimeSpan + time_span_step, 200, EasingTypes.OutQuint);
|
||||
transformVisibleTimeRangeTo(visibleTimeRange + time_span_step, 200, EasingTypes.OutQuint);
|
||||
break;
|
||||
case Key.Plus:
|
||||
transformTimeSpanTo(TimeSpan - time_span_step, 200, EasingTypes.OutQuint);
|
||||
transformVisibleTimeRangeTo(visibleTimeRange - time_span_step, 200, EasingTypes.OutQuint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -227,29 +233,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
return false;
|
||||
}
|
||||
|
||||
private double timeSpan;
|
||||
/// <summary>
|
||||
/// The amount of time which the length of the playfield spans.
|
||||
/// </summary>
|
||||
public double TimeSpan
|
||||
private void transformVisibleTimeRangeTo(double newTimeRange, double duration = 0, EasingTypes easing = EasingTypes.None)
|
||||
{
|
||||
get { return timeSpan; }
|
||||
set
|
||||
{
|
||||
if (timeSpan == value)
|
||||
return;
|
||||
timeSpan = value;
|
||||
|
||||
timeSpan = MathHelper.Clamp(timeSpan, time_span_min, time_span_max);
|
||||
|
||||
barLineContainer.TimeSpan = value;
|
||||
Columns.ForEach(c => c.ControlPointContainer.TimeSpan = value);
|
||||
}
|
||||
}
|
||||
|
||||
private void transformTimeSpanTo(double newTimeSpan, double duration = 0, EasingTypes easing = EasingTypes.None)
|
||||
{
|
||||
TransformTo(() => TimeSpan, newTimeSpan, duration, easing, new TransformTimeSpan());
|
||||
TransformTo(newTimeRange, duration, easing, new TransformTimeSpan());
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -259,9 +245,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
barLineContainer.Width = columns.Width;
|
||||
}
|
||||
|
||||
private class TransformTimeSpan : Transform<double>
|
||||
private class TransformTimeSpan : Transform<double, Drawable>
|
||||
{
|
||||
public override double CurrentValue
|
||||
public double CurrentValue
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -273,13 +259,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
public override void Apply(Drawable d)
|
||||
{
|
||||
base.Apply(d);
|
||||
|
||||
var p = (ManiaPlayfield)d;
|
||||
p.TimeSpan = CurrentValue;
|
||||
}
|
||||
public override void Apply(Drawable d) => ((ManiaPlayfield)d).visibleTimeRange.Value = (float)CurrentValue;
|
||||
public override void ReadIntoStartValue(Drawable d) => StartValue = ((ManiaPlayfield)d).visibleTimeRange.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,9 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
@ -62,6 +63,7 @@
|
||||
<Compile Include="Judgements\ManiaHitResult.cs" />
|
||||
<Compile Include="Judgements\ManiaJudgement.cs" />
|
||||
<Compile Include="ManiaDifficultyCalculator.cs" />
|
||||
<Compile Include="Mods\IGenerateSpeedAdjustments.cs" />
|
||||
<Compile Include="Objects\Drawables\DrawableBarLine.cs" />
|
||||
<Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
|
||||
<Compile Include="Objects\Drawables\DrawableHoldNoteTick.cs" />
|
||||
@ -77,14 +79,17 @@
|
||||
<Compile Include="Objects\ManiaHitObject.cs" />
|
||||
<Compile Include="Objects\Note.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Timing\BasicScrollingDrawableTimingSection.cs" />
|
||||
<Compile Include="Timing\GravityScrollingDrawableTimingSection.cs" />
|
||||
<Compile Include="Timing\ScrollingAlgorithm.cs" />
|
||||
<Compile Include="UI\Column.cs" />
|
||||
<Compile Include="UI\ManiaHitRenderer.cs" />
|
||||
<Compile Include="UI\ManiaPlayfield.cs" />
|
||||
<Compile Include="ManiaRuleset.cs" />
|
||||
<Compile Include="Mods\ManiaMod.cs" />
|
||||
<Compile Include="Mods\ManiaModGravity.cs" />
|
||||
<Compile Include="UI\SpecialColumnPosition.cs" />
|
||||
<Compile Include="Timing\ControlPointContainer.cs" />
|
||||
<Compile Include="Timing\TimingChange.cs" />
|
||||
<Compile Include="Timing\ManiaSpeedAdjustmentContainer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||
|
@ -1,9 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" />
|
||||
</packages>
|
@ -6,7 +6,7 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
Masking = true;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
CornerRadius = width / 2;
|
||||
EdgeEffect = new EdgeEffect
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = Color4.White.Opacity(0.2f),
|
||||
|
@ -89,11 +89,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
base.UpdateInitialState();
|
||||
|
||||
//sane defaults
|
||||
ring.Alpha = circle.Alpha = number.Alpha = glow.Alpha = 1;
|
||||
ApproachCircle.Alpha = 0;
|
||||
ApproachCircle.Scale = new Vector2(4);
|
||||
explode.Alpha = 0;
|
||||
// sane defaults
|
||||
ring.Show();
|
||||
circle.Show();
|
||||
number.Show();
|
||||
glow.Show();
|
||||
|
||||
ApproachCircle.Hide();
|
||||
ApproachCircle.ScaleTo(new Vector2(4));
|
||||
explode.Hide();
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
@ -106,43 +110,45 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
{
|
||||
ApproachCircle.FadeOut();
|
||||
double duration = ((HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime) - HitObject.StartTime;
|
||||
|
||||
double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||
double duration = endTime - HitObject.StartTime;
|
||||
|
||||
glow.Delay(duration);
|
||||
glow.FadeOut(400);
|
||||
using (glow.BeginDelayedSequence(duration))
|
||||
glow.FadeOut(400);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Idle:
|
||||
Delay(duration + TIME_PREEMPT);
|
||||
FadeOut(TIME_FADEOUT);
|
||||
using (BeginDelayedSequence(duration + TIME_PREEMPT))
|
||||
FadeOut(TIME_FADEOUT);
|
||||
Expire(true);
|
||||
break;
|
||||
case ArmedState.Miss:
|
||||
ApproachCircle.FadeOut(50);
|
||||
FadeOut(TIME_FADEOUT / 5);
|
||||
Expire();
|
||||
break;
|
||||
case ArmedState.Hit:
|
||||
ApproachCircle.FadeOut(50);
|
||||
|
||||
const double flash_in = 40;
|
||||
|
||||
flash.FadeTo(0.8f, flash_in);
|
||||
flash.Delay(flash_in);
|
||||
flash.FadeOut(100);
|
||||
using (flash.BeginDelayedSequence(flash_in))
|
||||
flash.FadeOut(100);
|
||||
|
||||
explode.FadeIn(flash_in);
|
||||
|
||||
Delay(flash_in, true);
|
||||
using (BeginDelayedSequence(flash_in, true))
|
||||
{
|
||||
//after the flash, we can hide some elements that were behind it
|
||||
ring.FadeOut();
|
||||
circle.FadeOut();
|
||||
number.FadeOut();
|
||||
|
||||
//after the flash, we can hide some elements that were behind it
|
||||
ring.FadeOut();
|
||||
circle.FadeOut();
|
||||
number.FadeOut();
|
||||
FadeOut(800);
|
||||
ScaleTo(Scale * 1.5f, 400, EasingTypes.OutQuad);
|
||||
}
|
||||
|
||||
FadeOut(800);
|
||||
ScaleTo(Scale * 1.5f, 400, EasingTypes.OutQuad);
|
||||
Expire();
|
||||
break;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
: base(hitObject)
|
||||
{
|
||||
AccentColour = HitObject.ComboColour;
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.Hit300 };
|
||||
@ -25,10 +26,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
Flush();
|
||||
|
||||
UpdateInitialState();
|
||||
|
||||
using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true))
|
||||
{
|
||||
UpdateInitialState();
|
||||
|
||||
UpdatePreemptState();
|
||||
|
||||
using (BeginDelayedSequence(TIME_PREEMPT + Judgement.TimeOffset, true))
|
||||
@ -36,8 +37,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateCurrentState(ArmedState state)
|
||||
protected virtual void UpdateInitialState()
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
protected virtual void UpdatePreemptState()
|
||||
@ -45,9 +47,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
FadeIn(TIME_FADEIN);
|
||||
}
|
||||
|
||||
protected virtual void UpdateInitialState()
|
||||
protected virtual void UpdateCurrentState(ArmedState state)
|
||||
{
|
||||
Alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public DrawableSlider(Slider s) : base(s)
|
||||
{
|
||||
// Since the DrawableSlider itself is just a container without a size we need to
|
||||
// pass all input through.
|
||||
AlwaysReceiveInput = true;
|
||||
|
||||
SliderBouncer bouncer1;
|
||||
slider = s;
|
||||
|
||||
@ -129,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
if (!userTriggered && Time.Current >= slider.EndTime)
|
||||
{
|
||||
var ticksCount = ticks.Children.Count() + 1;
|
||||
var ticksCount = ticks.Children.Count + 1;
|
||||
var ticksHit = ticks.Children.Count(t => t.Judgement.Result == HitResult.Hit);
|
||||
if (initialCircle.Judgement.Result == HitResult.Hit)
|
||||
ticksHit++;
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
|
@ -38,8 +38,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public DrawableSpinner(Spinner s) : base(s)
|
||||
{
|
||||
AlwaysReceiveInput = true;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
Position = s.Position;
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
@ -31,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
Masking = true,
|
||||
Origin = Anchor.Centre,
|
||||
EdgeEffect = new EdgeEffect
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 60,
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
base.Update();
|
||||
|
||||
if (Time.Current < slider.EndTime)
|
||||
Tracking = canCurrentlyTrack && lastState != null && Contains(lastState.Mouse.NativeState.Position) && lastState.Mouse.HasMainButtonPressed;
|
||||
Tracking = canCurrentlyTrack && lastState != null && ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && lastState.Mouse.HasMainButtonPressed;
|
||||
}
|
||||
|
||||
public void UpdateProgress(double progress, int repeat)
|
||||
|
@ -37,8 +37,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
icon.RotateTo(360, 1000);
|
||||
icon.Loop();
|
||||
using (icon.BeginLoopedSequence())
|
||||
icon.RotateTo(360, 1000);
|
||||
}
|
||||
|
||||
public void UpdateProgress(double progress, int repeat)
|
||||
|
@ -4,7 +4,7 @@
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
Disc.Colour = value;
|
||||
|
||||
EdgeEffect = new EdgeEffect
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Hollow = true,
|
||||
Type = EdgeEffectType.Glow,
|
||||
|
@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
spinner = s;
|
||||
|
||||
AlwaysReceiveInput = true;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
@ -40,6 +39,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
};
|
||||
}
|
||||
|
||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
private bool tracking;
|
||||
public bool Tracking
|
||||
{
|
||||
|
@ -5,9 +5,9 @@ using System;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.4f,
|
||||
EdgeEffect = new EdgeEffect
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 10,
|
||||
|
@ -1,201 +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 OpenTK;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
internal class OsuHitObjectDifficulty
|
||||
{
|
||||
/// <summary>
|
||||
/// Factor by how much speed / aim strain decays per second.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These values are results of tweaking a lot and taking into account general feedback.
|
||||
/// Opinionated observation: Speed is easier to maintain than accurate jumps.
|
||||
/// </remarks>
|
||||
internal static readonly double[] DECAY_BASE = { 0.3, 0.15 };
|
||||
|
||||
/// <summary>
|
||||
/// Pseudo threshold values to distinguish between "singles" and "streams"
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Of course the border can not be defined clearly, therefore the algorithm has a smooth transition between those values.
|
||||
/// They also are based on tweaking and general feedback.
|
||||
/// </remarks>
|
||||
private const double stream_spacing_threshold = 110,
|
||||
single_spacing_threshold = 125;
|
||||
|
||||
/// <summary>
|
||||
/// Scaling values for weightings to keep aim and speed difficulty in balance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Found from testing a very large map pool (containing all ranked maps) and keeping the average values the same.
|
||||
/// </remarks>
|
||||
private static readonly double[] spacing_weight_scaling = { 1400, 26.25 };
|
||||
|
||||
/// <summary>
|
||||
/// Almost the normed diameter of a circle (104 osu pixel). That is -after- position transforming.
|
||||
/// </summary>
|
||||
private const double almost_diameter = 90;
|
||||
|
||||
internal OsuHitObject BaseHitObject;
|
||||
internal double[] Strains = { 1, 1 };
|
||||
|
||||
internal int MaxCombo = 1;
|
||||
|
||||
private readonly float scalingFactor;
|
||||
private float lazySliderLength;
|
||||
|
||||
private readonly Vector2 startPosition;
|
||||
private readonly Vector2 endPosition;
|
||||
|
||||
internal OsuHitObjectDifficulty(OsuHitObject baseHitObject)
|
||||
{
|
||||
BaseHitObject = baseHitObject;
|
||||
float circleRadius = baseHitObject.Scale * 64;
|
||||
|
||||
Slider slider = BaseHitObject as Slider;
|
||||
if (slider != null)
|
||||
MaxCombo += slider.Ticks.Count();
|
||||
|
||||
// We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps.
|
||||
scalingFactor = 52.0f / circleRadius;
|
||||
if (circleRadius < 30)
|
||||
{
|
||||
float smallCircleBonus = Math.Min(30.0f - circleRadius, 5.0f) / 50.0f;
|
||||
scalingFactor *= 1.0f + smallCircleBonus;
|
||||
}
|
||||
|
||||
lazySliderLength = 0;
|
||||
startPosition = baseHitObject.StackedPosition;
|
||||
|
||||
// Calculate approximation of lazy movement on the slider
|
||||
if (slider != null)
|
||||
{
|
||||
float sliderFollowCircleRadius = circleRadius * 3; // Not sure if this is correct, but here we do not need 100% exact values. This comes pretty darn close in my tests.
|
||||
|
||||
// For simplifying this step we use actual osu! coordinates and simply scale the length, that we obtain by the ScalingFactor later
|
||||
Vector2 cursorPos = startPosition;
|
||||
|
||||
Action<Vector2> addSliderVertex = delegate (Vector2 pos)
|
||||
{
|
||||
Vector2 difference = pos - cursorPos;
|
||||
float distance = difference.Length;
|
||||
|
||||
// Did we move away too far?
|
||||
if (distance > sliderFollowCircleRadius)
|
||||
{
|
||||
// Yep, we need to move the cursor
|
||||
difference.Normalize(); // Obtain the direction of difference. We do no longer need the actual difference
|
||||
distance -= sliderFollowCircleRadius;
|
||||
cursorPos += difference * distance; // We move the cursor just as far as needed to stay in the follow circle
|
||||
lazySliderLength += distance;
|
||||
}
|
||||
};
|
||||
|
||||
// Actual computation of the first lazy curve
|
||||
foreach (var tick in slider.Ticks)
|
||||
addSliderVertex(tick.StackedPosition);
|
||||
|
||||
addSliderVertex(baseHitObject.StackedEndPosition);
|
||||
|
||||
lazySliderLength *= scalingFactor;
|
||||
endPosition = cursorPos;
|
||||
}
|
||||
// We have a normal HitCircle or a spinner
|
||||
else
|
||||
endPosition = startPosition;
|
||||
}
|
||||
|
||||
internal void CalculateStrains(OsuHitObjectDifficulty previousHitObject, double timeRate)
|
||||
{
|
||||
calculateSpecificStrain(previousHitObject, OsuDifficultyCalculator.DifficultyType.Speed, timeRate);
|
||||
calculateSpecificStrain(previousHitObject, OsuDifficultyCalculator.DifficultyType.Aim, timeRate);
|
||||
}
|
||||
|
||||
// Caution: The subjective values are strong with this one
|
||||
private static double spacingWeight(double distance, OsuDifficultyCalculator.DifficultyType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OsuDifficultyCalculator.DifficultyType.Speed:
|
||||
if (distance > single_spacing_threshold)
|
||||
return 2.5;
|
||||
else if (distance > stream_spacing_threshold)
|
||||
return 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
|
||||
else if (distance > almost_diameter)
|
||||
return 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
|
||||
else if (distance > almost_diameter / 2)
|
||||
return 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
|
||||
else
|
||||
return 0.95;
|
||||
|
||||
case OsuDifficultyCalculator.DifficultyType.Aim:
|
||||
return Math.Pow(distance, 0.99);
|
||||
}
|
||||
|
||||
Debug.Assert(false, "Invalid osu difficulty hit object type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void calculateSpecificStrain(OsuHitObjectDifficulty previousHitObject, OsuDifficultyCalculator.DifficultyType type, double timeRate)
|
||||
{
|
||||
double addition = 0;
|
||||
double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate;
|
||||
double decay = Math.Pow(DECAY_BASE[(int)type], timeElapsed / 1000);
|
||||
|
||||
if (BaseHitObject is Spinner)
|
||||
{
|
||||
// Do nothing for spinners
|
||||
}
|
||||
else if (BaseHitObject is Slider)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OsuDifficultyCalculator.DifficultyType.Speed:
|
||||
|
||||
// For speed strain we treat the whole slider as a single spacing entity, since "Speed" is about how hard it is to click buttons fast.
|
||||
// The spacing weight exists to differentiate between being able to easily alternate or having to single.
|
||||
addition =
|
||||
spacingWeight(previousHitObject.lazySliderLength +
|
||||
DistanceTo(previousHitObject), type) *
|
||||
spacing_weight_scaling[(int)type];
|
||||
|
||||
break;
|
||||
case OsuDifficultyCalculator.DifficultyType.Aim:
|
||||
|
||||
// For Aim strain we treat each slider segment and the jump after the end of the slider as separate jumps, since movement-wise there is no difference
|
||||
// to multiple jumps.
|
||||
addition =
|
||||
(
|
||||
spacingWeight(previousHitObject.lazySliderLength, type) +
|
||||
spacingWeight(DistanceTo(previousHitObject), type)
|
||||
) *
|
||||
spacing_weight_scaling[(int)type];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (BaseHitObject is HitCircle)
|
||||
{
|
||||
addition = spacingWeight(DistanceTo(previousHitObject), type) * spacing_weight_scaling[(int)type];
|
||||
}
|
||||
|
||||
// Scale addition by the time, that elapsed. Filter out HitObjects that are too close to be played anyway to avoid crazy values by division through close to zero.
|
||||
// You will never find maps that require this amongst ranked maps.
|
||||
addition /= Math.Max(timeElapsed, 50);
|
||||
|
||||
Strains[(int)type] = previousHitObject.Strains[(int)type] * decay + addition;
|
||||
}
|
||||
|
||||
internal double DistanceTo(OsuHitObjectDifficulty other)
|
||||
{
|
||||
// Scale the distance by circle size.
|
||||
return (startPosition - other.endPosition).Length * scalingFactor;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
// 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.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Skills;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
||||
{
|
||||
public class OsuDifficultyCalculator : DifficultyCalculator<OsuHitObject>
|
||||
{
|
||||
private const int section_length = 400;
|
||||
private const double difficulty_multiplier = 0.0675;
|
||||
|
||||
public OsuDifficultyCalculator(Beatmap beatmap) : base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void PreprocessHitObjects()
|
||||
{
|
||||
foreach (OsuHitObject h in Objects)
|
||||
(h as Slider)?.Curve?.Calculate();
|
||||
}
|
||||
|
||||
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
|
||||
{
|
||||
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Objects);
|
||||
Skill[] skills =
|
||||
{
|
||||
new Aim(),
|
||||
new Speed()
|
||||
};
|
||||
|
||||
double sectionEnd = section_length / TimeRate;
|
||||
foreach (OsuDifficultyHitObject h in beatmap)
|
||||
{
|
||||
while (h.BaseObject.StartTime > sectionEnd)
|
||||
{
|
||||
foreach (Skill s in skills)
|
||||
{
|
||||
s.SaveCurrentPeak();
|
||||
s.StartNewSectionFrom(sectionEnd);
|
||||
}
|
||||
|
||||
sectionEnd += section_length;
|
||||
}
|
||||
|
||||
foreach (Skill s in skills)
|
||||
s.Process(h);
|
||||
}
|
||||
|
||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||
|
||||
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
|
||||
|
||||
if (categoryDifficulty != null)
|
||||
{
|
||||
categoryDifficulty.Add("Aim", aimRating.ToString("0.00"));
|
||||
categoryDifficulty.Add("Speed", speedRating.ToString("0.00"));
|
||||
}
|
||||
|
||||
return starRating;
|
||||
}
|
||||
|
||||
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||
{
|
||||
/// <summary>
|
||||
/// An enumerable container wrapping <see cref="OsuHitObject"/> input as <see cref="OsuDifficultyHitObject"/>
|
||||
/// which contains extra data required for difficulty calculation.
|
||||
/// </summary>
|
||||
public class OsuDifficultyBeatmap : IEnumerable<OsuDifficultyHitObject>
|
||||
{
|
||||
private readonly IEnumerator<OsuDifficultyHitObject> difficultyObjects;
|
||||
private readonly Queue<OsuDifficultyHitObject> onScreen = new Queue<OsuDifficultyHitObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an enumerator, which preprocesses a list of <see cref="OsuHitObject"/>s recieved as input, wrapping them as
|
||||
/// <see cref="OsuDifficultyHitObject"/> which contains extra data required for difficulty calculation.
|
||||
/// </summary>
|
||||
public OsuDifficultyBeatmap(List<OsuHitObject> objects)
|
||||
{
|
||||
// Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
|
||||
// This should probably happen before the objects reach the difficulty calculator.
|
||||
objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
|
||||
difficultyObjects = createDifficultyObjectEnumerator(objects);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that enumerates all <see cref="OsuDifficultyHitObject"/>s in the <see cref="OsuDifficultyBeatmap"/>.
|
||||
/// The inner loop adds objects that appear on screen into a queue until we need to hit the next object.
|
||||
/// The outer loop returns objects from this queue one at a time, only after they had to be hit, and should no longer be on screen.
|
||||
/// This means that we can loop through every object that is on screen at the time when a new one appears,
|
||||
/// allowing us to determine a reading strain for the object that just appeared.
|
||||
/// </summary>
|
||||
public IEnumerator<OsuDifficultyHitObject> GetEnumerator()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Add upcoming objects to the queue until we have at least one object that had been hit and can be dequeued.
|
||||
// This means there is always at least one object in the queue unless we reached the end of the map.
|
||||
do
|
||||
{
|
||||
if (!difficultyObjects.MoveNext())
|
||||
break; // New objects can't be added anymore, but we still need to dequeue and return the ones already on screen.
|
||||
|
||||
OsuDifficultyHitObject latest = difficultyObjects.Current;
|
||||
// Calculate flow values here
|
||||
|
||||
foreach (OsuDifficultyHitObject h in onScreen)
|
||||
{
|
||||
h.TimeUntilHit -= latest.DeltaTime;
|
||||
// Calculate reading strain here
|
||||
}
|
||||
|
||||
onScreen.Enqueue(latest);
|
||||
}
|
||||
while (onScreen.Peek().TimeUntilHit > 0); // Keep adding new objects on screen while there is still time before we have to hit the next one.
|
||||
|
||||
if (onScreen.Count == 0) break; // We have reached the end of the map and enumerated all the objects.
|
||||
yield return onScreen.Dequeue(); // Remove and return objects one by one that had to be hit before the latest one appeared.
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
private IEnumerator<OsuDifficultyHitObject> createDifficultyObjectEnumerator(List<OsuHitObject> objects)
|
||||
{
|
||||
// We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object.
|
||||
OsuHitObject[] triangle = new OsuHitObject[3];
|
||||
|
||||
// OsuDifficultyHitObject construction requires three components, an extra copy of the first OsuHitObject is used at the beginning.
|
||||
if (objects.Count > 1)
|
||||
{
|
||||
triangle[1] = objects[0]; // This copy will get shifted to the last spot in the triangle.
|
||||
triangle[0] = objects[0]; // This component corresponds to the real first OsuHitOject.
|
||||
}
|
||||
|
||||
// The final component of the first triangle will be the second OsuHitOject of the map, which forms the first jump.
|
||||
// If the map has less than two OsuHitObjects, the enumerator will not return anything.
|
||||
for (int i = 1; i < objects.Count; ++i)
|
||||
{
|
||||
triangle[2] = triangle[1];
|
||||
triangle[1] = triangle[0];
|
||||
triangle[0] = objects[i];
|
||||
|
||||
yield return new OsuDifficultyHitObject(triangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
// 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.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
||||
/// </summary>
|
||||
public class OsuDifficultyHitObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="OsuHitObject"/> this <see cref="OsuDifficultyHitObject"/> refers to.
|
||||
/// </summary>
|
||||
public OsuHitObject BaseObject { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized distance from the <see cref="OsuHitObject.StackedPosition"/> of the previous <see cref="OsuDifficultyHitObject"/>.
|
||||
/// </summary>
|
||||
public double Distance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Milliseconds elapsed since the StartTime of the previous <see cref="OsuDifficultyHitObject"/>.
|
||||
/// </summary>
|
||||
public double DeltaTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of milliseconds until the <see cref="OsuDifficultyHitObject"/> has to be hit.
|
||||
/// </summary>
|
||||
public double TimeUntilHit { get; set; }
|
||||
|
||||
private const int normalized_radius = 52;
|
||||
|
||||
private readonly OsuHitObject[] t;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the object calculating extra data required for difficulty calculation.
|
||||
/// </summary>
|
||||
public OsuDifficultyHitObject(OsuHitObject[] triangle)
|
||||
{
|
||||
t = triangle;
|
||||
BaseObject = t[0];
|
||||
setDistances();
|
||||
setTimingValues();
|
||||
// Calculate angle here
|
||||
}
|
||||
|
||||
private void setDistances()
|
||||
{
|
||||
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
||||
double scalingFactor = normalized_radius / BaseObject.Radius;
|
||||
if (BaseObject.Radius < 30)
|
||||
{
|
||||
double smallCircleBonus = Math.Min(30 - BaseObject.Radius, 5) / 50;
|
||||
scalingFactor *= 1 + smallCircleBonus;
|
||||
}
|
||||
|
||||
Distance = (t[0].StackedPosition - t[1].StackedPosition).Length * scalingFactor;
|
||||
}
|
||||
|
||||
private void setTimingValues()
|
||||
{
|
||||
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
||||
DeltaTime = Math.Max(40, t[0].StartTime - t[1].StartTime);
|
||||
TimeUntilHit = 450; // BaseObject.PreEmpt;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user