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

Merge branch 'master' of git://github.com/ppy/osu into tooltips

# Conflicts:
#	osu.Game/Graphics/Cursor/MenuCursor.cs
This commit is contained in:
Jorolf 2017-04-13 23:12:07 +02:00
commit f6f75fac74
221 changed files with 3921 additions and 2284 deletions

4
.vscode/launch.json vendored
View File

@ -11,7 +11,7 @@
"preLaunchTask": "build",
"runtimeExecutable": null,
"env": {},
"externalConsole": false
"console": "internalConsole"
},
{
"name": "Launch Desktop",
@ -23,7 +23,7 @@
"preLaunchTask": "build",
"runtimeExecutable": null,
"env": {},
"externalConsole": false
"console": "internalConsole"
},
{
"name": "Attach",

24
.vscode/tasks.json vendored
View File

@ -2,25 +2,23 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"windows": {
"command": "msbuild"
},
"linux": {
"command": "xbuild"
},
"args": [
// Ask msbuild to generate full paths for file names.
"/property:GenerateFullPaths=true"
],
"taskSelector": "/t:",
"showOutput": "silent",
"tasks": [
{
"taskName": "build",
// Show the output window only if unrecognized errors occur.
"isShellCommand": true,
"showOutput": "silent",
"command": "xbuild",
"windows": {
"command": "msbuild"
},
"args": [
// Ask msbuild to generate full paths for file names.
"/property:GenerateFullPaths=true"
],
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"isBuildCommand": true
}
]
}

View File

@ -10,7 +10,7 @@ install:
- cmd: git submodule update --init --recursive
- cmd: choco install resharper-clt -y
- cmd: choco install nvika -y
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.1/CodeFileSanity.exe
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.2/CodeFileSanity.exe
before_build:
- cmd: CodeFileSanity.exe
- cmd: nuget restore

@ -1 +1 @@
Subproject commit bf6a3dc40176ee4f921012808070e014fc4a5779
Subproject commit 2234013e59a99116ee9f9e56a95ff8a6667db2a7

@ -1 +1 @@
Subproject commit 12bbab717d372dadbd3220d38da862276ac97e98
Subproject commit 0cba3cbc167cfe94e07fe5b629c925e190be939e

View File

@ -21,4 +21,16 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="DeltaCompressionDotNet.MsDelta" publicKeyToken="46b2138a390abf55" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<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>

View File

@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Desktop.Deploy")]
@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]

View File

@ -68,9 +68,8 @@
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<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="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>
@ -120,7 +119,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>

View File

@ -6,7 +6,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
<packages>
<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="9.0.1" 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="Splat" version="2.0.0" targetFramework="net452" />
<package id="squirrel.windows" version="1.5.2" targetFramework="net452" />

View File

@ -33,18 +33,17 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
<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>
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="Newtonsoft.Json">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SQLiteNetExtensions">
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
</Reference>

View File

@ -1,12 +1,11 @@
<?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="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="NUnit" version="3.5.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" />
<package id="NUnit" version="3.6.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" />

View File

@ -16,7 +16,7 @@ namespace osu.Desktop.VisualTests.Beatmaps
}
private readonly Beatmap beatmap;
protected override Beatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetTrack() => null;

View File

@ -15,7 +15,7 @@ namespace osu.Desktop.VisualTests.Platform
public TestStorage(string baseName) : base(baseName)
{
}
public override SQLiteConnection GetDatabase(string name)
{
ISQLitePlatform platform;

View File

@ -0,0 +1,65 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Screens.Select;
using System.Linq;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseBeatmapDetails : TestCase
{
public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
private BeatmapDetails details;
public override void Reset()
{
base.Reset();
Add(details = new BeatmapDetails
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(150),
Beatmap = new BeatmapInfo
{
Version = "VisualTest",
Metadata = new BeatmapMetadata
{
Source = "Some guy",
Tags = "beatmap metadata example with a very very long list of tags and not much creativity",
},
Difficulty = new BeatmapDifficulty
{
CircleSize = 7,
ApproachRate = 3.5f,
OverallDifficulty = 5.7f,
DrainRate = 1,
},
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
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),
},
},
});
AddRepeatStep("fail values", newRetryAndFailValues, 10);
}
private int lastRange = 1;
private void newRetryAndFailValues()
{
details.Beatmap.Metrics.Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6);
details.Beatmap.Metrics.Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6);
details.Beatmap = details.Beatmap;
lastRange += 100;
}
}
}

View File

@ -3,15 +3,12 @@
using osu.Framework.Testing;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseChatDisplay : TestCase
{
private ScheduledDelegate messageRequest;
public override string Description => @"Testing chat api and overlay";
public override void Reset()

View File

@ -0,0 +1,42 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using System.Linq;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseGraph : TestCase
{
public override string Description => "graph";
private BarGraph graph;
public override void Reset()
{
base.Reset();
Children = new[]
{
graph = new BarGraph
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(0.5f),
},
};
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);
AddStep("Top to bottom", () => graph.Direction = BarDirection.TopToBottom);
AddStep("Left to right", () => graph.Direction = BarDirection.LeftToRight);
AddStep("Right to left", () => graph.Direction = BarDirection.RightToLeft);
}
}
}

View File

@ -99,6 +99,7 @@ namespace osu.Desktop.VisualTests.Tests
AddToggleStep(@"auto", state => { auto = state; load(mode); });
BasicSliderBar<double> sliderBar;
Add(new Container
{
Anchor = Anchor.TopRight,
@ -107,16 +108,17 @@ namespace osu.Desktop.VisualTests.Tests
Children = new Drawable[]
{
new SpriteText { Text = "Playback Speed" },
new BasicSliderBar<double>
sliderBar = new BasicSliderBar<double>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Bindable = playbackSpeed
}
}
});
sliderBar.Current.BindTo(playbackSpeed);
framedClock.ProcessFrame();
var clockAdjustContainer = new Container

View File

@ -44,6 +44,8 @@ namespace osu.Desktop.VisualTests.Tests
kc.Add(new KeyCounterKeyboard(key));
});
TestSliderBar<int> sliderBar;
Add(new Container
{
Anchor = Anchor.TopRight,
@ -52,16 +54,17 @@ namespace osu.Desktop.VisualTests.Tests
Children = new Drawable[]
{
new SpriteText { Text = "FadeTime" },
new TestSliderBar<int>
sliderBar =new TestSliderBar<int>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Bindable = bindable
}
}
});
sliderBar.Current.BindTo(bindable);
Add(kc);
}
private class TestSliderBar<T> : SliderBar<T> where T : struct

View File

@ -0,0 +1,59 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Testing;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseMenuOverlays : TestCase
{
public override string Description => @"Tests pause and fail overlays";
private PauseOverlay pauseOverlay;
private FailOverlay failOverlay;
private int retryCount;
public override void Reset()
{
base.Reset();
retryCount = 0;
Add(pauseOverlay = new PauseOverlay
{
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
Add(failOverlay = new FailOverlay
{
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
AddStep(@"Pause", delegate {
if(failOverlay.State == Visibility.Visible)
{
failOverlay.Hide();
}
pauseOverlay.Show();
});
AddStep("Fail", delegate {
if (pauseOverlay.State == Visibility.Visible)
{
pauseOverlay.Hide();
}
failOverlay.Show();
});
AddStep("Add Retry", delegate
{
retryCount++;
pauseOverlay.Retries = retryCount;
failOverlay.Retries = retryCount;
});
}
}
}

View File

@ -30,7 +30,9 @@ namespace osu.Desktop.VisualTests.Tests
Anchor = Anchor.Centre
};
Add(mc);
AddToggleStep(@"Show", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
AddStep(@"show", () => mc.State = Visibility.Visible);
}
}
}

View File

@ -1,38 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Logging;
using osu.Framework.Testing;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCasePauseOverlay : TestCase
{
public override string Description => @"Tests the pause overlay";
private PauseOverlay pauseOverlay;
private int retryCount;
public override void Reset()
{
base.Reset();
Add(pauseOverlay = new PauseOverlay
{
Depth = -1,
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit")
});
AddStep("Pause", pauseOverlay.Show);
AddStep("Add Retry", delegate
{
retryCount++;
pauseOverlay.Retries = retryCount;
});
retryCount = 0;
}
}
}

View File

@ -14,7 +14,7 @@ namespace osu.Desktop.VisualTests.Tests
{
internal class TestCasePlaySongSelect : TestCase
{
private BeatmapDatabase db, oldDb;
private BeatmapDatabase db;
private TestStorage storage;
private PlaySongSelect songSelect;
@ -44,13 +44,13 @@ namespace osu.Desktop.VisualTests.Tests
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
}
protected override void Dispose(bool isDisposing)
{
if (oldDb != null)
db = null;
//protected override void Dispose(bool isDisposing)
//{
// if (oldDb != null)
// db = null;
base.Dispose(isDisposing);
}
// base.Dispose(isDisposing);
//}
private BeatmapSetInfo createTestBeatmapSet(int i)
{

View File

@ -83,10 +83,7 @@ namespace osu.Desktop.VisualTests.Tests
Colour = Color4.Black,
});
Add(new PlayerLoader(Player = CreatePlayer(beatmap))
{
Beatmap = beatmap
});
Add(Player = CreatePlayer(beatmap));
}
protected virtual Player CreatePlayer(WorkingBeatmap beatmap)

View File

@ -1,24 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Handlers;
using osu.Game.Beatmaps;
using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Mods;
using osu.Game.Screens.Play;
using System;
using System.IO;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseReplay : TestCasePlayer
{
private WorkingBeatmap beatmap;
private InputHandler replay;
private Func<Stream> getReplayStream;
public override string Description => @"Testing replay playback.";
protected override Player CreatePlayer(WorkingBeatmap beatmap)

View File

@ -22,8 +22,6 @@ namespace osu.Desktop.VisualTests.Tests
int numerator = 0, denominator = 0;
bool maniaHold = false;
ScoreCounter score = new ScoreCounter(7)
{
Origin = Anchor.TopRight,

View File

@ -36,9 +36,9 @@ namespace osu.Desktop.VisualTests.Tests
filter.PinItem(GroupMode.All);
filter.PinItem(GroupMode.RecentlyPlayed);
filter.ItemChanged += (sender, mode) =>
filter.Current.ValueChanged += newFilter =>
{
text.Text = "Currently Selected: " + mode.ToString();
text.Text = "Currently Selected: " + newFilter.ToString();
};
}
}

View File

@ -1,13 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Desktop.VisualTests.Tests
{
@ -24,13 +23,12 @@ namespace osu.Desktop.VisualTests.Tests
AddToggleStep("Kiai", b =>
{
kiai = !kiai;
Reset();
updateKiaiState();
});
Add(new CirclePiece
{
Position = new Vector2(100, 100),
Width = 0,
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
@ -39,10 +37,9 @@ namespace osu.Desktop.VisualTests.Tests
}
});
Add(new StrongCirclePiece
Add(new CirclePiece(true)
{
Position = new Vector2(350, 100),
Width = 0,
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
@ -54,7 +51,6 @@ namespace osu.Desktop.VisualTests.Tests
Add(new CirclePiece
{
Position = new Vector2(100, 300),
Width = 0,
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
@ -63,10 +59,9 @@ namespace osu.Desktop.VisualTests.Tests
}
});
Add(new StrongCirclePiece
Add(new CirclePiece(true)
{
Position = new Vector2(350, 300),
Width = 0,
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
@ -78,7 +73,6 @@ namespace osu.Desktop.VisualTests.Tests
Add(new CirclePiece
{
Position = new Vector2(100, 500),
Width = 0,
AccentColour = Color4.Orange,
KiaiMode = kiai,
Children = new[]
@ -87,37 +81,29 @@ namespace osu.Desktop.VisualTests.Tests
}
});
Add(new DrumRollCircle(new CirclePiece
Add(new ElongatedCirclePiece
{
KiaiMode = kiai
})
{
Width = 250,
Position = new Vector2(575, 100)
Position = new Vector2(575, 100),
AccentColour = Color4.Orange,
KiaiMode = kiai,
Length = 0.10f,
PlayfieldLengthReference = () => DrawSize.X
});
Add(new DrumRollCircle(new StrongCirclePiece
Add(new ElongatedCirclePiece(true)
{
KiaiMode = kiai
})
{
Width = 250,
Position = new Vector2(575, 300)
Position = new Vector2(575, 300),
AccentColour = Color4.Orange,
KiaiMode = kiai,
Length = 0.10f,
PlayfieldLengthReference = () => DrawSize.X
});
}
private class DrumRollCircle : BaseCircle
private void updateKiaiState()
{
public DrumRollCircle(CirclePiece piece)
: base(piece)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Piece.AccentColour = colours.YellowDark;
}
foreach (var c in Children.OfType<CirclePiece>())
c.KiaiMode = kiai;
}
private abstract class BaseCircle : Container

View File

@ -1,24 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.MathUtils;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.Objects.Drawable;
using osu.Game.Modes.Taiko.Objects.Drawables;
using osu.Game.Modes.Taiko.UI;
using System;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseTaikoPlayfield : TestCase
{
private const double default_duration = 300;
private const float scroll_time = 1000;
public override string Description => "Taiko playfield";
protected override double TimePerAction => default_duration * 2;
private readonly Random rng = new Random(1337);
private TaikoPlayfield playfield;
private Container playfieldContainer;
public override void Reset()
{
@ -26,17 +35,31 @@ namespace osu.Desktop.VisualTests.Tests
AddStep("Hit!", addHitJudgement);
AddStep("Miss :(", addMissJudgement);
AddStep("Swell", addSwell);
AddStep("DrumRoll", () => addDrumRoll(false));
AddStep("Strong DrumRoll", () => addDrumRoll(true));
AddStep("Swell", () => addSwell());
AddStep("Centre", () => addCentreHit(false));
AddStep("Strong Centre", () => addCentreHit(true));
AddStep("Rim", () => addRimHit(false));
AddStep("Strong Rim", () => addRimHit(true));
AddStep("Add bar line", () => addBarLine(false));
AddStep("Add major bar line", () => addBarLine(true));
AddStep("Height test 1", () => changePlayfieldSize(1));
AddStep("Height test 2", () => changePlayfieldSize(2));
AddStep("Height test 3", () => changePlayfieldSize(3));
AddStep("Height test 4", () => changePlayfieldSize(4));
AddStep("Height test 5", () => changePlayfieldSize(5));
AddStep("Reset height", () => changePlayfieldSize(6));
Add(new Container
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
Add(playfieldContainer = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Y = 200,
Padding = new MarginPadding { Left = 200 },
Height = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT,
Clock = new FramedClock(rateAdjustClock),
Children = new[]
{
playfield = new TaikoPlayfield()
@ -44,21 +67,63 @@ namespace osu.Desktop.VisualTests.Tests
});
}
private void changePlayfieldSize(int step)
{
// Add new hits
switch (step)
{
case 1:
addCentreHit(false);
break;
case 2:
addCentreHit(true);
break;
case 3:
addDrumRoll(false);
break;
case 4:
addDrumRoll(true);
break;
case 5:
addSwell(1000);
playfieldContainer.Delay(scroll_time - 100);
break;
}
// Tween playfield height
switch (step)
{
default:
playfieldContainer.ResizeTo(new Vector2(1, rng.Next(25, 400)), 500);
break;
case 6:
playfieldContainer.ResizeTo(new Vector2(1, TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT), 500);
break;
}
}
private void addHitJudgement()
{
TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great;
playfield.OnJudgement(new DrawableTestHit(new Hit())
var h = new DrawableTestHit(new Hit())
{
X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f),
Judgement = new TaikoJudgement
{
Result = HitResult.Hit,
TaikoResult = hitResult,
TimeOffset = 0,
SecondHit = RNG.Next(10) == 0
TimeOffset = 0
}
});
};
playfield.OnJudgement(h);
if (RNG.Next(10) == 0)
{
h.Judgement.SecondHit = true;
playfield.OnJudgement(h);
}
}
private void addMissJudgement()
@ -73,26 +138,53 @@ namespace osu.Desktop.VisualTests.Tests
});
}
private void addSwell()
private void addBarLine(bool major, double delay = scroll_time)
{
BarLine bl = new BarLine
{
StartTime = playfield.Time.Current + delay,
ScrollTime = scroll_time
};
playfield.AddBarLine(major ? new DrawableBarLineMajor(bl) : new DrawableBarLine(bl));
}
private void addSwell(double duration = default_duration)
{
playfield.Add(new DrawableSwell(new Swell
{
StartTime = Time.Current + 1000,
EndTime = Time.Current + 5000,
PreEmpt = 1000
StartTime = playfield.Time.Current + scroll_time,
Duration = duration,
ScrollTime = scroll_time
}));
}
private void addDrumRoll(bool strong, double duration = default_duration)
{
addBarLine(true);
addBarLine(true, scroll_time + duration);
var d = new DrumRoll
{
StartTime = playfield.Time.Current + scroll_time,
IsStrong = strong,
Duration = duration,
ScrollTime = scroll_time,
};
playfield.Add(new DrawableDrumRoll(d));
}
private void addCentreHit(bool strong)
{
Hit h = new Hit
{
StartTime = Time.Current + 1000,
PreEmpt = 1000
StartTime = playfield.Time.Current + scroll_time,
ScrollTime = scroll_time
};
if (strong)
playfield.Add(new DrawableStrongCentreHit(h));
playfield.Add(new DrawableCentreHitStrong(h));
else
playfield.Add(new DrawableCentreHit(h));
}
@ -101,12 +193,12 @@ namespace osu.Desktop.VisualTests.Tests
{
Hit h = new Hit
{
StartTime = Time.Current + 1000,
PreEmpt = 1000
StartTime = playfield.Time.Current + scroll_time,
ScrollTime = scroll_time
};
if (strong)
playfield.Add(new DrawableStrongRimHit(h));
playfield.Add(new DrawableRimHitStrong(h));
else
playfield.Add(new DrawableRimHit(h));
}

View File

@ -14,7 +14,7 @@ namespace osu.Desktop.VisualTests
{
base.LoadComplete();
new BackgroundScreenDefault { Depth = 10 }.LoadAsync(this, AddInternal);
LoadComponentAsync(new BackgroundScreenDefault { Depth = 10 }, AddInternal);
// Have to construct this here, rather than in the constructor, because
// we depend on some dependencies to be loaded within OsuGameBase.load().

View File

@ -83,22 +83,20 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
<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="SharpCompress, Version=0.15.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>..\packages\SharpCompress.0.15.1\lib\net45\SharpCompress.dll</HintPath>
<Private>True</Private>
<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>
<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>
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="Newtonsoft.Json">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SQLiteNetExtensions">
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
</Reference>
@ -187,8 +185,11 @@
<Compile Include="AutomatedVisualTestGame.cs" />
<Compile Include="Program.cs" />
<Compile Include="Tests\TestCaseChatDisplay.cs" />
<Compile Include="Tests\TestCaseBeatmapDetails.cs" />
<Compile Include="Tests\TestCaseDrawings.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseGraph.cs" />
<Compile Include="Tests\TestCaseMenuOverlays.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" />
<Compile Include="Tests\TestCaseNotificationManager.cs" />
<Compile Include="Tests\TestCasePlayer.cs" />
@ -207,7 +208,6 @@
<Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseOptions.cs" />
<Compile Include="Tests\TestCasePauseOverlay.cs" />
<Compile Include="Tests\TestCaseModSelectOverlay.cs" />
<Compile Include="Tests\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />

View File

@ -4,9 +4,9 @@ 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="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1340" targetFramework="net45" />
<package id="SharpCompress" version="0.15.1" targetFramework="net45" />
<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="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" />

View File

@ -3,10 +3,7 @@
using System.IO;
using System.Linq;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using osu.Game.Beatmaps;
using osu.Game.Database;
namespace osu.Desktop.Beatmaps.IO
{
@ -18,20 +15,17 @@ namespace osu.Desktop.Beatmaps.IO
public static void Register() => AddReader<LegacyFilesystemReader>((storage, path) => Directory.Exists(path));
private string basePath { get; }
private Beatmap firstMap { get; }
public LegacyFilesystemReader(string path)
{
basePath = path;
BeatmapFilenames = Directory.GetFiles(basePath, @"*.osu").Select(Path.GetFileName).ToArray();
if (BeatmapFilenames.Length == 0)
throw new FileNotFoundException(@"This directory contains no beatmaps");
StoryboardFilename = Directory.GetFiles(basePath, @"*.osb").Select(Path.GetFileName).FirstOrDefault();
using (var stream = new StreamReader(GetStream(BeatmapFilenames[0])))
{
var decoder = BeatmapDecoder.GetDecoder(stream);
firstMap = decoder.Decode(stream);
}
}
public override Stream GetStream(string name)
@ -39,11 +33,6 @@ namespace osu.Desktop.Beatmaps.IO
return File.OpenRead(Path.Combine(basePath, name));
}
public override BeatmapMetadata ReadMetadata()
{
return firstMap.BeatmapInfo.Metadata;
}
public override void Dispose()
{
// no-op

View File

@ -29,7 +29,7 @@ namespace osu.Desktop
{
base.LoadComplete();
versionManager.LoadAsync(this);
LoadComponentAsync(versionManager);
ScreenChanged += s =>
{
if (!versionManager.IsAlive && s is Intro)

View File

@ -189,19 +189,24 @@ namespace osu.Desktop.Overlays
private class UpdateProgressNotification : ProgressNotification
{
private OsuGame game;
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification()
{
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
UpdateManager.RestartApp();
UpdateManager.RestartAppWhenExited();
game.GracefullyExit();
return true;
}
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OsuColour colours, OsuGame game)
{
this.game = game;
IconContent.Add(new Drawable[]
{
new Box

View File

@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu!lazer")]
@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

View File

@ -124,8 +124,7 @@
<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.1340\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
</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>

View File

@ -7,7 +7,7 @@ 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.1340" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
<package id="Splat" version="2.0.0" targetFramework="net45" />
<package id="squirrel.windows" version="1.5.2" targetFramework="net45" />
</packages>

View File

@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Catch")]
@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]

View File

@ -14,8 +14,7 @@ namespace osu.Game.Modes.Catch.UI
{
public CatchPlayfield()
{
RelativeSizeAxes = Axes.Y;
Size = new Vector2(512, 0.9f);
Size = new Vector2(1, 0.9f);
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;

View File

@ -33,8 +33,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -84,7 +83,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>

View File

@ -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.1340" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
</packages>

View File

@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Mania")]
@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]

View File

@ -15,8 +15,7 @@ namespace osu.Game.Modes.Mania.UI
{
public ManiaPlayfield(int columns)
{
RelativeSizeAxes = Axes.Both;
Size = new Vector2(columns / 20f, 1f);
Size = new Vector2(0.8f, 1f);
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;

View File

@ -33,8 +33,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -89,7 +88,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>

View File

@ -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.1340" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
</packages>

View File

@ -43,7 +43,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Slider
{
StartTime = original.StartTime,
Sample = original.Sample,
Samples = original.Samples,
CurveObject = curveData,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
@ -55,7 +55,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Spinner
{
StartTime = original.StartTime,
Sample = original.Sample,
Samples = original.Samples,
Position = new Vector2(512, 384) / 2,
EndTime = endTimeData.EndTime
};
@ -64,7 +64,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new HitCircle
{
StartTime = original.StartTime,
Sample = original.Sample,
Samples = original.Samples,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
};

View File

@ -32,7 +32,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Connections
Colour = Color4.White.Opacity(0.2f),
Radius = 4,
};
Children = new Drawable[]
{
new Box

View File

@ -67,7 +67,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ComboIndex = s.ComboIndex,
Scale = s.Scale,
ComboColour = s.ComboColour,
Sample = s.Sample,
Samples = s.Samples,
}),
};
@ -111,7 +111,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
if (repeat > currentRepeat)
{
if (repeat < slider.RepeatCount && ball.Tracking)
PlaySample();
PlaySamples();
currentRepeat = repeat;
}

View File

@ -2,12 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
@ -53,22 +49,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
};
}
private SampleChannel sample;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
string sampleSet = (HitObject.Sample?.Set ?? SampleSet.Normal).ToString().ToLower();
sample = audio.Sample.Get($@"Gameplay/{sampleSet}-slidertick");
}
protected override void PlaySample()
{
sample?.Play();
}
protected override void CheckJudgement(bool userTriggered)
{
if (Judgement.TimeOffset >= 0)
@ -77,7 +57,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Judgement.Score = Tracking ? OsuScoreResult.SliderTick : OsuScoreResult.Miss;
}
}
protected override void UpdatePreemptState()
{
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);

View File

@ -2,18 +2,24 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using osu.Game.Modes.Objects;
using osu.Game.Database;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Modes.Osu.Objects
{
public class Slider : OsuHitObject, IHasCurve
{
/// <summary>
/// Scoring distance with a speed-adjusted beat length of 1 second.
/// </summary>
private const float base_scoring_distance = 100;
public IHasCurve CurveObject { get; set; }
public SliderCurve Curve => CurveObject.Curve;
@ -51,13 +57,10 @@ namespace osu.Game.Modes.Osu.Objects
{
base.ApplyDefaults(timing, difficulty);
ControlPoint overridePoint;
ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
var velocityAdjustment = overridePoint?.VelocityAdjustment ?? 1;
var baseVelocity = 100 * difficulty.SliderMultiplier / velocityAdjustment;
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / timing.SpeedMultiplierAt(StartTime);
Velocity = baseVelocity / timingPoint.BeatLength;
TickDistance = baseVelocity / difficulty.SliderTickRate;
Velocity = scoringDistance / timing.BeatLengthAt(StartTime);
TickDistance = scoringDistance / difficulty.SliderTickRate;
}
public IEnumerable<SliderTick> Ticks
@ -93,11 +96,12 @@ namespace osu.Game.Modes.Osu.Objects
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
Sample = new HitSampleInfo
Samples = Samples.Select(s => new SampleInfo
{
Type = SampleType.None,
Set = SampleSet.Soft,
},
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList()
};
}
}

View File

@ -42,14 +42,14 @@ namespace osu.Game.Modes.Osu
{
if (mouseDisabled.Value)
{
mouse.PressedButtons.Remove(MouseButton.Left);
mouse.PressedButtons.Remove(MouseButton.Right);
mouse.SetPressed(MouseButton.Left, false);
mouse.SetPressed(MouseButton.Right, false);
}
if (leftViaKeyboard)
mouse.PressedButtons.Add(MouseButton.Left);
mouse.SetPressed(MouseButton.Left, true);
if (rightViaKeyboard)
mouse.PressedButtons.Add(MouseButton.Right);
mouse.SetPressed(MouseButton.Right, true);
}
}
}

View File

@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Mode.Osu")]
@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]

View File

@ -35,11 +35,9 @@ namespace osu.Game.Modes.Osu.Scoring
switch (judgement.Result)
{
case HitResult.Hit:
Combo.Value++;
Health.Value += 0.1f;
break;
case HitResult.Miss:
Combo.Value = 0;
Health.Value -= 0.2f;
break;
}

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Beatmaps;
@ -46,5 +47,7 @@ namespace osu.Game.Modes.Osu.UI
return new DrawableSpinner(spinner);
return null;
}
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
}
}

View File

@ -21,6 +21,8 @@ namespace osu.Game.Modes.Osu.UI
private readonly Container judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
public override bool ProvidingUserCursor => true;
public override Vector2 Size
{
get
@ -36,8 +38,6 @@ namespace osu.Game.Modes.Osu.UI
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
Size = new Vector2(0.75f);
Add(new Drawable[]
{

View File

@ -34,8 +34,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -104,7 +103,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>

View File

@ -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.1340" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
</packages>

View File

@ -2,96 +2,160 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Taiko.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Database;
using osu.Game.IO.Serialization;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Beatmaps
{
internal class TaikoBeatmapConverter : IBeatmapConverter<TaikoHitObject>
{
private const float legacy_velocity_scale = 1.4f;
private const float bash_convert_factor = 1.65f;
/// <summary>
/// osu! is generally slower than taiko, so a factor is added to increase
/// speed. This must be used everywhere slider length or beat length is used.
/// </summary>
private const float legacy_velocity_multiplier = 1.4f;
/// <summary>
/// Because swells are easier in taiko than spinners are in osu!,
/// legacy taiko multiplies a factor when converting the number of required hits.
/// </summary>
private const float swell_hit_multiplier = 1.65f;
/// <summary>
/// Base osu! slider scoring distance.
/// </summary>
private const float osu_base_scoring_distance = 100;
/// <summary>
/// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
/// </summary>
private const float taiko_base_distance = 100;
public Beatmap<TaikoHitObject> Convert(Beatmap original)
{
if (original is LegacyBeatmap)
original.TimingInfo.ControlPoints.ForEach(c => c.VelocityAdjustment /= legacy_velocity_scale);
BeatmapInfo info = original.BeatmapInfo.DeepClone<BeatmapInfo>();
info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier;
return new Beatmap<TaikoHitObject>(original)
{
HitObjects = convertHitObjects(original.HitObjects)
BeatmapInfo = info,
HitObjects = original.HitObjects.SelectMany(h => convertHitObject(h, original)).ToList()
};
}
private List<TaikoHitObject> convertHitObjects(List<HitObject> hitObjects)
{
return hitObjects.Select(convertHitObject).ToList();
}
private TaikoHitObject convertHitObject(HitObject original)
private IEnumerable<TaikoHitObject> convertHitObject(HitObject obj, Beatmap beatmap)
{
// Check if this HitObject is already a TaikoHitObject, and return it if so
TaikoHitObject originalTaiko = original as TaikoHitObject;
var originalTaiko = obj as TaikoHitObject;
if (originalTaiko != null)
return originalTaiko;
yield return originalTaiko;
IHasDistance distanceData = original as IHasDistance;
IHasRepeats repeatsData = original as IHasRepeats;
IHasEndTime endTimeData = original as IHasEndTime;
var distanceData = obj as IHasDistance;
var repeatsData = obj as IHasRepeats;
var endTimeData = obj as IHasEndTime;
// Old osu! used hit sounding to determine various hit type information
SampleType sample = original.Sample?.Type ?? SampleType.None;
List<SampleInfo> samples = obj.Samples;
bool strong = (sample & SampleType.Finish) > 0;
bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH);
if (distanceData != null)
{
return new DrumRoll
int repeats = repeatsData?.RepeatCount ?? 1;
double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(obj.StartTime);
double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(obj.StartTime) * speedAdjustment;
// The true distance, accounting for any repeats. This ends up being the drum roll distance later
double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
// The velocity of the taiko hit object - calculated as the velocity of a drum roll
double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
// The duration of the taiko hit object
double taikoDuration = distance / taikoVelocity;
// For some reason, old osu! always uses speedAdjustment to determine the taiko velocity, but
// only uses it to determine osu! velocity if beatmap version < 8. Let's account for that here.
if (beatmap.BeatmapInfo.BeatmapVersion >= 8)
speedAdjustedBeatLength /= speedAdjustment;
// The velocity of the osu! hit object - calculated as the velocity of a slider
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
// The duration of the osu! hit object
double osuDuration = distance / osuVelocity;
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats) / 8;
if (tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
{
StartTime = original.StartTime,
Sample = original.Sample,
for (double j = obj.StartTime; j <= distanceData.EndTime + tickSpacing; j += tickSpacing)
{
// Todo: This should generate different type of hits (including strongs)
// depending on hitobject sound additions (not implemented fully yet)
yield return new CentreHit
{
StartTime = j,
Samples = obj.Samples,
IsStrong = strong,
};
}
}
else
{
yield return new DrumRoll
{
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
Duration = taikoDuration,
TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4,
};
}
}
else if (endTimeData != null)
{
double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier;
yield return new Swell
{
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
Distance = distanceData.Distance * (repeatsData?.RepeatCount ?? 1)
Duration = endTimeData.Duration,
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
};
}
if (endTimeData != null)
else
{
// We compute the end time manually to add in the Bash convert factor
return new Swell
bool isRim = samples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE);
if (isRim)
{
StartTime = original.StartTime,
Sample = original.Sample,
IsStrong = strong,
EndTime = original.StartTime + endTimeData.Duration * bash_convert_factor
};
}
bool isCentre = (sample & ~(SampleType.Finish | SampleType.Normal)) == 0;
if (isCentre)
{
return new CentreHit
yield return new RimHit
{
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
};
}
else
{
StartTime = original.StartTime,
Sample = original.Sample,
IsStrong = strong
};
yield return new CentreHit
{
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
};
}
}
return new RimHit
{
StartTime = original.StartTime,
Sample = original.Sample,
IsStrong = strong,
};
}
}
}

View File

@ -15,6 +15,8 @@ namespace osu.Game.Modes.Taiko.Judgements
/// </summary>
public override string MaxResultString => string.Empty;
public override bool AffectsCombo => false;
protected override int NumericResultForScore(TaikoHitResult result)
{
switch (result)

View File

@ -3,6 +3,7 @@
using osu.Game.Modes.Judgements;
using osu.Framework.Extensions;
using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Taiko.Judgements
{
@ -21,12 +22,12 @@ namespace osu.Game.Modes.Taiko.Judgements
/// <summary>
/// The result value for the combo portion of the score.
/// </summary>
public int ResultValueForScore => NumericResultForScore(TaikoResult);
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(TaikoResult);
/// <summary>
/// The result value for the accuracy portion of the score.
/// </summary>
public int ResultValueForAccuracy => NumericResultForAccuracy(TaikoResult);
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(TaikoResult);
/// <summary>
/// The maximum result value for the combo portion of the score.
@ -43,7 +44,7 @@ namespace osu.Game.Modes.Taiko.Judgements
public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
/// <summary>
/// Whether this Judgement has a secondary hit in the case of finishers.
/// Whether this Judgement has a secondary hit in the case of strong hits.
/// </summary>
public virtual bool SecondHit { get; set; }

View File

@ -1,10 +1,9 @@
// 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.Beatmaps.Samples
namespace osu.Game.Modes.Taiko.Objects
{
public class HitSampleInfo : SampleInfo
public class BarLine : TaikoHitObject
{
public SampleType Type { get; set; }
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using System.Linq;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableDrumRoll : DrawableTaikoHitObject
{
private readonly DrumRoll drumRoll;
public DrawableDrumRoll(DrumRoll drumRoll)
: base(drumRoll)
{
this.drumRoll = drumRoll;
int tickIndex = 0;
foreach (var tick in drumRoll.Ticks)
{
var newTick = new DrawableDrumRollTick(tick)
{
Depth = tickIndex,
X = (float)((tick.StartTime - HitObject.StartTime) / drumRoll.Duration)
};
AddNested(newTick);
tickIndex++;
}
}
protected override void UpdateState(ArmedState state)
{
}
protected override void CheckJudgement(bool userTriggered)
{
if (userTriggered)
return;
if (Judgement.TimeOffset < 0)
return;
int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
if (countHit > drumRoll.RequiredGoodHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = countHit >= drumRoll.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
}
}
}

View File

@ -1,35 +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.Input;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
using osu.Framework.Allocation;
using osu.Game.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableStrongCentreHit : DrawableStrongHit
{
protected override Key[] HitKeys { get; } = { Key.F, Key.J };
private readonly CirclePiece circlePiece;
public DrawableStrongCentreHit(Hit hit)
: base(hit)
{
Add(circlePiece = new StrongCirclePiece
{
Children = new []
{
new CentreHitSymbolPiece()
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.PinkDarker;
}
}
}

View File

@ -1,35 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Graphics;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableStrongRimHit : DrawableStrongHit
{
protected override Key[] HitKeys { get; } = { Key.D, Key.K };
private readonly CirclePiece circlePiece;
public DrawableStrongRimHit(Hit hit)
: base(hit)
{
Add(circlePiece = new StrongCirclePiece
{
Children = new[]
{
new RimHitSymbolPiece()
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.BlueDarker;
}
}
}

View File

@ -1,161 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Backgrounds;
using OpenTK.Graphics;
using System;
using osu.Game.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
{
/// <summary>
/// A circle piece which is used uniformly through osu!taiko to visualise hitobjects.
/// <para>
/// The body of this piece will overshoot its parent by <see cref="CirclePiece.Height"/> to form
/// a rounded (_[-Width-]_) figure such that a regular "circle" is the result of a parent with Width = 0.
/// </para>
/// </summary>
public class CirclePiece : Container, IHasAccentColour
{
public const float SYMBOL_SIZE = TaikoHitObject.CIRCLE_RADIUS * 2f * 0.45f;
public const float SYMBOL_BORDER = 8;
public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER;
private Color4 accentColour;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
innerBackground.Colour = AccentColour;
triangles.ColourLight = AccentColour;
triangles.ColourDark = AccentColour.Darken(0.1f);
resetEdgeEffects();
}
}
private bool kiaiMode;
/// <summary>
/// Whether Kiai mode effects are enabled for this circle piece.
/// </summary>
public bool KiaiMode
{
get { return kiaiMode; }
set
{
kiaiMode = value;
resetEdgeEffects();
}
}
public override Anchor Origin
{
get { return Anchor.CentreLeft; }
set { throw new InvalidOperationException($"{nameof(CirclePiece)} must always use CentreLeft origin."); }
}
protected override Container<Framework.Graphics.Drawable> Content => SymbolContainer;
protected readonly Container SymbolContainer;
private readonly Container innerLayer;
private readonly Container innerCircleContainer;
private readonly Box innerBackground;
private readonly Triangles triangles;
public CirclePiece()
{
RelativeSizeAxes = Axes.X;
Height = TaikoHitObject.CIRCLE_RADIUS * 2;
// The "inner layer" is the body of the CirclePiece that overshoots it by Height/2 px on both sides
AddInternal(innerLayer = new Container
{
Name = "Inner Layer",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Children = new Framework.Graphics.Drawable[]
{
innerCircleContainer = new CircularContainer
{
Name = "Inner Circle",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Framework.Graphics.Drawable[]
{
innerBackground = new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
},
triangles = new Triangles
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
}
}
},
new CircularContainer
{
Name = "Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
BorderThickness = 8,
BorderColour = Color4.White,
Masking = true,
Children = new[]
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
},
SymbolContainer = new Container
{
Name = "Symbol",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
}
});
}
protected override void Update()
{
// Add the overshoot to compensate for corner radius
innerLayer.Width = DrawWidth + DrawHeight;
}
private void resetEdgeEffects()
{
innerCircleContainer.EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Colour = AccentColour,
Radius = KiaiMode ? 50 : 8
};
}
}
}

View File

@ -1,25 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
{
/// <summary>
/// A type of circle piece which is drawn at a higher scale to represent a "strong" piece.
/// </summary>
public class StrongCirclePiece : CirclePiece
{
/// <summary>
/// The amount to scale up the base circle to show it as a "strong" piece.
/// </summary>
private const float strong_scale = 1.5f;
public StrongCirclePiece()
{
SymbolContainer.Scale = new Vector2(strong_scale);
}
public override Vector2 Size => new Vector2(base.Size.X, base.Size.Y * strong_scale);
}
}

View File

@ -0,0 +1,80 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
/// <summary>
/// A line that scrolls alongside hit objects in the playfield and visualises control points.
/// </summary>
public class DrawableBarLine : Container
{
/// <summary>
/// The width of the line tracker.
/// </summary>
private const float tracker_width = 2f;
/// <summary>
/// Fade out time calibrated to a pre-empt of 1000ms.
/// </summary>
private const float base_fadeout_time = 100f;
/// <summary>
/// The visual line tracker.
/// </summary>
protected Box Tracker;
/// <summary>
/// The bar line.
/// </summary>
protected readonly BarLine BarLine;
public DrawableBarLine(BarLine barLine)
{
BarLine = barLine;
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
RelativePositionAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Width = tracker_width;
Children = new[]
{
Tracker = new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(0.5f, 0),
Alpha = 0.75f
}
};
LifetimeStart = BarLine.StartTime - BarLine.ScrollTime * 2;
LifetimeEnd = BarLine.StartTime + BarLine.ScrollTime;
}
protected override void LoadComplete()
{
base.LoadComplete();
Delay(BarLine.StartTime - Time.Current);
FadeOut(base_fadeout_time * BarLine.ScrollTime / 1000);
}
private void updateScrollPosition(double time) => MoveToX((float)((BarLine.StartTime - time) / BarLine.ScrollTime));
protected override void Update()
{
base.Update();
updateScrollPosition(Time.Current);
}
}
}

View File

@ -0,0 +1,57 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableBarLineMajor : DrawableBarLine
{
/// <summary>
/// The vertical offset of the triangles from the line tracker.
/// </summary>
private const float triangle_offfset = 10f;
/// <summary>
/// The size of the triangles.
/// </summary>
private const float triangle_size = 20f;
public DrawableBarLineMajor(BarLine barLine)
: base(barLine)
{
Add(new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new EquilateralTriangle
{
Name = "Top",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Position = new Vector2(0, -triangle_offfset),
Size = new Vector2(-triangle_size),
EdgeSmoothness = new Vector2(1),
},
new EquilateralTriangle
{
Name = "Bottom",
Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre,
Position = new Vector2(0, triangle_offfset),
Size = new Vector2(triangle_size),
EdgeSmoothness = new Vector2(1),
}
}
});
Tracker.Alpha = 1f;
}
}
}

View File

@ -1,35 +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 OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
using osu.Game.Graphics;
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableCentreHit : DrawableHit
{
protected override Key[] HitKeys { get; } = { Key.F, Key.J };
private readonly CirclePiece circlePiece;
public DrawableCentreHit(Hit hit)
: base(hit)
{
Add(circlePiece = new CirclePiece
{
Children = new[]
{
new CentreHitSymbolPiece()
}
});
MainPiece.Add(new CentreHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.PinkDarker;
MainPiece.AccentColour = colours.PinkDarker;
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableCentreHitStrong : DrawableHitStrong
{
protected override Key[] HitKeys { get; } = { Key.F, Key.J };
public DrawableCentreHitStrong(Hit hit)
: base(hit)
{
MainPiece.Add(new CentreHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
MainPiece.AccentColour = colours.PinkDarker;
}
}
}

View File

@ -0,0 +1,109 @@
// 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.Linq;
using osu.Framework.Allocation;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableDrumRoll : DrawableTaikoHitObject<DrumRoll>
{
/// <summary>
/// Number of rolling hits required to reach the dark/final accent colour.
/// </summary>
private const int rolling_hits_for_dark_accent = 5;
private Color4 accentDarkColour;
/// <summary>
/// Rolling number of tick hits. This increases for hits and decreases for misses.
/// </summary>
private int rollingHits;
public DrawableDrumRoll(DrumRoll drumRoll)
: base(drumRoll)
{
foreach (var tick in drumRoll.Ticks)
{
var newTick = new DrawableDrumRollTick(tick)
{
X = (float)((tick.StartTime - HitObject.StartTime) / HitObject.Duration)
};
newTick.OnJudgement += onTickJudgement;
AddNested(newTick);
MainPiece.Add(newTick);
}
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement { SecondHit = HitObject.IsStrong };
protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(HitObject.IsStrong)
{
Length = (float)(HitObject.Duration / HitObject.ScrollTime),
PlayfieldLengthReference = () => Parent.DrawSize.X
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
MainPiece.AccentColour = AccentColour = colours.YellowDark;
accentDarkColour = colours.YellowDarker;
}
protected override void LoadComplete()
{
base.LoadComplete();
// This is naive, however it's based on the reasoning that the hit target
// is further than mid point of the play field, so the time taken to scroll in should always
// be greater than the time taken to scroll out to the left of the screen.
// Thus, using PreEmpt here is enough for the drum roll to completely scroll out.
LifetimeEnd = HitObject.EndTime + HitObject.ScrollTime;
}
private void onTickJudgement(DrawableHitObject<TaikoHitObject, TaikoJudgement> obj)
{
if (obj.Judgement.Result == HitResult.Hit)
rollingHits++;
else
rollingHits--;
rollingHits = MathHelper.Clamp(rollingHits, 0, rolling_hits_for_dark_accent);
Color4 newAccent = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_dark_accent, AccentColour, accentDarkColour, 0, 1);
MainPiece.FadeAccent(newAccent, 100);
}
protected override void CheckJudgement(bool userTriggered)
{
if (userTriggered)
return;
if (Judgement.TimeOffset < 0)
return;
int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit);
if (countHit > HitObject.RequiredGoodHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
}
protected override void UpdateState(ArmedState state)
{
}
}
}

View File

@ -1,35 +1,39 @@
// 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.Input;
using osu.Game.Modes.Taiko.Judgements;
using System;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableDrumRollTick : DrawableTaikoHitObject
public class DrawableDrumRollTick : DrawableTaikoHitObject<DrumRollTick>
{
private readonly DrumRollTick tick;
public DrawableDrumRollTick(DrumRollTick tick)
: base(tick)
{
this.tick = tick;
}
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement();
protected override TaikoPiece CreateMainPiece() => new TickPiece
{
Filled = HitObject.FirstTick
};
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong };
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
if (Judgement.TimeOffset > tick.HitWindow)
if (Judgement.TimeOffset > HitObject.HitWindow)
Judgement.Result = HitResult.Miss;
return;
}
if (Math.Abs(Judgement.TimeOffset) < tick.HitWindow)
if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
@ -38,11 +42,17 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
Content.ScaleTo(0, 100, EasingTypes.OutQuint);
break;
}
}
protected override void UpdateScrollPosition(double time)
{
// Drum roll ticks shouldn't move
// Ticks don't move
}
protected override bool HandleKeyPress(Key key)

View File

@ -1,66 +1,53 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Input;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using System;
using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public abstract class DrawableHit : DrawableTaikoHitObject
public abstract class DrawableHit : DrawableTaikoHitObject<Hit>
{
/// <summary>
/// A list of keys which can result in hits for this HitObject.
/// </summary>
protected abstract Key[] HitKeys { get; }
protected override Container<Framework.Graphics.Drawable> Content => bodyContainer;
private readonly Hit hit;
/// <summary>
/// Whether the last key pressed is a valid hit key.
/// </summary>
private bool validKeyPressed;
private readonly Container bodyContainer;
protected DrawableHit(Hit hit)
: base(hit)
{
this.hit = hit;
AddInternal(bodyContainer = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
}
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
if (Judgement.TimeOffset > hit.HitWindowGood)
if (Judgement.TimeOffset > HitObject.HitWindowGood)
Judgement.Result = HitResult.Miss;
return;
}
double hitOffset = Math.Abs(Judgement.TimeOffset);
if (hitOffset > hit.HitWindowMiss)
if (hitOffset > HitObject.HitWindowMiss)
return;
if (!validKeyPressed)
Judgement.Result = HitResult.Miss;
else if (hitOffset < hit.HitWindowGood)
else if (hitOffset < HitObject.HitWindowGood)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = hitOffset < hit.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
Judgement.TaikoResult = hitOffset < HitObject.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
@ -80,21 +67,39 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
{
Delay(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true);
var circlePiece = MainPiece as CirclePiece;
circlePiece?.FlashBox.Flush();
switch (State)
{
case ArmedState.Idle:
Delay(hit.HitWindowMiss);
Delay(HitObject.HitWindowMiss);
break;
case ArmedState.Miss:
FadeOut(100);
break;
case ArmedState.Hit:
bodyContainer.ScaleTo(0.8f, 400, EasingTypes.OutQuad);
bodyContainer.MoveToY(-200, 250, EasingTypes.Out);
bodyContainer.Delay(250);
bodyContainer.MoveToY(0, 500, EasingTypes.In);
FadeOut(600);
var flash = circlePiece?.FlashBox;
if (flash != null)
{
flash.FadeTo(0.9f);
flash.FadeOut(300);
}
FadeOut(800);
const float gravity_time = 300;
const float gravity_travel_height = 200;
Content.ScaleTo(0.8f, gravity_time * 2, EasingTypes.OutQuad);
MoveToY(-gravity_travel_height, gravity_time, EasingTypes.Out);
Delay(gravity_time, true);
MoveToY(gravity_travel_height * 2, gravity_time * 2, EasingTypes.In);
break;
}

View File

@ -1,16 +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
using OpenTK.Input;
using System;
using System.Linq;
using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public abstract class DrawableStrongHit : DrawableHit
public abstract class DrawableHitStrong : DrawableHit
{
/// <summary>
/// The lenience for the second key press.
@ -22,11 +23,13 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
private bool firstKeyHeld;
private Key firstHitKey;
protected DrawableStrongHit(Hit hit)
protected DrawableHitStrong(Hit hit)
: base(hit)
{
}
protected override TaikoPiece CreateMainPiece() => new CirclePiece(true);
protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
protected override void CheckJudgement(bool userTriggered)

View File

@ -3,33 +3,25 @@
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableRimHit : DrawableHit
{
protected override Key[] HitKeys { get; } = { Key.D, Key.K };
private readonly CirclePiece circlePiece;
public DrawableRimHit(Hit hit)
: base(hit)
{
Add(circlePiece = new CirclePiece
{
Children = new[]
{
new RimHitSymbolPiece()
}
});
MainPiece.Add(new RimHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.BlueDarker;
MainPiece.AccentColour = colours.BlueDarker;
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableRimHitStrong : DrawableHitStrong
{
protected override Key[] HitKeys { get; } = { Key.D, Key.K };
public DrawableRimHitStrong(Hit hit)
: base(hit)
{
MainPiece.Add(new RimHitSymbolPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
MainPiece.AccentColour = colours.BlueDarker;
}
}
}

View File

@ -1,9 +1,8 @@
// 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 OpenTK.Input;
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@ -12,13 +11,14 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
using System;
using System.Linq;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableSwell : DrawableTaikoHitObject
public class DrawableSwell : DrawableTaikoHitObject<Swell>
{
/// <summary>
/// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime.
@ -31,8 +31,6 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
private const float target_ring_scale = 5f;
private const float inner_ring_alpha = 0.65f;
private readonly Swell swell;
private readonly Container bodyContainer;
private readonly CircularContainer targetRing;
private readonly CircularContainer expandingRing;
@ -54,13 +52,12 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
public DrawableSwell(Swell swell)
: base(swell)
{
this.swell = swell;
Children = new Framework.Graphics.Drawable[]
Children = new Drawable[]
{
bodyContainer = new Container
{
Children = new Framework.Graphics.Drawable[]
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
expandingRing = new CircularContainer
{
@ -68,7 +65,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Alpha = 0,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
BlendingMode = BlendingMode.Additive,
Masking = true,
Children = new []
@ -85,11 +82,11 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
Name = "Target ring (thick border)",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
Masking = true,
BorderThickness = target_ring_thick_border,
BlendingMode = BlendingMode.Additive,
Children = new Framework.Graphics.Drawable[]
Children = new Drawable[]
{
new Box
{
@ -120,6 +117,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
},
circlePiece = new CirclePiece
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new []
{
symbol = new SwellSymbolPiece()
@ -128,6 +127,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
}
}
};
circlePiece.KiaiMode = HitObject.Kiai;
}
[BackgroundDependencyLoader]
@ -144,18 +145,18 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
{
userHits++;
var completion = (float)userHits / swell.RequiredHits;
var completion = (float)userHits / HitObject.RequiredHits;
expandingRing.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50);
expandingRing.Delay(50);
expandingRing.FadeTo(completion / 8, 2000, EasingTypes.OutQuint);
expandingRing.DelayReset();
symbol.RotateTo((float)(completion * swell.Duration / 8), 4000, EasingTypes.OutQuint);
symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, EasingTypes.OutQuint);
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);
if (userHits == swell.RequiredHits)
if (userHits == HitObject.RequiredHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
@ -167,7 +168,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
return;
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
if (userHits > swell.RequiredHits / 2)
if (userHits > HitObject.RequiredHits / 2)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Good;
@ -187,7 +188,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
Delay(preempt, true);
Delay(Judgement.TimeOffset + swell.Duration, true);
Delay(Judgement.TimeOffset + HitObject.Duration, true);
const float out_transition_time = 300;

View File

@ -1,16 +1,20 @@
// 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.Input;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using System.Collections.Generic;
using osu.Framework.Input;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawable
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public abstract class DrawableTaikoHitObject : DrawableHitObject<TaikoHitObject, TaikoJudgement>
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableHitObject<TaikoHitObject, TaikoJudgement>
where TaikoHitType : TaikoHitObject
{
/// <summary>
/// A list of keys which this hit object will accept. These are the standard Taiko keys for now.
@ -18,33 +22,52 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable
/// </summary>
private readonly List<Key> validKeys = new List<Key>(new[] { Key.D, Key.F, Key.J, Key.K });
protected DrawableTaikoHitObject(TaikoHitObject hitObject)
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
protected override Container<Drawable> Content => bodyContainer;
protected readonly TaikoPiece MainPiece;
private readonly Container bodyContainer;
public new TaikoHitType HitObject;
protected DrawableTaikoHitObject(TaikoHitType hitObject)
: base(hitObject)
{
HitObject = hitObject;
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
Origin = Anchor.Custom;
AutoSizeAxes = Axes.Both;
RelativePositionAxes = Axes.X;
}
protected override void LoadComplete()
{
LifetimeStart = HitObject.StartTime - HitObject.PreEmpt * 2;
AddInternal(bodyContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new[]
{
MainPiece = CreateMainPiece()
}
});
base.LoadComplete();
MainPiece.KiaiMode = HitObject.Kiai;
LifetimeStart = HitObject.StartTime - HitObject.ScrollTime * 2;
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(HitObject.IsStrong);
/// <summary>
/// Sets the scroll position of the DrawableHitObject relative to the offset between
/// a time value and the HitObject's StartTime.
/// </summary>
/// <param name="time"></param>
protected virtual void UpdateScrollPosition(double time)
{
MoveToX((float)((HitObject.StartTime - time) / HitObject.PreEmpt));
}
protected virtual void UpdateScrollPosition(double time) => X = (float)((HitObject.StartTime - time) / HitObject.ScrollTime);
protected override void Update()
{

View File

@ -1,12 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
/// <summary>
/// The symbol used for centre hit pieces.

View File

@ -0,0 +1,152 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Backgrounds;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
/// <summary>
/// A circle piece which is used uniformly through osu!taiko to visualise hitobjects.
/// <para>
/// Note that this can actually be non-circle if the width is changed. See <see cref="ElongatedCirclePiece"/>
/// for a usage example.
/// </para>
/// </summary>
public class CirclePiece : TaikoPiece
{
public const float SYMBOL_SIZE = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER * 0.45f;
public const float SYMBOL_BORDER = 8;
public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
base.AccentColour = value;
background.Colour = AccentColour;
resetEdgeEffects();
}
}
/// <summary>
/// Whether Kiai mode effects are enabled for this circle piece.
/// </summary>
public override bool KiaiMode
{
get { return base.KiaiMode; }
set
{
base.KiaiMode = value;
resetEdgeEffects();
}
}
protected override Container<Drawable> Content => content;
private readonly Container content;
private readonly Container background;
public Box FlashBox;
public CirclePiece(bool isStrong = false)
{
AddInternal(new Drawable[]
{
background = new CircularContainer
{
Name = "Background",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
},
new Triangles
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
ColourLight = Color4.White,
ColourDark = Color4.White.Darken(0.1f)
}
}
},
new CircularContainer
{
Name = "Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
BorderThickness = 8,
BorderColour = Color4.White,
Masking = true,
Children = new[]
{
FlashBox = new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
BlendingMode = BlendingMode.Additive,
Alpha = 0,
AlwaysPresent = true
}
}
},
content = new Container
{
RelativeSizeAxes = Axes.Both,
Name = "Content",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
if (isStrong)
{
Size *= TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE;
//default for symbols etc.
Content.Scale *= TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE;
}
}
protected override void Update()
{
base.Update();
//we want to allow for width of content to remain mapped to the area inside us, regardless of the scale applied above.
Content.Width = 1 / Content.Scale.X;
}
private void resetEdgeEffects()
{
background.EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Colour = AccentColour,
Radius = KiaiMode ? 50 : 8
};
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics.Primitives;
using osu.Game.Modes.Taiko.UI;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
public class ElongatedCirclePiece : CirclePiece
{
/// <summary>
/// As we are being used to define the absolute size of hits, we need to be given a relative reference of our containing <see cref="TaikoPlayfield"/>.
/// </summary>
public Func<float> PlayfieldLengthReference;
/// <summary>
/// The length of this piece as a multiple of the value returned by <see cref="PlayfieldLengthReference"/>
/// </summary>
public float Length;
public ElongatedCirclePiece(bool isStrong = false) : base(isStrong)
{
}
protected override void Update()
{
base.Update();
var padding = Content.DrawHeight * Content.Width / 2;
Content.Padding = new MarginPadding
{
Left = padding,
Right = padding,
};
Width = (PlayfieldLengthReference?.Invoke() ?? 0) * Length + DrawHeight;
}
}
}

View File

@ -1,13 +1,13 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
/// <summary>
/// The symbol used for rim hit pieces.

View File

@ -1,10 +1,10 @@
// 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.Graphics;
using osu.Framework.Graphics;
using osu.Game.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
/// <summary>
/// The symbol used for swell pieces.

View File

@ -0,0 +1,45 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
public class TaikoPiece : Container, IHasAccentColour
{
private Color4 accentColour;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public virtual Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
}
}
private bool kiaiMode;
/// <summary>
/// Whether Kiai mode effects are enabled for this circle piece.
/// </summary>
public virtual bool KiaiMode
{
get { return kiaiMode; }
set
{
kiaiMode = value;
}
}
public TaikoPiece()
{
//just a default
Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER);
}
}
}

View File

@ -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.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
public class TickPiece : TaikoPiece
{
/// <summary>
/// Any tick that is not the first for a drumroll is not filled, but is instead displayed
/// as a hollow circle. This is what controls the border width of that circle.
/// </summary>
private const float tick_border_width = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 16;
/// <summary>
/// The size of a tick.
/// </summary>
private const float tick_size = TaikoHitObject.DEFAULT_CIRCLE_DIAMETER / 4;
private bool filled;
public bool Filled
{
get { return filled; }
set
{
filled = value;
fillBox.Alpha = filled ? 1 : 0;
}
}
private readonly Box fillBox;
public TickPiece()
{
Size = new Vector2(tick_size);
Add(new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = tick_border_width,
BorderColour = Color4.White,
Children = new[]
{
fillBox = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
});
}
}
}

View File

@ -1,37 +1,31 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Objects
{
public class DrumRoll : TaikoHitObject, IHasDistance
public class DrumRoll : TaikoHitObject, IHasEndTime
{
public double EndTime => StartTime + Distance / Velocity;
/// <summary>
/// Drum roll distance that results in a duration of 1 speed-adjusted beat length.
/// </summary>
private const float base_distance = 100;
public double Duration => EndTime - StartTime;
public double EndTime => StartTime + Duration;
public double Duration { get; set; }
/// <summary>
/// Raw length of the drum roll in positional length units.
/// Numer of ticks per beat length.
/// </summary>
public double Distance { get; set; }
/// <summary>
/// Velocity of the drum roll in positional length units per millisecond.
/// </summary>
public double Velocity { get; protected set; }
/// <summary>
/// The distance between ticks of this drumroll.
/// <para>Half of this value is the hit window of the ticks.</para>
/// </summary>
public double TickTimeDistance { get; protected set; }
public int TickRate = 1;
/// <summary>
/// Number of drum roll ticks required for a "Good" hit.
@ -55,18 +49,17 @@ namespace osu.Game.Modes.Taiko.Objects
private List<DrumRollTick> ticks;
/// <summary>
/// The length (in milliseconds) between ticks of this drumroll.
/// <para>Half of this value is the hit window of the ticks.</para>
/// </summary>
private double tickSpacing = 100;
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
Velocity = timing.SliderVelocityAt(StartTime) * difficulty.SliderMultiplier / 1000;
TickTimeDistance = timing.BeatLengthAt(StartTime);
//TODO: move this to legacy conversion code to allow for direct division without special case.
if (difficulty.SliderTickRate == 3)
TickTimeDistance /= 3;
else
TickTimeDistance /= 4;
tickSpacing = timing.BeatLengthAt(StartTime) / TickRate;
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
@ -76,23 +69,25 @@ namespace osu.Game.Modes.Taiko.Objects
{
var ret = new List<DrumRollTick>();
if (TickTimeDistance == 0)
if (tickSpacing == 0)
return ret;
bool first = true;
for (double t = StartTime; t < EndTime + (int)TickTimeDistance; t += TickTimeDistance)
for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing)
{
ret.Add(new DrumRollTick
{
FirstTick = first,
PreEmpt = PreEmpt,
TickTimeDistance = TickTimeDistance,
ScrollTime = ScrollTime,
TickSpacing = tickSpacing,
StartTime = t,
Sample = new HitSampleInfo
IsStrong = IsStrong,
Samples = Samples.Select(s => new SampleInfo
{
Type = SampleType.None,
Set = SampleSet.Soft
}
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList()
});
first = false;

View File

@ -11,14 +11,14 @@ namespace osu.Game.Modes.Taiko.Objects
public bool FirstTick;
/// <summary>
/// The distance between this tick and the next in milliseconds.
/// The length (in milliseconds) between this tick and the next.
/// <para>Half of this value is the hit window of the tick.</para>
/// </summary>
public double TickTimeDistance;
public double TickSpacing;
/// <summary>
/// The time allowed to hit this tick.
/// </summary>
public double HitWindow => TickTimeDistance / 2;
public double HitWindow => TickSpacing / 2;
}
}

View File

@ -1,30 +1,19 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Modes.Objects.Types;
namespace osu.Game.Modes.Taiko.Objects
{
public class Swell : TaikoHitObject, IHasEndTime
{
public double EndTime { get; set; }
public double EndTime => StartTime + Duration;
public double Duration => EndTime - StartTime;
public double Duration { get; set; }
/// <summary>
/// The number of hits required to complete the swell successfully.
/// </summary>
public int RequiredHits { get; protected set; } = 10;
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
double spinnerRotationRatio = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5);
RequiredHits = (int)Math.Max(1, Duration / 1000f * spinnerRotationRatio);
}
public int RequiredHits = 10;
}
}

View File

@ -4,20 +4,41 @@
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Taiko.UI;
namespace osu.Game.Modes.Taiko.Objects
{
public abstract class TaikoHitObject : HitObject
{
/// <summary>
/// HitCircle radius.
/// Diameter of a circle relative to the size of the <see cref="TaikoPlayfield"/>.
/// </summary>
public const float CIRCLE_RADIUS = 42f;
public const float PLAYFIELD_RELATIVE_DIAMETER = 0.5f;
/// <summary>
/// The time to scroll in the HitObject.
/// Scale multiplier for a strong circle.
/// </summary>
public double PreEmpt;
public const float STRONG_CIRCLE_DIAMETER_SCALE = 1.5f;
/// <summary>
/// Default circle diameter.
/// </summary>
public const float DEFAULT_CIRCLE_DIAMETER = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT * PLAYFIELD_RELATIVE_DIAMETER;
/// <summary>
/// Default strong circle diameter.
/// </summary>
public const float DEFAULT_STRONG_CIRCLE_DIAMETER = DEFAULT_CIRCLE_DIAMETER * STRONG_CIRCLE_DIAMETER_SCALE;
/// <summary>
/// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a <see cref="ControlPoint.BeatLength"/> of 1000ms.
/// </summary>
private const double scroll_time = 6000;
/// <summary>
/// Our adjusted <see cref="scroll_time"/> taking into consideration local <see cref="ControlPoint.BeatLength"/> and other speed multipliers.
/// </summary>
public double ScrollTime;
/// <summary>
/// Whether this HitObject is a "strong" type.
@ -34,7 +55,7 @@ namespace osu.Game.Modes.Taiko.Objects
{
base.ApplyDefaults(timing, difficulty);
PreEmpt = 600 / (timing.SliderVelocityAt(StartTime) * difficulty.SliderMultiplier) * 1000;
ScrollTime = scroll_time * (timing.BeatLengthAt(StartTime) * timing.SpeedMultiplierAt(StartTime) / 1000) / difficulty.SliderMultiplier;
ControlPoint overridePoint;
Kiai = timing.TimingPointAt(StartTime, out overridePoint).KiaiMode;

View File

@ -4,7 +4,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Taiko")]
@ -16,8 +16,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@ -27,11 +27,11 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]

View File

@ -72,14 +72,9 @@ namespace osu.Game.Modes.Taiko.Replays
}
else if (drumRoll != null)
{
double delay = drumRoll.TickTimeDistance;
double time = drumRoll.StartTime;
for (int j = 0; j < drumRoll.TotalTicks; j++)
foreach (var tick in drumRoll.Ticks)
{
Frames.Add(new ReplayFrame((int)time, 0, 0, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2));
time += delay;
Frames.Add(new ReplayFrame(tick.StartTime, 0, 0, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2));
hitButton = !hitButton;
}
}

View File

@ -187,10 +187,6 @@ namespace osu.Game.Modes.Taiko.Scoring
if (!isTick)
totalHits++;
// Apply combo changes, must be done before the hit score is added
if (!isTick && judgement.Result == HitResult.Hit)
Combo.Value++;
// Apply score changes
addHitScore(judgement);
@ -261,7 +257,7 @@ namespace osu.Game.Modes.Taiko.Scoring
foreach (var j in Judgements)
{
scoreForAccuracy += j.ResultValueForAccuracy;
maxScoreForAccuracy = j.MaxResultValueForAccuracy;
maxScoreForAccuracy += j.MaxResultValueForAccuracy;
}
Accuracy.Value = (double)scoreForAccuracy / maxScoreForAccuracy;

View File

@ -18,14 +18,18 @@ namespace osu.Game.Modes.Taiko.UI
/// </summary>
internal class HitExplosion : CircularContainer
{
private readonly TaikoJudgement judgement;
/// <summary>
/// The judgement this hit explosion visualises.
/// </summary>
public readonly TaikoJudgement Judgement;
private readonly Box innerFill;
public HitExplosion(TaikoJudgement judgement)
{
this.judgement = judgement;
Judgement = judgement;
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2);
Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
@ -50,10 +54,7 @@ namespace osu.Game.Modes.Taiko.UI
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (judgement.SecondHit)
Size *= 1.5f;
switch (judgement.TaikoResult)
switch (Judgement.TaikoResult)
{
case TaikoHitResult.Good:
innerFill.Colour = colours.Green;
@ -73,5 +74,13 @@ namespace osu.Game.Modes.Taiko.UI
Expire();
}
/// <summary>
/// Transforms this hit explosion to visualise a secondary hit.
/// </summary>
public void VisualiseSecondHit()
{
ResizeTo(Size * TaikoHitObject.STRONG_CIRCLE_DIAMETER_SCALE, 50);
}
}
}

View File

@ -15,16 +15,6 @@ namespace osu.Game.Modes.Taiko.UI
/// </summary>
internal class HitTarget : Container
{
/// <summary>
/// Diameter of normal hit object circles.
/// </summary>
private const float normal_diameter = TaikoHitObject.CIRCLE_RADIUS * 2;
/// <summary>
/// Diameter of finisher hit object circles.
/// </summary>
private const float finisher_diameter = normal_diameter * 1.5f;
/// <summary>
/// The 1px inner border of the taiko playfield.
/// </summary>
@ -37,7 +27,7 @@ namespace osu.Game.Modes.Taiko.UI
public HitTarget()
{
RelativeSizeAxes = Axes.Y;
Size = new Vector2(TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT);
Children = new Drawable[]
{
@ -47,15 +37,15 @@ namespace osu.Game.Modes.Taiko.UI
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = border_offset,
Size = new Vector2(border_thickness, (TaikoPlayfield.PLAYFIELD_HEIGHT - finisher_diameter) / 2f - border_offset),
Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER) / 2f - border_offset),
Alpha = 0.1f
},
new CircularContainer
{
Name = "Finisher Ring",
Name = "Strong Hit Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(finisher_diameter),
Size = new Vector2(TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER),
Masking = true,
BorderColour = Color4.White,
BorderThickness = border_thickness,
@ -72,10 +62,10 @@ namespace osu.Game.Modes.Taiko.UI
},
new CircularContainer
{
Name = "Normal Ring",
Name = "Normal Hit Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(normal_diameter),
Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
Masking = true,
BorderColour = Color4.White,
BorderThickness = border_thickness,
@ -96,7 +86,7 @@ namespace osu.Game.Modes.Taiko.UI
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Y = -border_offset,
Size = new Vector2(border_thickness, (TaikoPlayfield.PLAYFIELD_HEIGHT - finisher_diameter) / 2f - border_offset),
Size = new Vector2(border_thickness, (TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT - TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER) / 2f - border_offset),
Alpha = 0.1f
},
};

View File

@ -21,7 +21,7 @@ namespace osu.Game.Modes.Taiko.UI
{
public InputDrum()
{
Size = new Vector2(TaikoPlayfield.PLAYFIELD_HEIGHT);
Size = new Vector2(TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT);
const float middle_split = 10;
@ -60,7 +60,7 @@ namespace osu.Game.Modes.Taiko.UI
/// The key to be used for the rim of the half-drum.
/// </summary>
public Key RimKey;
/// <summary>
/// The key to be used for the centre of the half-drum.
/// </summary>
@ -128,17 +128,36 @@ namespace osu.Game.Modes.Taiko.UI
return false;
Drawable target = null;
Drawable back = null;
if (args.Key == CentreKey)
{
target = centreHit;
back = centre;
}
else if (args.Key == RimKey)
{
target = rimHit;
back = rim;
}
if (target != null)
{
target.FadeTo(Math.Min(target.Alpha + 0.4f, 1), 40, EasingTypes.OutQuint);
target.Delay(40);
target.FadeOut(1000, EasingTypes.OutQuint);
const float scale_amount = 0.05f;
const float alpha_amount = 0.5f;
const float down_time = 40;
const float up_time = 1000;
back.ScaleTo(target.Scale.X - scale_amount, down_time, EasingTypes.OutQuint);
back.Delay(down_time);
back.ScaleTo(1, up_time, EasingTypes.OutQuint);
target.ScaleTo(target.Scale.X - scale_amount, down_time, EasingTypes.OutQuint);
target.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, EasingTypes.OutQuint);
target.Delay(down_time);
target.ScaleTo(1, up_time, EasingTypes.OutQuint);
target.FadeOut(up_time, EasingTypes.OutQuint);
}
return false;

View File

@ -1,16 +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 osu.Framework.Allocation;
using osu.Framework.MathUtils;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Replays;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.Taiko.Beatmaps;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.Replays;
using osu.Game.Modes.Taiko.Objects.Drawables;
using osu.Game.Modes.Taiko.Scoring;
using osu.Game.Modes.UI;
using osu.Game.Modes.Taiko.Replays;
using OpenTK;
namespace osu.Game.Modes.Taiko.UI
{
@ -21,15 +28,132 @@ namespace osu.Game.Modes.Taiko.UI
{
}
[BackgroundDependencyLoader]
private void load()
{
loadBarLines();
}
private void loadBarLines()
{
var taikoPlayfield = Playfield as TaikoPlayfield;
if (taikoPlayfield == null)
return;
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
var timingPoints = Beatmap.TimingInfo.ControlPoints.FindAll(cp => cp.TimingChange);
if (timingPoints.Count == 0)
return;
int currentIndex = 0;
while (currentIndex < timingPoints.Count && Precision.AlmostEquals(timingPoints[currentIndex].BeatLength, 0))
currentIndex++;
double time = timingPoints[currentIndex].Time;
double measureLength = timingPoints[currentIndex].BeatLength * (int)timingPoints[currentIndex].TimeSignature;
// Find the bar line time closest to 0
time -= measureLength * (int)(time / measureLength);
// Always start barlines from a positive time
while (time < 0)
time += measureLength;
int currentBeat = 0;
while (time <= lastHitTime)
{
ControlPoint current = timingPoints[currentIndex];
if (time > current.Time || current.OmitFirstBarLine)
{
bool isMajor = currentBeat % (int)current.TimeSignature == 0;
var barLine = new BarLine
{
StartTime = time,
};
barLine.ApplyDefaults(Beatmap.TimingInfo, Beatmap.BeatmapInfo.Difficulty);
taikoPlayfield.AddBarLine(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine));
currentBeat++;
}
double bl = current.BeatLength;
if (bl < 800)
bl *= (int)current.TimeSignature;
time += bl;
if (currentIndex + 1 >= timingPoints.Count || time < timingPoints[currentIndex + 1].Time)
continue;
currentBeat = 0;
currentIndex++;
time = timingPoints[currentIndex].Time;
}
}
protected override Vector2 GetPlayfieldAspectAdjust()
{
const float default_relative_height = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT / 768;
const float default_aspect = 16f / 9f;
float aspectAdjust = MathHelper.Clamp(DrawWidth / DrawHeight, 0.4f, 4) / default_aspect;
return new Vector2(1, default_relative_height * aspectAdjust);
}
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
protected override IBeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
protected override IBeatmapProcessor<TaikoHitObject> CreateBeatmapProcessor() => new TaikoBeatmapProcessor();
protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield();
protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft
};
protected override DrawableHitObject<TaikoHitObject, TaikoJudgement> GetVisualRepresentation(TaikoHitObject h) => null;
protected override DrawableHitObject<TaikoHitObject, TaikoJudgement> GetVisualRepresentation(TaikoHitObject h)
{
var centreHit = h as CentreHit;
if (centreHit != null)
{
if (h.IsStrong)
return new DrawableCentreHitStrong(centreHit);
return new DrawableCentreHit(centreHit);
}
var rimHit = h as RimHit;
if (rimHit != null)
{
if (h.IsStrong)
return new DrawableRimHitStrong(rimHit);
return new DrawableRimHit(rimHit);
}
var drumRoll = h as DrumRoll;
if (drumRoll != null)
{
return new DrawableDrumRoll(drumRoll);
}
var swell = h as Swell;
if (swell != null)
return new DrawableSwell(swell);
return null;
}
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay);
}

View File

@ -14,22 +14,23 @@ using osu.Game.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Primitives;
using osu.Game.Modes.Taiko.Objects.Drawable;
using System.Linq;
using osu.Game.Modes.Taiko.Objects.Drawables;
using System;
namespace osu.Game.Modes.Taiko.UI
{
public class TaikoPlayfield : Playfield<TaikoHitObject, TaikoJudgement>
{
/// <summary>
/// The play field height. This is relative to the size of hit objects
/// such that the playfield is just a bit larger than finishers.
/// The default play field height.
/// </summary>
public const float PLAYFIELD_HEIGHT = TaikoHitObject.CIRCLE_RADIUS * 2 * 2;
public const float DEFAULT_PLAYFIELD_HEIGHT = 168f;
/// <summary>
/// The offset from <see cref="left_area_size"/> which the center of the hit target lies at.
/// </summary>
private const float hit_target_offset = TaikoHitObject.CIRCLE_RADIUS * 1.5f + 40;
private const float hit_target_offset = TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER / 2f + 40;
/// <summary>
/// The size of the left area of the playfield. This area contains the input drum.
@ -39,7 +40,7 @@ namespace osu.Game.Modes.Taiko.UI
protected override Container<Drawable> Content => hitObjectContainer;
private readonly Container<HitExplosion> hitExplosionContainer;
//private Container<DrawableBarLine> barLineContainer;
private readonly Container<DrawableBarLine> barLineContainer;
private readonly Container<DrawableTaikoJudgement> judgementContainer;
private readonly Container hitObjectContainer;
@ -51,13 +52,11 @@ namespace osu.Game.Modes.Taiko.UI
public TaikoPlayfield()
{
RelativeSizeAxes = Axes.X;
Height = PLAYFIELD_HEIGHT;
AddInternal(new Drawable[]
{
rightBackgroundContainer = new Container
{
Name = "Transparent playfield background",
RelativeSizeAxes = Axes.Both,
BorderThickness = 2,
Masking = true,
@ -76,76 +75,88 @@ namespace osu.Game.Modes.Taiko.UI
},
}
},
new Container
new ScaleFixContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = left_area_size },
Children = new Drawable[]
RelativeSizeAxes = Axes.X,
Height = DEFAULT_PLAYFIELD_HEIGHT,
Children = new[]
{
new Container
{
Padding = new MarginPadding { Left = hit_target_offset },
Name = "Transparent playfield elements",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = left_area_size },
Children = new Drawable[]
{
hitExplosionContainer = new Container<HitExplosion>
new Container
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
BlendingMode = BlendingMode.Additive
Name = "Hit target container",
X = hit_target_offset,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
hitExplosionContainer = new Container<HitExplosion>
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
BlendingMode = BlendingMode.Additive
},
barLineContainer = new Container<DrawableBarLine>
{
RelativeSizeAxes = Axes.Both,
},
new HitTarget
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
},
hitObjectContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
judgementContainer = new Container<DrawableTaikoJudgement>
{
RelativeSizeAxes = Axes.Y,
BlendingMode = BlendingMode.Additive
},
},
},
//barLineContainer = new Container<DrawableBarLine>
//{
// RelativeSizeAxes = Axes.Both,
//},
new HitTarget
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
},
hitObjectContainer = new Container
}
},
leftBackgroundContainer = new Container
{
Name = "Left overlay",
Size = new Vector2(left_area_size, DEFAULT_PLAYFIELD_HEIGHT),
BorderThickness = 1,
Children = new Drawable[]
{
leftBackground = new Box
{
RelativeSizeAxes = Axes.Both,
},
judgementContainer = new Container<DrawableTaikoJudgement>
new InputDrum
{
RelativeSizeAxes = Axes.Both,
BlendingMode = BlendingMode.Additive
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
Position = new Vector2(0.10f, 0),
Scale = new Vector2(0.9f)
},
},
},
}
},
leftBackgroundContainer = new Container
{
Size = new Vector2(left_area_size, PLAYFIELD_HEIGHT),
BorderThickness = 1,
Children = new Drawable[]
{
leftBackground = new Box
{
RelativeSizeAxes = Axes.Both,
},
new InputDrum
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
Position = new Vector2(0.10f, 0),
Scale = new Vector2(0.9f)
},
new Box
{
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = 10,
ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
new Box
{
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = 10,
ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
},
}
},
}
},
topLevelHitContainer = new Container
{
Name = "Top level hit objects",
RelativeSizeAxes = Axes.Both,
}
});
@ -173,12 +184,15 @@ namespace osu.Game.Modes.Taiko.UI
swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy());
}
public void AddBarLine(DrawableBarLine barLine)
{
barLineContainer.Add(barLine);
}
public override void OnJudgement(DrawableHitObject<TaikoHitObject, TaikoJudgement> judgedObject)
{
bool wasHit = judgedObject.Judgement.Result == HitResult.Hit;
if (wasHit)
hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement));
bool secondHit = judgedObject.Judgement.SecondHit;
judgementContainer.Add(new DrawableTaikoJudgement(judgedObject.Judgement)
{
@ -187,6 +201,73 @@ namespace osu.Game.Modes.Taiko.UI
RelativePositionAxes = Axes.X,
X = wasHit ? judgedObject.Position.X : 0,
});
if (!wasHit)
return;
if (!secondHit)
{
if (judgedObject.X >= -0.05f && !(judgedObject is DrawableSwell))
{
// If we're far enough away from the left stage, we should bring outselves in front of it
topLevelHitContainer.Add(judgedObject.CreateProxy());
}
hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement));
}
else
hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit();
}
/// <summary>
/// This is a very special type of container. It serves a similar purpose to <see cref="FillMode.Fit"/>, however unlike <see cref="FillMode.Fit"/>,
/// this will only adjust the scale relative to the height of its parent and will maintain the original width relative to its parent.
///
/// <para>
/// By adjusting the scale relative to the height of its parent, the aspect ratio of this container's children is maintained, however this is undesirable
/// in the case where the hit object container should not have its width adjusted by scale. To counteract this, another container is nested inside this
/// container which takes care of reversing the width adjustment while appearing transparent to the user.
/// </para>
/// </summary>
private class ScaleFixContainer : Container
{
protected override Container<Drawable> Content => widthAdjustmentContainer;
private readonly WidthAdjustmentContainer widthAdjustmentContainer;
/// <summary>
/// We only want to apply DrawScale in the Y-axis to preserve aspect ratio and <see cref="TaikoPlayfield"/> doesn't care about having its width adjusted.
/// </summary>
protected override Vector2 DrawScale => Scale * RelativeToAbsoluteFactor.Y / DrawHeight;
public ScaleFixContainer()
{
AddInternal(widthAdjustmentContainer = new WidthAdjustmentContainer { ParentDrawScaleReference = () => DrawScale.X });
}
/// <summary>
/// The container type that reverses the <see cref="Drawable.DrawScale"/> width adjustment.
/// </summary>
private class WidthAdjustmentContainer : Container
{
/// <summary>
/// This container needs to know its parent's <see cref="Drawable.DrawScale"/> so it can reverse the width adjustment caused by <see cref="Drawable.DrawScale"/>.
/// </summary>
public Func<float> ParentDrawScaleReference;
public WidthAdjustmentContainer()
{
// This container doesn't care about height, it should always fill its parent
RelativeSizeAxes = Axes.Y;
}
protected override void Update()
{
base.Update();
// Reverse the DrawScale adjustment
Width = Parent.DrawSize.X / ParentDrawScaleReference();
}
}
}
}
}

View File

@ -33,8 +33,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -53,22 +52,27 @@
<Compile Include="Judgements\TaikoStrongHitJudgement.cs" />
<Compile Include="Judgements\TaikoJudgement.cs" />
<Compile Include="Judgements\TaikoHitResult.cs" />
<Compile Include="Objects\BarLine.cs" />
<Compile Include="Objects\Drawables\DrawableBarLine.cs" />
<Compile Include="Objects\Drawables\DrawableBarLineMajor.cs" />
<Compile Include="Objects\CentreHit.cs" />
<Compile Include="Objects\Drawable\DrawableRimHit.cs" />
<Compile Include="Objects\Drawable\DrawableStrongRimHit.cs" />
<Compile Include="Objects\Drawable\DrawableCentreHit.cs" />
<Compile Include="Objects\Drawable\DrawableHit.cs" />
<Compile Include="Objects\Drawable\DrawableStrongCentreHit.cs" />
<Compile Include="Objects\Drawable\DrawableStrongHit.cs" />
<Compile Include="Objects\Drawable\Pieces\CentreHitSymbolPiece.cs" />
<Compile Include="Objects\Drawable\DrawableDrumRoll.cs" />
<Compile Include="Objects\Drawable\DrawableDrumRollTick.cs" />
<Compile Include="Objects\Drawable\DrawableSwell.cs" />
<Compile Include="Objects\Drawable\DrawableTaikoHitObject.cs" />
<Compile Include="Objects\Drawable\Pieces\RimHitSymbolPiece.cs" />
<Compile Include="Objects\Drawable\Pieces\StrongCirclePiece.cs" />
<Compile Include="Objects\Drawable\Pieces\CirclePiece.cs" />
<Compile Include="Objects\Drawable\Pieces\SwellSymbolPiece.cs" />
<Compile Include="Objects\Drawables\DrawableRimHit.cs" />
<Compile Include="Objects\Drawables\DrawableRimHitStrong.cs" />
<Compile Include="Objects\Drawables\DrawableCentreHit.cs" />
<Compile Include="Objects\Drawables\DrawableHit.cs" />
<Compile Include="Objects\Drawables\DrawableCentreHitStrong.cs" />
<Compile Include="Objects\Drawables\DrawableHitStrong.cs" />
<Compile Include="Objects\Drawables\Pieces\ElongatedCirclePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\CentreHitSymbolPiece.cs" />
<Compile Include="Objects\Drawables\DrawableDrumRoll.cs" />
<Compile Include="Objects\Drawables\DrawableDrumRollTick.cs" />
<Compile Include="Objects\Drawables\DrawableSwell.cs" />
<Compile Include="Objects\Drawables\DrawableTaikoHitObject.cs" />
<Compile Include="Objects\Drawables\Pieces\RimHitSymbolPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\SwellSymbolPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\TaikoPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\TickPiece.cs" />
<Compile Include="Objects\DrumRoll.cs" />
<Compile Include="Objects\DrumRollTick.cs" />
<Compile Include="Objects\Hit.cs" />
@ -107,7 +111,7 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>

View File

@ -4,5 +4,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.1340" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1341" targetFramework="net45" />
</packages>

View File

@ -6,11 +6,12 @@ using NUnit.Framework;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes;
using osu.Game.Tests.Resources;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Objects.Legacy;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Tests.Beatmaps.Formats
{
@ -55,7 +56,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo;
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(false, beatmapInfo.Countdown);
Assert.AreEqual(SampleSet.Soft, beatmapInfo.SampleSet);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode);
@ -137,12 +137,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(slider);
Assert.AreEqual(new Vector2(192, 168), slider.Position);
Assert.AreEqual(956, slider.StartTime);
Assert.AreEqual(SampleType.None, slider.Sample.Type);
Assert.IsTrue(slider.Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
var hit = beatmap.HitObjects[1] as LegacyHit;
Assert.IsNotNull(hit);
Assert.AreEqual(new Vector2(304, 56), hit.Position);
Assert.AreEqual(1285, hit.StartTime);
Assert.AreEqual(SampleType.Clap, hit.Sample.Type);
Assert.IsTrue(hit.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
}
}
}

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