Merge remote-tracking branch 'origin/master' into taiko_barlines

Conflicts:
	osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
	osu.Game.Modes.Taiko/UI/TaikoHitRenderer.cs
	osu.Game.Modes.Taiko/UI/TaikoPlayfield.cs
	osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
This commit is contained in:
smoogipooo
2017-04-01 23:57:02 +09:00
266 changed files with 4341 additions and 1692 deletions

View File

@ -53,7 +53,7 @@ namespace osu.Desktop.Deploy
private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg"; private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg"; private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
private static Stopwatch sw = new Stopwatch(); private static readonly Stopwatch sw = new Stopwatch();
private static string codeSigningPassword; private static string codeSigningPassword;

View File

@ -13,10 +13,10 @@ using osu.Game.Modes.Taiko;
namespace osu.Desktop.Tests namespace osu.Desktop.Tests
{ {
[TestFixture] [TestFixture]
public class BenchmarkTest public class VisualTests
{ {
[Test] [Test]
public void TestBenchmark() public void TestVisualTests()
{ {
using (var host = new HeadlessGameHost()) using (var host = new HeadlessGameHost())
{ {
@ -25,7 +25,7 @@ namespace osu.Desktop.Tests
Ruleset.Register(new ManiaRuleset()); Ruleset.Register(new ManiaRuleset());
Ruleset.Register(new CatchRuleset()); Ruleset.Register(new CatchRuleset());
host.Run(new Benchmark()); host.Run(new AutomatedVisualTestGame());
} }
} }
} }

View File

@ -56,7 +56,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BenchmarkTest.cs" /> <Compile Include="VisualTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework.Desktop\osu.Framework.Desktop.csproj"> <ProjectReference Include="..\osu-framework\osu.Framework.Desktop\osu.Framework.Desktop.csproj">

View File

@ -0,0 +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 osu.Framework.Testing;
using osu.Game;
namespace osu.Desktop.VisualTests
{
public class AutomatedVisualTestGame : OsuGameBase
{
protected override void LoadComplete()
{
base.LoadComplete();
// Have to construct this here, rather than in the constructor, because
// we depend on some dependencies to be loaded within OsuGameBase.load().
Add(new TestRunner(new TestBrowser()));
}
}
}

View File

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

View File

@ -1,45 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Screens.Testing;
using osu.Game;
namespace osu.Desktop.VisualTests
{
public class Benchmark : OsuGameBase
{
private double timePerTest = 200;
[BackgroundDependencyLoader]
private void load()
{
Host.MaximumDrawHz = int.MaxValue;
Host.MaximumUpdateHz = int.MaxValue;
Host.MaximumInactiveHz = int.MaxValue;
}
protected override void LoadComplete()
{
base.LoadComplete();
TestBrowser f = new TestBrowser();
Add(f);
Console.WriteLine($@"{Time}: Running {f.TestCount} tests for {timePerTest}ms each...");
for (int i = 1; i < f.TestCount; i++)
{
int loadableCase = i;
Scheduler.AddDelayed(delegate
{
f.LoadTest(loadableCase);
Console.WriteLine($@"{Time}: Switching to test #{loadableCase}");
}, loadableCase * timePerTest);
}
Scheduler.AddDelayed(Host.Exit, f.TestCount * timePerTest);
}
}
}

View File

@ -27,7 +27,7 @@ namespace osu.Desktop.VisualTests
Ruleset.Register(new CatchRuleset()); Ruleset.Register(new CatchRuleset());
if (benchmark) if (benchmark)
host.Run(new Benchmark()); host.Run(new AutomatedVisualTestGame());
else else
host.Run(new VisualTestGame()); host.Run(new VisualTestGame());
} }

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 OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Screens.Select;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseBeatmapDetailArea : TestCase
{
public override string Description => @"Beatmap details in song select";
public override void Reset()
{
base.Reset();
Add(new BeatmapDetailArea
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(550f, 450f),
});
}
}
}

View File

@ -3,7 +3,7 @@
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Screens.Select.Options; using osu.Game.Screens.Select.Options;
@ -26,7 +26,7 @@ namespace osu.Desktop.VisualTests.Tests
Add(overlay); Add(overlay);
AddButton(@"Toggle", overlay.ToggleVisibility); AddStep(@"Toggle", overlay.ToggleVisibility);
} }
} }
} }

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Overlays; using osu.Game.Overlays;

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Dialog;
@ -20,7 +20,7 @@ namespace osu.Desktop.VisualTests.Tests
Add(overlay = new DialogOverlay()); Add(overlay = new DialogOverlay());
AddButton("dialog #1", () => overlay.Push(new PopupDialog AddStep("dialog #1", () => overlay.Push(new PopupDialog
{ {
Icon = FontAwesome.fa_trash_o, Icon = FontAwesome.fa_trash_o,
HeaderText = @"Confirm deletion of", HeaderText = @"Confirm deletion of",
@ -40,7 +40,7 @@ namespace osu.Desktop.VisualTests.Tests
}, },
})); }));
AddButton("dialog #2", () => overlay.Push(new PopupDialog AddStep("dialog #2", () => overlay.Push(new PopupDialog
{ {
Icon = FontAwesome.fa_gear, Icon = FontAwesome.fa_gear,
HeaderText = @"What do you want to do with", HeaderText = @"What do you want to do with",

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Screens.Tournament; using osu.Game.Screens.Tournament;
using osu.Game.Screens.Tournament.Teams; using osu.Game.Screens.Tournament.Teams;
using osu.Game.Users; using osu.Game.Users;

View File

@ -5,7 +5,7 @@ using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Database; using osu.Game.Database;

View File

@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Modes.Objects; using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
@ -21,7 +21,7 @@ namespace osu.Desktop.VisualTests.Tests
{ {
internal class TestCaseHitObjects : TestCase internal class TestCaseHitObjects : TestCase
{ {
private FramedClock framedClock; private readonly FramedClock framedClock;
private bool auto; private bool auto;
@ -34,7 +34,7 @@ namespace osu.Desktop.VisualTests.Tests
private HitObjectType mode = HitObjectType.Slider; private HitObjectType mode = HitObjectType.Slider;
private BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 }; private readonly BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 };
private Container playfieldContainer; private Container playfieldContainer;
private Container approachContainer; private Container approachContainer;
@ -93,19 +93,28 @@ namespace osu.Desktop.VisualTests.Tests
playbackSpeed.TriggerChange(); playbackSpeed.TriggerChange();
AddButton(@"circles", () => load(HitObjectType.Circle)); AddStep(@"circles", () => load(HitObjectType.Circle));
AddButton(@"slider", () => load(HitObjectType.Slider)); AddStep(@"slider", () => load(HitObjectType.Slider));
AddButton(@"spinner", () => load(HitObjectType.Spinner)); AddStep(@"spinner", () => load(HitObjectType.Spinner));
AddToggle(@"auto", state => { auto = state; load(mode); }); AddToggleStep(@"auto", state => { auto = state; load(mode); });
ButtonsContainer.Add(new SpriteText { Text = "Playback Speed" }); Add(new Container
ButtonsContainer.Add(new BasicSliderBar<double>
{ {
Width = 150, Anchor = Anchor.TopRight,
Height = 10, Origin = Anchor.TopRight,
SelectionColor = Color4.Orange, AutoSizeAxes = Axes.Both,
Bindable = playbackSpeed Children = new Drawable[]
{
new SpriteText { Text = "Playback Speed" },
new BasicSliderBar<double>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Bindable = playbackSpeed
}
}
}); });
framedClock.ProcessFrame(); framedClock.ProcessFrame();
@ -136,7 +145,7 @@ namespace osu.Desktop.VisualTests.Tests
if (auto) if (auto)
{ {
h.State = ArmedState.Hit; h.State = ArmedState.Hit;
h.Judgement = new OsuJudgementInfo { Result = HitResult.Hit }; h.Judgement = new OsuJudgement { Result = HitResult.Hit };
} }
playfieldContainer.Add(h); playfieldContainer.Add(h);

View File

@ -1,16 +1,16 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using OpenTK.Input; using OpenTK.Input;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests namespace osu.Desktop.VisualTests.Tests
@ -38,19 +38,30 @@ namespace osu.Desktop.VisualTests.Tests
}; };
BindableInt bindable = new BindableInt { MinValue = 0, MaxValue = 200, Default = 50 }; BindableInt bindable = new BindableInt { MinValue = 0, MaxValue = 200, Default = 50 };
bindable.ValueChanged += delegate { kc.FadeTime = bindable.Value; }; bindable.ValueChanged += delegate { kc.FadeTime = bindable.Value; };
AddButton("Add Random", () => AddStep("Add Random", () =>
{ {
Key key = (Key)((int)Key.A + RNG.Next(26)); Key key = (Key)((int)Key.A + RNG.Next(26));
kc.Add(new KeyCounterKeyboard(key)); kc.Add(new KeyCounterKeyboard(key));
}); });
ButtonsContainer.Add(new SpriteText { Text = "FadeTime" });
ButtonsContainer.Add(new TestSliderBar<int> Add(new Container
{ {
Width = 150, Anchor = Anchor.TopRight,
Height = 10, Origin = Anchor.TopRight,
SelectionColor = Color4.Orange, AutoSizeAxes = Axes.Both,
Bindable = bindable Children = new Drawable[]
{
new SpriteText { Text = "FadeTime" },
new TestSliderBar<int>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Bindable = bindable
}
}
}); });
Add(kc); Add(kc);
} }
private class TestSliderBar<T> : SliderBar<T> where T : struct private class TestSliderBar<T> : SliderBar<T> where T : struct

View File

@ -3,10 +3,10 @@
using OpenTK; using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Modes;
using osu.Game.Modes.Mods; using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Mods; using osu.Game.Modes.Osu.Mods;
using osu.Game.Modes.Scoring;
using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users; using osu.Game.Users;
@ -218,7 +218,7 @@ namespace osu.Desktop.VisualTests.Tests
Size = new Vector2(550f, 450f), Size = new Vector2(550f, 450f),
}); });
AddButton(@"New Scores", newScores); AddStep(@"New Scores", newScores);
newScores(); newScores();
} }
} }

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;

View File

@ -3,7 +3,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Overlays.Mods; using osu.Game.Overlays.Mods;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Modes; using osu.Game.Modes;
namespace osu.Desktop.VisualTests.Tests namespace osu.Desktop.VisualTests.Tests
@ -25,11 +25,11 @@ namespace osu.Desktop.VisualTests.Tests
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
}); });
AddButton("Toggle", modSelect.ToggleVisibility); AddStep("Toggle", modSelect.ToggleVisibility);
AddButton("osu!", () => modSelect.PlayMode.Value = PlayMode.Osu); AddStep("osu!", () => modSelect.PlayMode.Value = PlayMode.Osu);
AddButton("osu!taiko", () => modSelect.PlayMode.Value = PlayMode.Taiko); AddStep("osu!taiko", () => modSelect.PlayMode.Value = PlayMode.Taiko);
AddButton("osu!catch", () => modSelect.PlayMode.Value = PlayMode.Catch); AddStep("osu!catch", () => modSelect.PlayMode.Value = PlayMode.Catch);
AddButton("osu!mania", () => modSelect.PlayMode.Value = PlayMode.Mania); AddStep("osu!mania", () => modSelect.PlayMode.Value = PlayMode.Mania);
} }
} }
} }

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Overlays; using osu.Game.Overlays;
@ -30,7 +30,7 @@ namespace osu.Desktop.VisualTests.Tests
Anchor = Anchor.Centre Anchor = Anchor.Centre
}; };
Add(mc); Add(mc);
AddToggle(@"Show", state => mc.State = state ? Visibility.Visible : Visibility.Hidden); AddToggleStep(@"Show", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
} }
} }
} }

View File

@ -3,7 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Overlays; using osu.Game.Overlays;
using System.Linq; using System.Linq;
@ -30,13 +30,13 @@ namespace osu.Desktop.VisualTests.Tests
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
}); });
AddToggle(@"show", state => manager.State = state ? Visibility.Visible : Visibility.Hidden); AddToggleStep(@"show", state => manager.State = state ? Visibility.Visible : Visibility.Hidden);
AddButton(@"simple #1", sendNotification1); AddStep(@"simple #1", sendNotification1);
AddButton(@"simple #2", sendNotification2); AddStep(@"simple #2", sendNotification2);
AddButton(@"progress #1", sendProgress1); AddStep(@"progress #1", sendProgress1);
AddButton(@"progress #2", sendProgress2); AddStep(@"progress #2", sendProgress2);
AddButton(@"barrage", () => sendBarrage()); AddStep(@"barrage", () => sendBarrage());
} }
private void sendBarrage(int remaining = 100) private void sendBarrage(int remaining = 100)
@ -95,7 +95,7 @@ namespace osu.Desktop.VisualTests.Tests
progressingNotifications.Add(n); progressingNotifications.Add(n);
} }
private List<ProgressNotification> progressingNotifications = new List<ProgressNotification>(); private readonly List<ProgressNotification> progressingNotifications = new List<ProgressNotification>();
private void sendProgress1() private void sendProgress1()
{ {

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Overlays; using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests namespace osu.Desktop.VisualTests.Tests

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests namespace osu.Desktop.VisualTests.Tests
@ -25,8 +25,8 @@ namespace osu.Desktop.VisualTests.Tests
OnRetry = () => Logger.Log(@"Retry"), OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit") OnQuit = () => Logger.Log(@"Quit")
}); });
AddButton("Pause", pauseOverlay.Show); AddStep("Pause", pauseOverlay.Show);
AddButton("Add Retry", delegate AddStep("Add Retry", delegate
{ {
retryCount++; retryCount++;
pauseOverlay.Retries = retryCount; pauseOverlay.Retries = retryCount;

View File

@ -3,7 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using osu.Desktop.VisualTests.Platform; using osu.Desktop.VisualTests.Platform;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Modes; using osu.Game.Modes;
@ -23,12 +23,10 @@ namespace osu.Desktop.VisualTests.Tests
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
oldDb = Dependencies.Get<BeatmapDatabase>();
if (db == null) if (db == null)
{ {
storage = new TestStorage(@"TestCasePlaySongSelect"); storage = new TestStorage(@"TestCasePlaySongSelect");
db = new BeatmapDatabase(storage); db = new BeatmapDatabase(storage);
Dependencies.Cache(db, true);
var sets = new List<BeatmapSetInfo>(); var sets = new List<BeatmapSetInfo>();
@ -40,19 +38,16 @@ namespace osu.Desktop.VisualTests.Tests
Add(songSelect = new PlaySongSelect()); Add(songSelect = new PlaySongSelect());
AddButton(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
AddButton(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; }); AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
AddButton(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; }); AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
AddButton(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; }); AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
if (oldDb != null) if (oldDb != null)
{
Dependencies.Cache(oldDb, true);
db = null; db = null;
}
base.Dispose(isDisposing); base.Dispose(isDisposing);
} }

View File

@ -4,7 +4,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using OpenTK; using OpenTK;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;

View File

@ -6,7 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
@ -68,7 +68,7 @@ namespace osu.Desktop.VisualTests.Tests
}; };
Add(starsLabel); Add(starsLabel);
AddButton(@"Reset all", delegate AddStep(@"Reset all", delegate
{ {
score.Current.Value = 0; score.Current.Value = 0;
comboCounter.Current.Value = 0; comboCounter.Current.Value = 0;
@ -78,7 +78,7 @@ namespace osu.Desktop.VisualTests.Tests
starsLabel.Text = stars.Count.ToString("0.00"); starsLabel.Text = stars.Count.ToString("0.00");
}); });
AddButton(@"Hit! :D", delegate AddStep(@"Hit! :D", delegate
{ {
score.Current.Value += 300 + (ulong)(300.0 * (comboCounter.Current > 0 ? comboCounter.Current - 1 : 0) / 25.0); score.Current.Value += 300 + (ulong)(300.0 * (comboCounter.Current > 0 ? comboCounter.Current - 1 : 0) / 25.0);
comboCounter.Increment(); comboCounter.Increment();
@ -86,20 +86,20 @@ namespace osu.Desktop.VisualTests.Tests
accuracyCounter.SetFraction(numerator, denominator); accuracyCounter.SetFraction(numerator, denominator);
}); });
AddButton(@"miss...", delegate AddStep(@"miss...", delegate
{ {
comboCounter.Current.Value = 0; comboCounter.Current.Value = 0;
denominator++; denominator++;
accuracyCounter.SetFraction(numerator, denominator); accuracyCounter.SetFraction(numerator, denominator);
}); });
AddButton(@"Alter stars", delegate AddStep(@"Alter stars", delegate
{ {
stars.Count = RNG.NextSingle() * (stars.StarCount + 1); stars.Count = RNG.NextSingle() * (stars.StarCount + 1);
starsLabel.Text = stars.Count.ToString("0.00"); starsLabel.Text = stars.Count.ToString("0.00");
}); });
AddButton(@"Stop counters", delegate AddStep(@"Stop counters", delegate
{ {
score.StopRolling(); score.StopRolling();
comboCounter.StopRolling(); comboCounter.StopRolling();

View File

@ -3,7 +3,7 @@
using OpenTK; using OpenTK;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Select.Filter; using osu.Game.Screens.Select.Filter;

View File

@ -0,0 +1,135 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Objects.Drawable.Pieces;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseTaikoHitObjects : TestCase
{
public override string Description => "Taiko hit objects";
private bool kiai;
public override void Reset()
{
base.Reset();
AddToggleStep("Kiai", b =>
{
kiai = !kiai;
Reset();
});
Add(new CirclePiece
{
Position = new Vector2(100, 100),
Width = 0,
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
{
new CentreHitSymbolPiece()
}
});
Add(new StrongCirclePiece
{
Position = new Vector2(350, 100),
Width = 0,
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
{
new CentreHitSymbolPiece()
}
});
Add(new CirclePiece
{
Position = new Vector2(100, 300),
Width = 0,
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
{
new RimHitSymbolPiece()
}
});
Add(new StrongCirclePiece
{
Position = new Vector2(350, 300),
Width = 0,
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
{
new RimHitSymbolPiece()
}
});
Add(new CirclePiece
{
Position = new Vector2(100, 500),
Width = 0,
AccentColour = Color4.Orange,
KiaiMode = kiai,
Children = new[]
{
new SwellSymbolPiece()
}
});
Add(new DrumRollCircle(new CirclePiece
{
KiaiMode = kiai
})
{
Width = 250,
Position = new Vector2(575, 100)
});
Add(new DrumRollCircle(new StrongCirclePiece
{
KiaiMode = kiai
})
{
Width = 250,
Position = new Vector2(575, 300)
});
}
private class DrumRollCircle : BaseCircle
{
public DrumRollCircle(CirclePiece piece)
: base(piece)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Piece.AccentColour = colours.YellowDark;
}
}
private abstract class BaseCircle : Container
{
protected readonly CirclePiece Piece;
protected BaseCircle(CirclePiece piece)
{
Piece = piece;
Add(Piece);
}
}
}
}

View File

@ -1,8 +1,11 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // 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.Primitives;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements; using osu.Game.Modes.Taiko.Judgements;
@ -27,15 +30,24 @@ namespace osu.Desktop.VisualTests.Tests
{ {
base.Reset(); base.Reset();
Clock.ProcessFrame(); AddStep("Hit!", addHitJudgement);
AddStep("Miss :(", addMissJudgement);
AddButton("Hit!", addHitJudgement); AddStep("Swell", addSwell);
AddButton("Miss :(", addMissJudgement); AddStep("Centre", () => addCentreHit(false));
AddStep("Strong Centre", () => addCentreHit(true));
AddButton("Add bar line", addBarLine); AddButton("Add bar line", addBarLine);
AddStep("Rim", () => addRimHit(false));
AddStep("Strong Rim", () => addRimHit(true));
Add(playfield = new TaikoPlayfield Add(new Container
{ {
Y = 200 RelativeSizeAxes = Axes.X,
Y = 200,
Padding = new MarginPadding { Left = 200 },
Children = new[]
{
playfield = new TaikoPlayfield()
}
}); });
} }
@ -43,15 +55,14 @@ namespace osu.Desktop.VisualTests.Tests
{ {
TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great; TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great;
playfield.OnJudgement(new DrawableTestHit(new TaikoHitObject()) playfield.OnJudgement(new DrawableTestHit(new Hit())
{ {
X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f), X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f),
Judgement = new TaikoJudgementInfo Judgement = new TaikoJudgement
{ {
Result = HitResult.Hit, Result = HitResult.Hit,
TaikoResult = hitResult, TaikoResult = hitResult,
TimeOffset = 0, TimeOffset = 0,
ComboAtHit = 1,
SecondHit = RNG.Next(10) == 0 SecondHit = RNG.Next(10) == 0
} }
}); });
@ -59,13 +70,12 @@ namespace osu.Desktop.VisualTests.Tests
private void addMissJudgement() private void addMissJudgement()
{ {
playfield.OnJudgement(new DrawableTestHit(new TaikoHitObject()) playfield.OnJudgement(new DrawableTestHit(new Hit())
{ {
Judgement = new TaikoJudgementInfo Judgement = new TaikoJudgement
{ {
Result = HitResult.Miss, Result = HitResult.Miss,
TimeOffset = 0, TimeOffset = 0
ComboAtHit = 0
} }
}); });
} }
@ -83,14 +93,52 @@ namespace osu.Desktop.VisualTests.Tests
playfield.AddBarLine(isMajor ? new DrawableMajorBarLine(bl) : new DrawableBarLine(bl)); playfield.AddBarLine(isMajor ? new DrawableMajorBarLine(bl) : new DrawableBarLine(bl));
} }
private class DrawableTestHit : DrawableHitObject<TaikoHitObject, TaikoJudgementInfo> private void addSwell()
{
playfield.Add(new DrawableSwell(new Swell
{
StartTime = Time.Current + 1000,
EndTime = Time.Current + 5000,
PreEmpt = 1000
}));
}
private void addCentreHit(bool strong)
{
Hit h = new Hit
{
StartTime = Time.Current + 1000,
PreEmpt = 1000
};
if (strong)
playfield.Add(new DrawableStrongCentreHit(h));
else
playfield.Add(new DrawableCentreHit(h));
}
private void addRimHit(bool strong)
{
Hit h = new Hit
{
StartTime = Time.Current + 1000,
PreEmpt = 1000
};
if (strong)
playfield.Add(new DrawableStrongRimHit(h));
else
playfield.Add(new DrawableRimHit(h));
}
private class DrawableTestHit : DrawableHitObject<TaikoHitObject, TaikoJudgement>
{ {
public DrawableTestHit(TaikoHitObject hitObject) public DrawableTestHit(TaikoHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
} }
protected override TaikoJudgementInfo CreateJudgementInfo() => new TaikoJudgementInfo(); protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Screens.Testing; using osu.Framework.Testing;
using osu.Game; using osu.Game;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
@ -24,6 +24,11 @@ namespace osu.Desktop.VisualTests
public override void SetHost(GameHost host) public override void SetHost(GameHost host)
{ {
base.SetHost(host); base.SetHost(host);
host.UpdateThread.InactiveHz = host.UpdateThread.ActiveHz;
host.DrawThread.InactiveHz = host.DrawThread.ActiveHz;
host.InputThread.InactiveHz = host.InputThread.ActiveHz;
host.Window.CursorState = CursorState.Hidden; host.Window.CursorState = CursorState.Hidden;
} }
} }

View File

@ -150,6 +150,10 @@
<Project>{65dc628f-a640-4111-ab35-3a5652bc1e17}</Project> <Project>{65dc628f-a640-4111-ab35-3a5652bc1e17}</Project>
<Name>osu.Framework.Desktop</Name> <Name>osu.Framework.Desktop</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-framework\osu.Framework.Testing\osu.Framework.Testing.csproj">
<Project>{007b2356-ab6f-4bd9-96d5-116fc2dce69a}</Project>
<Name>osu.Framework.Testing</Name>
</ProjectReference>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj"> <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project> <Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
<Name>osu.Framework</Name> <Name>osu.Framework</Name>
@ -180,7 +184,7 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Benchmark.cs" /> <Compile Include="AutomatedVisualTestGame.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Tests\TestCaseChatDisplay.cs" /> <Compile Include="Tests\TestCaseChatDisplay.cs" />
<Compile Include="Tests\TestCaseDrawings.cs" /> <Compile Include="Tests\TestCaseDrawings.cs" />
@ -194,6 +198,7 @@
<Compile Include="Tests\TestCaseReplay.cs" /> <Compile Include="Tests\TestCaseReplay.cs" />
<Compile Include="Tests\TestCaseScoreCounter.cs" /> <Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTabControl.cs" /> <Compile Include="Tests\TestCaseTabControl.cs" />
<Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" /> <Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" /> <Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" /> <Compile Include="Tests\TestCasePlaySongSelect.cs" />
@ -207,12 +212,11 @@
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" /> <Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Tests\TestCaseLeaderboard.cs" /> <Compile Include="Tests\TestCaseLeaderboard.cs" />
<Compile Include="Beatmaps\TestWorkingBeatmap.cs" /> <Compile Include="Beatmaps\TestWorkingBeatmap.cs" />
<Compile Include="Tests\TestCaseBeatmapDetailArea.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<ItemGroup /> <ItemGroup />
<ItemGroup> <ItemGroup />
<Folder Include="Beatmaps\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\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. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -0,0 +1,29 @@
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
<!-- XQuartz compatibility (X11 on Mac) -->
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>

View File

@ -17,7 +17,7 @@ namespace osu.Desktop
{ {
internal class OsuGameDesktop : OsuGame internal class OsuGameDesktop : OsuGame
{ {
private VersionManager versionManager; private readonly VersionManager versionManager;
public OsuGameDesktop(string[] args = null) public OsuGameDesktop(string[] args = null)
: base(args) : base(args)

View File

@ -123,7 +123,10 @@
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath> <HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4" /> <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>
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath> <HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -150,6 +153,7 @@
<None Include="..\osu.licenseheader"> <None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link> <Link>osu.licenseheader</Link>
</None> </None>
<None Include="OpenTK.dll.config" />
<None Include="osu!.res" /> <None Include="osu!.res" />
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="Properties\app.manifest" /> <None Include="Properties\app.manifest" />

View File

@ -7,6 +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="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" 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="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1340" targetFramework="net45" />
<package id="Splat" version="2.0.0" targetFramework="net45" /> <package id="Splat" version="2.0.0" targetFramework="net45" />
<package id="squirrel.windows" version="1.5.2" targetFramework="net45" /> <package id="squirrel.windows" version="1.5.2" targetFramework="net45" />
</packages> </packages>

View File

@ -10,6 +10,8 @@ using osu.Game.Modes.Mods;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Modes.Catch.Scoring;
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Catch namespace osu.Game.Modes.Catch
{ {

View File

@ -5,7 +5,10 @@ using osu.Game.Modes.Judgements;
namespace osu.Game.Modes.Catch.Judgements namespace osu.Game.Modes.Catch.Judgements
{ {
public class CatchJudgementInfo : JudgementInfo public class CatchJudgement : Judgement
{ {
public override string ResultString => string.Empty;
public override string MaxResultString => string.Empty;
} }
} }

View File

@ -12,7 +12,7 @@ namespace osu.Game.Modes.Catch.Objects.Drawable
{ {
internal class DrawableFruit : Sprite internal class DrawableFruit : Sprite
{ {
private CatchBaseHit h; private readonly CatchBaseHit h;
public DrawableFruit(CatchBaseHit h) public DrawableFruit(CatchBaseHit h)
{ {
@ -29,7 +29,7 @@ namespace osu.Game.Modes.Catch.Objects.Drawable
{ {
Texture = textures.Get(@"Menu/logo"); Texture = textures.Get(@"Menu/logo");
double duration = 0; const double duration = 0;
Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) }); Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) });
Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 }); Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });

View File

@ -3,22 +3,23 @@
using osu.Game.Modes.Catch.Judgements; using osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects; using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
namespace osu.Game.Modes.Catch namespace osu.Game.Modes.Catch.Scoring
{ {
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgementInfo> internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgement>
{ {
public CatchScoreProcessor() public CatchScoreProcessor()
{ {
} }
public CatchScoreProcessor(HitRenderer<CatchBaseHit, CatchJudgementInfo> hitRenderer) public CatchScoreProcessor(HitRenderer<CatchBaseHit, CatchJudgement> hitRenderer)
: base(hitRenderer) : base(hitRenderer)
{ {
} }
protected override void UpdateCalculations(CatchJudgementInfo newJudgement) protected override void OnNewJudgement(CatchJudgement judgement)
{ {
} }
} }

View File

@ -5,12 +5,14 @@ using osu.Game.Beatmaps;
using osu.Game.Modes.Catch.Beatmaps; using osu.Game.Modes.Catch.Beatmaps;
using osu.Game.Modes.Catch.Judgements; using osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects; using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.Catch.Scoring;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
namespace osu.Game.Modes.Catch.UI namespace osu.Game.Modes.Catch.UI
{ {
public class CatchHitRenderer : HitRenderer<CatchBaseHit, CatchJudgementInfo> public class CatchHitRenderer : HitRenderer<CatchBaseHit, CatchJudgement>
{ {
public CatchHitRenderer(WorkingBeatmap beatmap) public CatchHitRenderer(WorkingBeatmap beatmap)
: base(beatmap) : base(beatmap)
@ -23,8 +25,8 @@ namespace osu.Game.Modes.Catch.UI
protected override IBeatmapProcessor<CatchBaseHit> CreateBeatmapProcessor() => new CatchBeatmapProcessor(); protected override IBeatmapProcessor<CatchBaseHit> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
protected override Playfield<CatchBaseHit, CatchJudgementInfo> CreatePlayfield() => new CatchPlayfield(); protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield();
protected override DrawableHitObject<CatchBaseHit, CatchJudgementInfo> GetVisualRepresentation(CatchBaseHit h) => null; protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h) => null;
} }
} }

View File

@ -10,7 +10,7 @@ using osu.Game.Modes.Catch.Judgements;
namespace osu.Game.Modes.Catch.UI namespace osu.Game.Modes.Catch.UI
{ {
public class CatchPlayfield : Playfield<CatchBaseHit, CatchJudgementInfo> public class CatchPlayfield : Playfield<CatchBaseHit, CatchJudgement>
{ {
public CatchPlayfield() public CatchPlayfield()
{ {

View File

@ -50,8 +50,8 @@
<Compile Include="Beatmaps\CatchBeatmapConverter.cs" /> <Compile Include="Beatmaps\CatchBeatmapConverter.cs" />
<Compile Include="Beatmaps\CatchBeatmapProcessor.cs" /> <Compile Include="Beatmaps\CatchBeatmapProcessor.cs" />
<Compile Include="CatchDifficultyCalculator.cs" /> <Compile Include="CatchDifficultyCalculator.cs" />
<Compile Include="CatchScoreProcessor.cs" /> <Compile Include="Scoring\CatchScoreProcessor.cs" />
<Compile Include="Judgements\CatchJudgementInfo.cs" /> <Compile Include="Judgements\CatchJudgement.cs" />
<Compile Include="Objects\CatchBaseHit.cs" /> <Compile Include="Objects\CatchBaseHit.cs" />
<Compile Include="Objects\Drawable\DrawableFruit.cs" /> <Compile Include="Objects\Drawable\DrawableFruit.cs" />
<Compile Include="Objects\Droplet.cs" /> <Compile Include="Objects\Droplet.cs" />

View File

@ -5,7 +5,10 @@ using osu.Game.Modes.Judgements;
namespace osu.Game.Modes.Mania.Judgements namespace osu.Game.Modes.Mania.Judgements
{ {
public class ManiaJudgementInfo : JudgementInfo public class ManiaJudgement : Judgement
{ {
public override string ResultString => string.Empty;
public override string MaxResultString => string.Empty;
} }
} }

View File

@ -9,6 +9,8 @@ using osu.Game.Modes.Mods;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Modes.Mania.Scoring;
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Mania namespace osu.Game.Modes.Mania
{ {

View File

@ -26,7 +26,7 @@ namespace osu.Game.Modes.Mania.Objects.Drawable
{ {
Texture = textures.Get(@"Menu/logo"); Texture = textures.Get(@"Menu/logo");
double duration = 0; const double duration = 0;
Transforms.Add(new TransformPositionY { StartTime = note.StartTime - 200, EndTime = note.StartTime, StartValue = -0.1f, EndValue = 0.9f }); Transforms.Add(new TransformPositionY { StartTime = note.StartTime - 200, EndTime = note.StartTime, StartValue = -0.1f, EndValue = 0.9f });
Transforms.Add(new TransformAlpha { StartTime = note.StartTime + duration + 200, EndTime = note.StartTime + duration + 400, StartValue = 1, EndValue = 0 }); Transforms.Add(new TransformAlpha { StartTime = note.StartTime + duration + 200, EndTime = note.StartTime + duration + 400, StartValue = 1, EndValue = 0 });

View File

@ -3,22 +3,23 @@
using osu.Game.Modes.Mania.Judgements; using osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects; using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania namespace osu.Game.Modes.Mania.Scoring
{ {
internal class ManiaScoreProcessor : ScoreProcessor<ManiaBaseHit, ManiaJudgementInfo> internal class ManiaScoreProcessor : ScoreProcessor<ManiaBaseHit, ManiaJudgement>
{ {
public ManiaScoreProcessor() public ManiaScoreProcessor()
{ {
} }
public ManiaScoreProcessor(HitRenderer<ManiaBaseHit, ManiaJudgementInfo> hitRenderer) public ManiaScoreProcessor(HitRenderer<ManiaBaseHit, ManiaJudgement> hitRenderer)
: base(hitRenderer) : base(hitRenderer)
{ {
} }
protected override void UpdateCalculations(ManiaJudgementInfo newJudgement) protected override void OnNewJudgement(ManiaJudgement judgement)
{ {
} }
} }

View File

@ -5,12 +5,14 @@ using osu.Game.Beatmaps;
using osu.Game.Modes.Mania.Beatmaps; using osu.Game.Modes.Mania.Beatmaps;
using osu.Game.Modes.Mania.Judgements; using osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects; using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.Mania.Scoring;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania.UI namespace osu.Game.Modes.Mania.UI
{ {
public class ManiaHitRenderer : HitRenderer<ManiaBaseHit, ManiaJudgementInfo> public class ManiaHitRenderer : HitRenderer<ManiaBaseHit, ManiaJudgement>
{ {
private readonly int columns; private readonly int columns;
@ -26,8 +28,8 @@ namespace osu.Game.Modes.Mania.UI
protected override IBeatmapProcessor<ManiaBaseHit> CreateBeatmapProcessor() => new ManiaBeatmapProcessor(); protected override IBeatmapProcessor<ManiaBaseHit> CreateBeatmapProcessor() => new ManiaBeatmapProcessor();
protected override Playfield<ManiaBaseHit, ManiaJudgementInfo> CreatePlayfield() => new ManiaPlayfield(columns); protected override Playfield<ManiaBaseHit, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(columns);
protected override DrawableHitObject<ManiaBaseHit, ManiaJudgementInfo> GetVisualRepresentation(ManiaBaseHit h) => null; protected override DrawableHitObject<ManiaBaseHit, ManiaJudgement> GetVisualRepresentation(ManiaBaseHit h) => null;
} }
} }

View File

@ -11,7 +11,7 @@ using osu.Game.Modes.Mania.Judgements;
namespace osu.Game.Modes.Mania.UI namespace osu.Game.Modes.Mania.UI
{ {
public class ManiaPlayfield : Playfield<ManiaBaseHit, ManiaJudgementInfo> public class ManiaPlayfield : Playfield<ManiaBaseHit, ManiaJudgement>
{ {
public ManiaPlayfield(int columns) public ManiaPlayfield(int columns)
{ {

View File

@ -49,9 +49,9 @@
<ItemGroup> <ItemGroup>
<Compile Include="Beatmaps\ManiaBeatmapConverter.cs" /> <Compile Include="Beatmaps\ManiaBeatmapConverter.cs" />
<Compile Include="Beatmaps\ManiaBeatmapProcessor.cs" /> <Compile Include="Beatmaps\ManiaBeatmapProcessor.cs" />
<Compile Include="Judgements\ManiaJudgementInfo.cs" /> <Compile Include="Judgements\ManiaJudgement.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" /> <Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="ManiaScoreProcessor.cs" /> <Compile Include="Scoring\ManiaScoreProcessor.cs" />
<Compile Include="Objects\Drawable\DrawableNote.cs" /> <Compile Include="Objects\Drawable\DrawableNote.cs" />
<Compile Include="Objects\HoldNote.cs" /> <Compile Include="Objects\HoldNote.cs" />
<Compile Include="Objects\ManiaBaseHit.cs" /> <Compile Include="Objects\ManiaBaseHit.cs" />

View File

@ -44,11 +44,8 @@ namespace osu.Game.Modes.Osu.Beatmaps
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, Sample = original.Sample,
CurveObject = curveData, CurveObject = curveData,
Position = positionData?.Position ?? Vector2.Zero, Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false NewCombo = comboData?.NewCombo ?? false
}; };
} }
@ -60,7 +57,6 @@ namespace osu.Game.Modes.Osu.Beatmaps
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, Sample = original.Sample,
Position = new Vector2(512, 384) / 2, Position = new Vector2(512, 384) / 2,
EndTime = endTimeData.EndTime EndTime = endTimeData.EndTime
}; };
} }
@ -69,9 +65,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, Sample = original.Sample,
Position = positionData?.Position ?? Vector2.Zero, Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false NewCombo = comboData?.NewCombo ?? false
}; };
} }
@ -81,7 +75,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
if (endIndex == -1) if (endIndex == -1)
endIndex = hitObjects.Count - 1; endIndex = hitObjects.Count - 1;
int stackDistance = 3; const int stack_distance = 3;
float stackThreshold = DrawableOsuHitObject.TIME_PREEMPT * stackLeniency; float stackThreshold = DrawableOsuHitObject.TIME_PREEMPT * stackLeniency;
// Reset stacking inside the update range // Reset stacking inside the update range
@ -108,8 +102,8 @@ namespace osu.Game.Modes.Osu.Beatmaps
//We are no longer within stacking range of the next object. //We are no longer within stacking range of the next object.
break; break;
if (Vector2.Distance(stackBaseObject.Position, objectN.Position) < stackDistance || if (Vector2.Distance(stackBaseObject.Position, objectN.Position) < stack_distance ||
stackBaseObject is Slider && Vector2.Distance(stackBaseObject.EndPosition, objectN.Position) < stackDistance) stackBaseObject is Slider && Vector2.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
{ {
stackBaseIndex = n; stackBaseIndex = n;
@ -174,14 +168,14 @@ namespace osu.Game.Modes.Osu.Beatmaps
* o <- hitCircle has stack of -1 * o <- hitCircle has stack of -1
* o <- hitCircle has stack of -2 * o <- hitCircle has stack of -2
*/ */
if (objectN is Slider && Vector2.Distance(objectN.EndPosition, objectI.Position) < stackDistance) if (objectN is Slider && Vector2.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{ {
int offset = objectI.StackHeight - objectN.StackHeight + 1; int offset = objectI.StackHeight - objectN.StackHeight + 1;
for (int j = n + 1; j <= i; j++) for (int j = n + 1; j <= i; j++)
{ {
//For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above). //For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above).
OsuHitObject objectJ = hitObjects[j]; OsuHitObject objectJ = hitObjects[j];
if (Vector2.Distance(objectN.EndPosition, objectJ.Position) < stackDistance) if (Vector2.Distance(objectN.EndPosition, objectJ.Position) < stack_distance)
objectJ.StackHeight -= offset; objectJ.StackHeight -= offset;
} }
@ -190,7 +184,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
break; break;
} }
if (Vector2.Distance(objectN.Position, objectI.Position) < stackDistance) if (Vector2.Distance(objectN.Position, objectI.Position) < stack_distance)
{ {
//Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out. //Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out.
//NOTE: Sliders with start positions stacking are a special case that is also handled here. //NOTE: Sliders with start positions stacking are a special case that is also handled here.
@ -214,7 +208,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
//We are no longer within stacking range of the previous object. //We are no longer within stacking range of the previous object.
break; break;
if (Vector2.Distance(objectN.EndPosition, objectI.Position) < stackDistance) if (Vector2.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{ {
objectN.StackHeight = objectI.StackHeight + 1; objectN.StackHeight = objectI.StackHeight + 1;
objectI = objectN; objectI = objectN;

View File

@ -4,10 +4,11 @@
using OpenTK; using OpenTK;
using osu.Game.Modes.Judgements; using osu.Game.Modes.Judgements;
using osu.Game.Modes.Osu.Objects.Drawables; using osu.Game.Modes.Osu.Objects.Drawables;
using osu.Framework.Extensions;
namespace osu.Game.Modes.Osu.Judgements namespace osu.Game.Modes.Osu.Judgements
{ {
public class OsuJudgementInfo : JudgementInfo public class OsuJudgement : Judgement
{ {
/// <summary> /// <summary>
/// The positional hit offset. /// The positional hit offset.
@ -24,6 +25,10 @@ namespace osu.Game.Modes.Osu.Judgements
/// </summary> /// </summary>
public OsuScoreResult MaxScore = OsuScoreResult.Hit300; public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
public override string ResultString => Score.GetDescription();
public override string MaxResultString => MaxScore.GetDescription();
public int ScoreValue => scoreToInt(Score); public int ScoreValue => scoreToInt(Score);
public int MaxScoreValue => scoreToInt(MaxScore); public int MaxScoreValue => scoreToInt(MaxScore);

View File

@ -7,6 +7,7 @@ using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects;
using System; using System;
using System.Linq; using System.Linq;
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Osu.Mods namespace osu.Game.Modes.Osu.Mods
{ {

View File

@ -7,7 +7,6 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Modes.Osu.Objects.Drawables.Connections namespace osu.Game.Modes.Osu.Objects.Drawables.Connections
{ {

View File

@ -3,7 +3,6 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces; using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
using OpenTK; using OpenTK;
@ -13,37 +12,33 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{ {
private OsuHitObject osuObject;
public ApproachCircle ApproachCircle; public ApproachCircle ApproachCircle;
private CirclePiece circle; private readonly CirclePiece circle;
private RingPiece ring; private readonly RingPiece ring;
private FlashPiece flash; private readonly FlashPiece flash;
private ExplodePiece explode; private readonly ExplodePiece explode;
private NumberPiece number; private readonly NumberPiece number;
private GlowPiece glow; private readonly GlowPiece glow;
public DrawableHitCircle(OsuHitObject h) : base(h) public DrawableHitCircle(OsuHitObject h) : base(h)
{ {
Origin = Anchor.Centre; Origin = Anchor.Centre;
osuObject = h; Position = HitObject.StackedPosition;
Scale = new Vector2(HitObject.Scale);
Position = osuObject.StackedPosition;
Scale = new Vector2(osuObject.Scale);
Children = new Drawable[] Children = new Drawable[]
{ {
glow = new GlowPiece glow = new GlowPiece
{ {
Colour = osuObject.ComboColour Colour = AccentColour
}, },
circle = new CirclePiece circle = new CirclePiece
{ {
Colour = osuObject.ComboColour, Colour = AccentColour,
Hit = () => Hit = () =>
{ {
if (Judgement.Result.HasValue) return false; if (Judgement.Result != HitResult.None) return false;
Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value
UpdateJudgement(true); UpdateJudgement(true);
@ -58,11 +53,11 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
flash = new FlashPiece(), flash = new FlashPiece(),
explode = new ExplodePiece explode = new ExplodePiece
{ {
Colour = osuObject.ComboColour, Colour = AccentColour,
}, },
ApproachCircle = new ApproachCircle ApproachCircle = new ApproachCircle
{ {
Colour = osuObject.ComboColour, Colour = AccentColour,
} }
}; };
@ -115,8 +110,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ApproachCircle.FadeOut(); ApproachCircle.FadeOut();
double endTime = (osuObject as IHasEndTime)?.EndTime ?? osuObject.StartTime; double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
double duration = endTime - osuObject.StartTime; double duration = endTime - HitObject.StartTime;
glow.Delay(duration); glow.Delay(duration);
glow.FadeOut(400); glow.FadeOut(400);

View File

@ -7,18 +7,19 @@ using osu.Game.Modes.Osu.Judgements;
namespace osu.Game.Modes.Osu.Objects.Drawables namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject, OsuJudgementInfo> public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject, OsuJudgement>
{ {
public const float TIME_PREEMPT = 600; public const float TIME_PREEMPT = 600;
public const float TIME_FADEIN = 400; public const float TIME_FADEIN = 400;
public const float TIME_FADEOUT = 500; public const float TIME_FADEOUT = 500;
public DrawableOsuHitObject(OsuHitObject hitObject) protected DrawableOsuHitObject(OsuHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
AccentColour = HitObject.ComboColour;
} }
protected override OsuJudgementInfo CreateJudgementInfo() => new OsuJudgementInfo { MaxScore = OsuScoreResult.Hit300 }; protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.Hit300 };
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
using osu.Game.Modes.Judgements;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableOsuJudgement : DrawableJudgement<OsuJudgement>
{
public DrawableOsuJudgement(OsuJudgement judgement) : base(judgement)
{
}
protected override void LoadComplete()
{
if (Judgement.Result != HitResult.Miss)
JudgementText.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
base.LoadComplete();
}
}
}

View File

@ -13,18 +13,18 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{ {
private Slider slider; private readonly Slider slider;
private DrawableHitCircle initialCircle; private readonly DrawableHitCircle initialCircle;
private List<ISliderProgress> components = new List<ISliderProgress>(); private readonly List<ISliderProgress> components = new List<ISliderProgress>();
private Container<DrawableSliderTick> ticks; private readonly Container<DrawableSliderTick> ticks;
private SliderBody body; private readonly SliderBody body;
private SliderBall ball; private readonly SliderBall ball;
private SliderBouncer bouncer2; private readonly SliderBouncer bouncer2;
public DrawableSlider(Slider s) : base(s) public DrawableSlider(Slider s) : base(s)
{ {
@ -39,6 +39,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
body = new SliderBody(s) body = new SliderBody(s)
{ {
AccentColour = AccentColour,
Position = s.StackedPosition, Position = s.StackedPosition,
PathWidth = s.Scale * 64, PathWidth = s.Scale * 64,
}, },
@ -56,6 +57,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ball = new SliderBall(s) ball = new SliderBall(s)
{ {
Scale = new Vector2(s.Scale), Scale = new Vector2(s.Scale),
AccentColour = AccentColour
}, },
initialCircle = new DrawableHitCircle(new HitCircle initialCircle = new DrawableHitCircle(new HitCircle
{ {

View File

@ -7,7 +7,6 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Beatmaps.Samples; using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements; using osu.Game.Modes.Osu.Judgements;
@ -18,7 +17,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
public class DrawableSliderTick : DrawableOsuHitObject public class DrawableSliderTick : DrawableOsuHitObject
{ {
private SliderTick sliderTick; private readonly SliderTick sliderTick;
public double FadeInTime; public double FadeInTime;
public double FadeOutTime; public double FadeOutTime;
@ -27,7 +26,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
public override bool RemoveWhenNotAlive => false; public override bool RemoveWhenNotAlive => false;
protected override OsuJudgementInfo CreateJudgementInfo() => new OsuJudgementInfo { MaxScore = OsuScoreResult.SliderTick }; protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.SliderTick };
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick) public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
{ {
@ -48,7 +47,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = sliderTick.ComboColour, Colour = AccentColour,
Alpha = 0.3f, Alpha = 0.3f,
} }
}; };

View File

@ -4,7 +4,6 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces; using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
@ -15,12 +14,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
public class DrawableSpinner : DrawableOsuHitObject public class DrawableSpinner : DrawableOsuHitObject
{ {
private Spinner spinner; private readonly Spinner spinner;
private SpinnerDisc disc; private readonly SpinnerDisc disc;
private SpinnerBackground background; private readonly SpinnerBackground background;
private Container circleContainer; private readonly Container circleContainer;
private DrawableHitCircle circle; private readonly DrawableHitCircle circle;
public DrawableSpinner(Spinner s) : base(s) public DrawableSpinner(Spinner s) : base(s)
{ {
@ -48,7 +47,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Alpha = 0, Alpha = 0,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
DiscColour = s.ComboColour DiscColour = AccentColour
}, },
circleContainer = new Container circleContainer = new Container
{ {
@ -108,9 +107,9 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
private Vector2 scaleToCircle => circle.Scale * circle.DrawWidth / DrawWidth * 0.95f; private Vector2 scaleToCircle => circle.Scale * circle.DrawWidth / DrawWidth * 0.95f;
private float spinsPerMinuteNeeded = 100 + 5 * 15; //TODO: read per-map OD and place it on the 5 private const float spins_per_minute_needed = 100 + 5 * 15; //TODO: read per-map OD and place it on the 5
private float rotationsNeeded => (float)(spinsPerMinuteNeeded * (spinner.EndTime - spinner.StartTime) / 60000f); private float rotationsNeeded => (float)(spins_per_minute_needed * (spinner.EndTime - spinner.StartTime) / 60000f);
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / rotationsNeeded, 0, 1); public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / rotationsNeeded, 0, 1);

View File

@ -1,86 +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;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics.Sprites;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class HitExplosion : FillFlowContainer
{
private readonly OsuJudgementInfo judgement;
private SpriteText line1;
private SpriteText line2;
public HitExplosion(OsuJudgementInfo judgement, OsuHitObject h = null)
{
this.judgement = judgement;
AutoSizeAxes = Axes.Both;
Origin = Anchor.Centre;
Direction = FillDirection.Vertical;
Spacing = new Vector2(0, 2);
Position = (h?.StackedEndPosition ?? Vector2.Zero) + judgement.PositionOffset;
Children = new Drawable[]
{
line1 = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = judgement.Score.GetDescription(),
Font = @"Venera",
TextSize = 16,
},
line2 = new OsuSpriteText
{
Text = judgement.Combo.GetDescription(),
Font = @"Venera",
TextSize = 11,
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
if (judgement.Result == HitResult.Miss)
{
FadeInFromZero(60);
ScaleTo(1.6f);
ScaleTo(1, 100, EasingTypes.In);
MoveToOffset(new Vector2(0, 100), 800, EasingTypes.InQuint);
RotateTo(40, 800, EasingTypes.InQuint);
Delay(600);
FadeOut(200);
}
else
{
line1.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
line2.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
FadeOut(500);
}
switch (judgement.Result)
{
case HitResult.Miss:
Colour = Color4.Red;
break;
}
Expire();
}
}
}

View File

@ -11,7 +11,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class ApproachCircle : Container public class ApproachCircle : Container
{ {
private Sprite approachCircle; private readonly Sprite approachCircle;
public ApproachCircle() public ApproachCircle()
{ {

View File

@ -14,7 +14,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class CirclePiece : Container public class CirclePiece : Container
{ {
private Sprite disc; private readonly Sprite disc;
public Func<bool> Hit; public Func<bool> Hit;

View File

@ -11,7 +11,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class GlowPiece : Container public class GlowPiece : Container
{ {
private Sprite layer; private readonly Sprite layer;
public GlowPiece() public GlowPiece()
{ {

View File

@ -12,7 +12,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class NumberPiece : Container public class NumberPiece : Container
{ {
private SpriteText number; private readonly SpriteText number;
public string Text public string Text
{ {

View File

@ -4,7 +4,6 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -12,11 +11,27 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class SliderBall : CircularContainer, ISliderProgress public class SliderBall : CircularContainer, ISliderProgress
{ {
private readonly Slider slider;
private Box follow;
private const float width = 128; private const float width = 128;
private Color4 accentColour = Color4.Black;
/// <summary>
/// The colour that is used for the slider ball.
/// </summary>
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
if (ball != null)
ball.Colour = value;
}
}
private readonly Slider slider;
private readonly Box follow;
private readonly Box ball;
public SliderBall(Slider slider) public SliderBall(Slider slider)
{ {
this.slider = slider; this.slider = slider;
@ -49,9 +64,9 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
Alpha = 1, Alpha = 1,
Children = new[] Children = new[]
{ {
new Box ball = new Box
{ {
Colour = slider.ComboColour, Colour = AccentColour,
Alpha = 0.4f, Alpha = 0.4f,
Width = width, Width = width,
Height = width, Height = width,

View File

@ -13,27 +13,45 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Configuration; using osu.Game.Configuration;
using OpenTK; using OpenTK;
using OpenTK.Graphics.ES30; using OpenTK.Graphics.ES30;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class SliderBody : Container, ISliderProgress public class SliderBody : Container, ISliderProgress
{ {
private Path path; private readonly Path path;
private BufferedContainer container; private readonly BufferedContainer container;
public float PathWidth public float PathWidth
{ {
get { return path.PathWidth; } get { return path.PathWidth; }
set set { path.PathWidth = value; }
{
path.PathWidth = value;
}
} }
public double? SnakedStart { get; private set; } public double? SnakedStart { get; private set; }
public double? SnakedEnd { get; private set; } public double? SnakedEnd { get; private set; }
private Slider slider; private Color4 accentColour;
/// <summary>
/// Used to colour the path.
/// </summary>
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
if (LoadState == LoadState.Loaded)
Schedule(reloadTexture);
}
}
private int textureWidth => (int)PathWidth * 2;
private readonly Slider slider;
public SliderBody(Slider s) public SliderBody(Slider s)
{ {
slider = s; slider = s;
@ -82,7 +100,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
snakingIn = config.GetBindable<bool>(OsuConfig.SnakingInSliders); snakingIn = config.GetBindable<bool>(OsuConfig.SnakingInSliders);
snakingOut = config.GetBindable<bool>(OsuConfig.SnakingOutSliders); snakingOut = config.GetBindable<bool>(OsuConfig.SnakingOutSliders);
int textureWidth = (int)PathWidth * 2; reloadTexture();
}
private void reloadTexture()
{
var texture = new Texture(textureWidth, 1);
//initialise background //initialise background
var upload = new TextureUpload(textureWidth * 4); var upload = new TextureUpload(textureWidth * 4);
@ -110,19 +133,18 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
progress -= border_portion; progress -= border_portion;
bytes[i * 4] = (byte)(slider.ComboColour.R * 255); bytes[i * 4] = (byte)(AccentColour.R * 255);
bytes[i * 4 + 1] = (byte)(slider.ComboColour.G * 255); bytes[i * 4 + 1] = (byte)(AccentColour.G * 255);
bytes[i * 4 + 2] = (byte)(slider.ComboColour.B * 255); bytes[i * 4 + 2] = (byte)(AccentColour.B * 255);
bytes[i * 4 + 3] = (byte)((opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * (slider.ComboColour.A * 255)); bytes[i * 4 + 3] = (byte)((opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * (AccentColour.A * 255));
} }
} }
var texture = new Texture(textureWidth, 1);
texture.SetData(upload); texture.SetData(upload);
path.Texture = texture; path.Texture = texture;
} }
private List<Vector2> currentCurve = new List<Vector2>(); private readonly List<Vector2> currentCurve = new List<Vector2>();
private bool updateSnaking(double p0, double p1) private bool updateSnaking(double p0, double p1)
{ {
if (SnakedStart == p0 && SnakedEnd == p1) return false; if (SnakedStart == p0 && SnakedEnd == p1) return false;

View File

@ -11,7 +11,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
private readonly Slider slider; private readonly Slider slider;
private readonly bool isEnd; private readonly bool isEnd;
private TextAwesome icon; private readonly TextAwesome icon;
public SliderBouncer(Slider slider, bool isEnd) public SliderBouncer(Slider slider, bool isEnd)
{ {

View File

@ -36,7 +36,7 @@ namespace osu.Game.Modes.Osu.Objects
public float Scale { get; set; } = 1; public float Scale { get; set; } = 1;
public Color4 ComboColour { get; set; } public Color4 ComboColour { get; set; } = Color4.Gray;
public virtual bool NewCombo { get; set; } public virtual bool NewCombo { get; set; }
public int ComboIndex { get; set; } public int ComboIndex { get; set; }

View File

@ -47,11 +47,11 @@ namespace osu.Game.Modes.Osu.Objects
internal int MaxCombo = 1; internal int MaxCombo = 1;
private float scalingFactor; private readonly float scalingFactor;
private float lazySliderLength; private float lazySliderLength;
private Vector2 startPosition; private readonly Vector2 startPosition;
private Vector2 endPosition; private readonly Vector2 endPosition;
internal OsuHitObjectDifficulty(OsuHitObject baseHitObject) internal OsuHitObjectDifficulty(OsuHitObject baseHitObject)
{ {

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK; using OpenTK;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects;
@ -10,17 +9,19 @@ using osu.Game.Modes.Osu.Objects.Drawables;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Types; using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Replays;
namespace osu.Game.Modes.Osu namespace osu.Game.Modes.Osu
{ {
public class OsuAutoReplay : LegacyReplay public class OsuAutoReplay : Replay
{ {
private static readonly Vector2 spinner_centre = new Vector2(256, 192); private static readonly Vector2 spinner_centre = new Vector2(256, 192);
private const float spin_radius = 50; private const float spin_radius = 50;
private Beatmap<OsuHitObject> beatmap; private readonly Beatmap<OsuHitObject> beatmap;
public OsuAutoReplay(Beatmap<OsuHitObject> beatmap) public OsuAutoReplay(Beatmap<OsuHitObject> beatmap)
{ {
@ -29,19 +30,22 @@ namespace osu.Game.Modes.Osu
createAutoReplay(); createAutoReplay();
} }
internal class LegacyReplayFrameComparer : IComparer<LegacyReplayFrame> private class ReplayFrameComparer : IComparer<ReplayFrame>
{ {
public int Compare(LegacyReplayFrame f1, LegacyReplayFrame f2) public int Compare(ReplayFrame f1, ReplayFrame f2)
{ {
if (f1 == null) throw new NullReferenceException($@"{nameof(f1)} cannot be null");
if (f2 == null) throw new NullReferenceException($@"{nameof(f2)} cannot be null");
return f1.Time.CompareTo(f2.Time); return f1.Time.CompareTo(f2.Time);
} }
} }
private static IComparer<LegacyReplayFrame> replayFrameComparer = new LegacyReplayFrameComparer(); private static readonly IComparer<ReplayFrame> replay_frame_comparer = new ReplayFrameComparer();
private int findInsertionIndex(LegacyReplayFrame frame) private int findInsertionIndex(ReplayFrame frame)
{ {
int index = Frames.BinarySearch(frame, replayFrameComparer); int index = Frames.BinarySearch(frame, replay_frame_comparer);
if (index < 0) if (index < 0)
{ {
@ -59,7 +63,7 @@ namespace osu.Game.Modes.Osu
return index; return index;
} }
private void addFrameToReplay(LegacyReplayFrame frame) => Frames.Insert(findInsertionIndex(frame), frame); private void addFrameToReplay(ReplayFrame frame) => Frames.Insert(findInsertionIndex(frame), frame);
private static Vector2 circlePosition(double t, double radius) => new Vector2((float)(Math.Cos(t) * radius), (float)(Math.Sin(t) * radius)); private static Vector2 circlePosition(double t, double radius) => new Vector2((float)(Math.Cos(t) * radius), (float)(Math.Sin(t) * radius));
@ -74,9 +78,9 @@ namespace osu.Game.Modes.Osu
EasingTypes preferredEasing = DelayedMovements ? EasingTypes.InOutCubic : EasingTypes.Out; EasingTypes preferredEasing = DelayedMovements ? EasingTypes.InOutCubic : EasingTypes.Out;
addFrameToReplay(new LegacyReplayFrame(-100000, 256, 500, LegacyButtonState.None)); addFrameToReplay(new ReplayFrame(-100000, 256, 500, ReplayButtonState.None));
addFrameToReplay(new LegacyReplayFrame(beatmap.HitObjects[0].StartTime - 1500, 256, 500, LegacyButtonState.None)); addFrameToReplay(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1500, 256, 500, ReplayButtonState.None));
addFrameToReplay(new LegacyReplayFrame(beatmap.HitObjects[0].StartTime - 1000, 256, 192, LegacyButtonState.None)); addFrameToReplay(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1000, 256, 192, ReplayButtonState.None));
// We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps. // We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps.
float frameDelay = (float)applyModsToRate(1000.0 / 60.0); float frameDelay = (float)applyModsToRate(1000.0 / 60.0);
@ -106,18 +110,18 @@ namespace osu.Game.Modes.Osu
//Make the cursor stay at a hitObject as long as possible (mainly for autopilot). //Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
if (h.StartTime - h.HitWindowFor(OsuScoreResult.Miss) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50) if (h.StartTime - h.HitWindowFor(OsuScoreResult.Miss) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
{ {
if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new LegacyReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), last.EndPosition.X, last.EndPosition.Y, LegacyButtonState.None)); if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), last.EndPosition.X, last.EndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) addFrameToReplay(new LegacyReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.Position.X, h.Position.Y, LegacyButtonState.None)); if (!(h is Spinner)) addFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.Position.X, h.Position.Y, ReplayButtonState.None));
} }
else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50) else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
{ {
if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new LegacyReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), last.EndPosition.X, last.EndPosition.Y, LegacyButtonState.None)); if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), last.EndPosition.X, last.EndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) addFrameToReplay(new LegacyReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.Position.X, h.Position.Y, LegacyButtonState.None)); if (!(h is Spinner)) addFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.Position.X, h.Position.Y, ReplayButtonState.None));
} }
else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100) > endTime + h.HitWindowFor(OsuScoreResult.Hit100) + 50) else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100) > endTime + h.HitWindowFor(OsuScoreResult.Hit100) + 50)
{ {
if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new LegacyReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), last.EndPosition.X, last.EndPosition.Y, LegacyButtonState.None)); if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), last.EndPosition.X, last.EndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) addFrameToReplay(new LegacyReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.Position.X, h.Position.Y, LegacyButtonState.None)); if (!(h is Spinner)) addFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.Position.X, h.Position.Y, ReplayButtonState.None));
} }
} }
@ -173,13 +177,13 @@ namespace osu.Game.Modes.Osu
// Do some nice easing for cursor movements // Do some nice easing for cursor movements
if (Frames.Count > 0) if (Frames.Count > 0)
{ {
LegacyReplayFrame lastFrame = Frames[Frames.Count - 1]; ReplayFrame lastFrame = Frames[Frames.Count - 1];
// Wait until Auto could "see and react" to the next note. // Wait until Auto could "see and react" to the next note.
double waitTime = h.StartTime - Math.Max(0.0, DrawableOsuHitObject.TIME_PREEMPT - reactionTime); double waitTime = h.StartTime - Math.Max(0.0, DrawableOsuHitObject.TIME_PREEMPT - reactionTime);
if (waitTime > lastFrame.Time) if (waitTime > lastFrame.Time)
{ {
lastFrame = new LegacyReplayFrame(waitTime, lastFrame.MouseX, lastFrame.MouseY, lastFrame.ButtonState); lastFrame = new ReplayFrame(waitTime, lastFrame.MouseX, lastFrame.MouseY, lastFrame.ButtonState);
addFrameToReplay(lastFrame); addFrameToReplay(lastFrame);
} }
@ -196,7 +200,7 @@ namespace osu.Game.Modes.Osu
for (double time = lastFrame.Time + frameDelay; time < h.StartTime; time += frameDelay) for (double time = lastFrame.Time + frameDelay; time < h.StartTime; time += frameDelay)
{ {
Vector2 currentPosition = Interpolation.ValueAt(time, lastPosition, targetPosition, lastFrame.Time, h.StartTime, easing); Vector2 currentPosition = Interpolation.ValueAt(time, lastPosition, targetPosition, lastFrame.Time, h.StartTime, easing);
addFrameToReplay(new LegacyReplayFrame((int)time, currentPosition.X, currentPosition.Y, lastFrame.ButtonState)); addFrameToReplay(new ReplayFrame((int)time, currentPosition.X, currentPosition.Y, lastFrame.ButtonState));
} }
buttonIndex = 0; buttonIndex = 0;
@ -207,12 +211,12 @@ namespace osu.Game.Modes.Osu
} }
} }
LegacyButtonState button = buttonIndex % 2 == 0 ? LegacyButtonState.Left1 : LegacyButtonState.Right1; ReplayButtonState button = buttonIndex % 2 == 0 ? ReplayButtonState.Left1 : ReplayButtonState.Right1;
double hEndTime = (h as IHasEndTime)?.EndTime ?? h.StartTime; double hEndTime = (h as IHasEndTime)?.EndTime ?? h.StartTime;
LegacyReplayFrame newFrame = new LegacyReplayFrame(h.StartTime, targetPosition.X, targetPosition.Y, button); ReplayFrame newFrame = new ReplayFrame(h.StartTime, targetPosition.X, targetPosition.Y, button);
LegacyReplayFrame endFrame = new LegacyReplayFrame(hEndTime + endDelay, h.EndPosition.X, h.EndPosition.Y, LegacyButtonState.None); ReplayFrame endFrame = new ReplayFrame(hEndTime + endDelay, h.EndPosition.X, h.EndPosition.Y, ReplayButtonState.None);
// Decrement because we want the previous frame, not the next one // Decrement because we want the previous frame, not the next one
int index = findInsertionIndex(newFrame) - 1; int index = findInsertionIndex(newFrame) - 1;
@ -220,19 +224,19 @@ namespace osu.Game.Modes.Osu
// Do we have a previous frame? No need to check for < replay.Count since we decremented! // Do we have a previous frame? No need to check for < replay.Count since we decremented!
if (index >= 0) if (index >= 0)
{ {
LegacyReplayFrame previousFrame = Frames[index]; ReplayFrame previousFrame = Frames[index];
var previousButton = previousFrame.ButtonState; var previousButton = previousFrame.ButtonState;
// If a button is already held, then we simply alternate // If a button is already held, then we simply alternate
if (previousButton != LegacyButtonState.None) if (previousButton != ReplayButtonState.None)
{ {
Debug.Assert(previousButton != (LegacyButtonState.Left1 | LegacyButtonState.Right1)); Debug.Assert(previousButton != (ReplayButtonState.Left1 | ReplayButtonState.Right1));
// Force alternation if we have the same button. Otherwise we can just keep the naturally to us assigned button. // Force alternation if we have the same button. Otherwise we can just keep the naturally to us assigned button.
if (previousButton == button) if (previousButton == button)
{ {
button = (LegacyButtonState.Left1 | LegacyButtonState.Right1) & ~button; button = (ReplayButtonState.Left1 | ReplayButtonState.Right1) & ~button;
newFrame.SetButtonStates(button); newFrame.ButtonState = button;
} }
// We always follow the most recent slider / spinner, so remove any other frames that occur while it exists. // We always follow the most recent slider / spinner, so remove any other frames that occur while it exists.
@ -246,7 +250,7 @@ namespace osu.Game.Modes.Osu
{ {
// Don't affect frames which stop pressing a button! // Don't affect frames which stop pressing a button!
if (j < Frames.Count - 1 || Frames[j].ButtonState == previousButton) if (j < Frames.Count - 1 || Frames[j].ButtonState == previousButton)
Frames[j].SetButtonStates(button); Frames[j].ButtonState = button;
} }
} }
} }
@ -270,13 +274,13 @@ namespace osu.Game.Modes.Osu
t = applyModsToTime(j - h.StartTime) * spinnerDirection; t = applyModsToTime(j - h.StartTime) * spinnerDirection;
Vector2 pos = spinner_centre + circlePosition(t / 20 + angle, spin_radius); Vector2 pos = spinner_centre + circlePosition(t / 20 + angle, spin_radius);
addFrameToReplay(new LegacyReplayFrame((int)j, pos.X, pos.Y, button)); addFrameToReplay(new ReplayFrame((int)j, pos.X, pos.Y, button));
} }
t = applyModsToTime(s.EndTime - h.StartTime) * spinnerDirection; t = applyModsToTime(s.EndTime - h.StartTime) * spinnerDirection;
Vector2 endPosition = spinner_centre + circlePosition(t / 20 + angle, spin_radius); Vector2 endPosition = spinner_centre + circlePosition(t / 20 + angle, spin_radius);
addFrameToReplay(new LegacyReplayFrame(s.EndTime, endPosition.X, endPosition.Y, button)); addFrameToReplay(new ReplayFrame(s.EndTime, endPosition.X, endPosition.Y, button));
endFrame.MouseX = endPosition.X; endFrame.MouseX = endPosition.X;
endFrame.MouseY = endPosition.Y; endFrame.MouseY = endPosition.Y;
@ -288,10 +292,10 @@ namespace osu.Game.Modes.Osu
for (double j = frameDelay; j < s.Duration; j += frameDelay) for (double j = frameDelay; j < s.Duration; j += frameDelay)
{ {
Vector2 pos = s.PositionAt(j / s.Duration); Vector2 pos = s.PositionAt(j / s.Duration);
addFrameToReplay(new LegacyReplayFrame(h.StartTime + j, pos.X, pos.Y, button)); addFrameToReplay(new ReplayFrame(h.StartTime + j, pos.X, pos.Y, button));
} }
addFrameToReplay(new LegacyReplayFrame(s.EndTime, s.EndPosition.X, s.EndPosition.Y, button)); addFrameToReplay(new ReplayFrame(s.EndTime, s.EndPosition.X, s.EndPosition.Y, button));
} }
// We only want to let go of our button if we are at the end of the current replay. Otherwise something is still going on after us so we need to keep the button pressed! // We only want to let go of our button if we are at the end of the current replay. Otherwise something is still going on after us so we need to keep the button pressed!

View File

@ -12,6 +12,8 @@ using osu.Game.Modes.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Modes.Osu.Scoring;
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Osu namespace osu.Game.Modes.Osu
{ {

View File

@ -1,7 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Osu using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Osu.Scoring
{ {
internal class OsuScore : Score internal class OsuScore : Score
{ {

View File

@ -4,17 +4,18 @@
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements; using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
namespace osu.Game.Modes.Osu namespace osu.Game.Modes.Osu.Scoring
{ {
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgementInfo> internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
{ {
public OsuScoreProcessor() public OsuScoreProcessor()
{ {
} }
public OsuScoreProcessor(HitRenderer<OsuHitObject, OsuJudgementInfo> hitRenderer) public OsuScoreProcessor(HitRenderer<OsuHitObject, OsuJudgement> hitRenderer)
: base(hitRenderer) : base(hitRenderer)
{ {
} }
@ -27,7 +28,7 @@ namespace osu.Game.Modes.Osu
Accuracy.Value = 1; Accuracy.Value = 1;
} }
protected override void UpdateCalculations(OsuJudgementInfo judgement) protected override void OnNewJudgement(OsuJudgement judgement)
{ {
if (judgement != null) if (judgement != null)
{ {
@ -47,9 +48,8 @@ namespace osu.Game.Modes.Osu
int score = 0; int score = 0;
int maxScore = 0; int maxScore = 0;
foreach (var judgementInfo in Judgements) foreach (var j in Judgements)
{ {
var j = judgementInfo;
score += j.ScoreValue; score += j.ScoreValue;
maxScore += j.MaxScoreValue; maxScore += j.MaxScoreValue;
} }

View File

@ -7,12 +7,14 @@ using osu.Game.Modes.Osu.Beatmaps;
using osu.Game.Modes.Osu.Judgements; using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Osu.Objects.Drawables; using osu.Game.Modes.Osu.Objects.Drawables;
using osu.Game.Modes.Osu.Scoring;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Game.Modes.Osu.UI namespace osu.Game.Modes.Osu.UI
{ {
public class OsuHitRenderer : HitRenderer<OsuHitObject, OsuJudgementInfo> public class OsuHitRenderer : HitRenderer<OsuHitObject, OsuJudgement>
{ {
public OsuHitRenderer(WorkingBeatmap beatmap) public OsuHitRenderer(WorkingBeatmap beatmap)
: base(beatmap) : base(beatmap)
@ -25,11 +27,11 @@ namespace osu.Game.Modes.Osu.UI
protected override IBeatmapProcessor<OsuHitObject> CreateBeatmapProcessor() => new OsuBeatmapProcessor(); protected override IBeatmapProcessor<OsuHitObject> CreateBeatmapProcessor() => new OsuBeatmapProcessor();
protected override Playfield<OsuHitObject, OsuJudgementInfo> CreatePlayfield() => new OsuPlayfield(); protected override Playfield<OsuHitObject, OsuJudgement> CreatePlayfield() => new OsuPlayfield();
protected override KeyConversionInputManager CreateKeyConversionInputManager() => new OsuKeyConversionInputManager(); protected override KeyConversionInputManager CreateKeyConversionInputManager() => new OsuKeyConversionInputManager();
protected override DrawableHitObject<OsuHitObject, OsuJudgementInfo> GetVisualRepresentation(OsuHitObject h) protected override DrawableHitObject<OsuHitObject, OsuJudgement> GetVisualRepresentation(OsuHitObject h)
{ {
var circle = h as HitCircle; var circle = h as HitCircle;
if (circle != null) if (circle != null)

View File

@ -15,11 +15,11 @@ using osu.Game.Modes.Osu.Judgements;
namespace osu.Game.Modes.Osu.UI namespace osu.Game.Modes.Osu.UI
{ {
public class OsuPlayfield : Playfield<OsuHitObject, OsuJudgementInfo> public class OsuPlayfield : Playfield<OsuHitObject, OsuJudgement>
{ {
private Container approachCircles; private readonly Container approachCircles;
private Container judgementLayer; private readonly Container judgementLayer;
private ConnectionRenderer<OsuHitObject> connectionLayer; private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
public override Vector2 Size public override Vector2 Size
{ {
@ -65,7 +65,7 @@ namespace osu.Game.Modes.Osu.UI
AddInternal(new GameplayCursor()); AddInternal(new GameplayCursor());
} }
public override void Add(DrawableHitObject<OsuHitObject, OsuJudgementInfo> h) public override void Add(DrawableHitObject<OsuHitObject, OsuJudgement> h)
{ {
h.Depth = (float)h.HitObject.StartTime; h.Depth = (float)h.HitObject.StartTime;
@ -83,9 +83,13 @@ namespace osu.Game.Modes.Osu.UI
.OrderBy(h => h.StartTime); .OrderBy(h => h.StartTime);
} }
public override void OnJudgement(DrawableHitObject<OsuHitObject, OsuJudgementInfo> judgedObject) public override void OnJudgement(DrawableHitObject<OsuHitObject, OsuJudgement> judgedObject)
{ {
HitExplosion explosion = new HitExplosion(judgedObject.Judgement, judgedObject.HitObject); DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgedObject.Judgement)
{
Origin = Anchor.Centre,
Position = judgedObject.HitObject.StackedEndPosition + judgedObject.Judgement.PositionOffset
};
judgementLayer.Add(explosion); judgementLayer.Add(explosion);
} }

View File

@ -48,7 +48,7 @@
<Compile Include="Objects\Drawables\DrawableOsuHitObject.cs" /> <Compile Include="Objects\Drawables\DrawableOsuHitObject.cs" />
<Compile Include="Objects\Drawables\Connections\ConnectionRenderer.cs" /> <Compile Include="Objects\Drawables\Connections\ConnectionRenderer.cs" />
<Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" /> <Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
<Compile Include="Judgements\OsuJudgementInfo.cs" /> <Compile Include="Judgements\OsuJudgement.cs" />
<Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" /> <Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
<Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" /> <Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
<Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" /> <Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
@ -58,7 +58,7 @@
<Compile Include="Objects\Drawables\Pieces\ExplodePiece.cs" /> <Compile Include="Objects\Drawables\Pieces\ExplodePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\FlashPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\FlashPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" />
<Compile Include="Objects\Drawables\HitExplosion.cs" /> <Compile Include="Objects\Drawables\DrawableOsuJudgement.cs" />
<Compile Include="Objects\Drawables\Pieces\NumberPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\NumberPiece.cs" />
<Compile Include="Objects\Drawables\DrawableSliderTick.cs" /> <Compile Include="Objects\Drawables\DrawableSliderTick.cs" />
<Compile Include="Objects\Drawables\Pieces\RingPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\RingPiece.cs" />
@ -72,8 +72,8 @@
<Compile Include="OsuAutoReplay.cs" /> <Compile Include="OsuAutoReplay.cs" />
<Compile Include="OsuDifficultyCalculator.cs" /> <Compile Include="OsuDifficultyCalculator.cs" />
<Compile Include="OsuKeyConversionInputManager.cs" /> <Compile Include="OsuKeyConversionInputManager.cs" />
<Compile Include="OsuScore.cs" /> <Compile Include="Scoring\OsuScore.cs" />
<Compile Include="OsuScoreProcessor.cs" /> <Compile Include="Scoring\OsuScoreProcessor.cs" />
<Compile Include="UI\OsuHitRenderer.cs" /> <Compile Include="UI\OsuHitRenderer.cs" />
<Compile Include="UI\OsuPlayfield.cs" /> <Compile Include="UI\OsuPlayfield.cs" />
<Compile Include="OsuRuleset.cs" /> <Compile Include="OsuRuleset.cs" />

View File

@ -2,18 +2,95 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; 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 osu.Game.Modes.Taiko.Objects;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Modes.Taiko.Beatmaps namespace osu.Game.Modes.Taiko.Beatmaps
{ {
internal class TaikoBeatmapConverter : IBeatmapConverter<TaikoHitObject> internal class TaikoBeatmapConverter : IBeatmapConverter<TaikoHitObject>
{ {
private const float legacy_velocity_scale = 1.4f;
private const float bash_convert_factor = 1.65f;
public Beatmap<TaikoHitObject> Convert(Beatmap original) public Beatmap<TaikoHitObject> Convert(Beatmap original)
{ {
if (original is LegacyBeatmap)
original.TimingInfo.ControlPoints.ForEach(c => c.VelocityAdjustment /= legacy_velocity_scale);
return new Beatmap<TaikoHitObject>(original) return new Beatmap<TaikoHitObject>(original)
{ {
HitObjects = new List<TaikoHitObject>() // Todo: Implement HitObjects = convertHitObjects(original.HitObjects)
};
}
private List<TaikoHitObject> convertHitObjects(List<HitObject> hitObjects)
{
return hitObjects.Select(convertHitObject).ToList();
}
private TaikoHitObject convertHitObject(HitObject original)
{
// Check if this HitObject is already a TaikoHitObject, and return it if so
TaikoHitObject originalTaiko = original as TaikoHitObject;
if (originalTaiko != null)
return originalTaiko;
IHasDistance distanceData = original as IHasDistance;
IHasRepeats repeatsData = original as IHasRepeats;
IHasEndTime endTimeData = original as IHasEndTime;
// Old osu! used hit sounding to determine various hit type information
SampleType sample = original.Sample?.Type ?? SampleType.None;
bool strong = (sample & SampleType.Finish) > 0;
if (distanceData != null)
{
return new DrumRoll
{
StartTime = original.StartTime,
Sample = original.Sample,
IsStrong = strong,
Distance = distanceData.Distance * (repeatsData?.RepeatCount ?? 1)
};
}
if (endTimeData != null)
{
// We compute the end time manually to add in the Bash convert factor
return new Swell
{
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
{
StartTime = original.StartTime,
Sample = original.Sample,
IsStrong = strong
};
}
return new RimHit
{
StartTime = original.StartTime,
Sample = original.Sample,
IsStrong = strong,
}; };
} }
} }

View File

@ -0,0 +1,34 @@
// 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.Modes.Taiko.Judgements
{
public class TaikoDrumRollTickJudgement : TaikoJudgement
{
/// <summary>
/// Drum roll ticks don't display judgement text.
/// </summary>
public override string ResultString => string.Empty;
/// <summary>
/// Drum roll ticks don't display judgement text.
/// </summary>
public override string MaxResultString => string.Empty;
protected override int NumericResultForScore(TaikoHitResult result)
{
switch (result)
{
default:
return 0;
case TaikoHitResult.Great:
return 200;
}
}
protected override int NumericResultForAccuracy(TaikoHitResult result)
{
return 0;
}
}
}

View File

@ -1,11 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
namespace osu.Game.Modes.Taiko.Judgements namespace osu.Game.Modes.Taiko.Judgements
{ {
public enum TaikoHitResult public enum TaikoHitResult
{ {
[Description("GOOD")]
Good, Good,
[Description("GREAT")]
Great Great
} }
} }

View File

@ -2,52 +2,57 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Judgements; using osu.Game.Modes.Judgements;
using osu.Framework.Extensions;
namespace osu.Game.Modes.Taiko.Judgements namespace osu.Game.Modes.Taiko.Judgements
{ {
public class TaikoJudgementInfo : JudgementInfo public class TaikoJudgement : Judgement
{ {
/// <summary> /// <summary>
/// The maximum score value. /// The maximum result.
/// </summary> /// </summary>
public const TaikoHitResult MAX_HIT_RESULT = TaikoHitResult.Great; public const TaikoHitResult MAX_HIT_RESULT = TaikoHitResult.Great;
/// <summary> /// <summary>
/// The score value. /// The result.
/// </summary> /// </summary>
public TaikoHitResult TaikoResult; public TaikoHitResult TaikoResult;
/// <summary> /// <summary>
/// The score value for the combo portion of the score. /// The result value for the combo portion of the score.
/// </summary> /// </summary>
public int ScoreValue => NumericResultForScore(TaikoResult); public int ResultValueForScore => NumericResultForScore(TaikoResult);
/// <summary> /// <summary>
/// The score value for the accuracy portion of the score. /// The result value for the accuracy portion of the score.
/// </summary> /// </summary>
public int AccuracyScoreValue => NumericResultForAccuracy(TaikoResult); public int ResultValueForAccuracy => NumericResultForAccuracy(TaikoResult);
/// <summary> /// <summary>
/// The maximum score value for the combo portion of the score. /// The maximum result value for the combo portion of the score.
/// </summary> /// </summary>
public int MaxScoreValue => NumericResultForScore(MAX_HIT_RESULT); public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
/// <summary> /// <summary>
/// The maximum score value for the accuracy portion of the score. /// The maximum result value for the accuracy portion of the score.
/// </summary> /// </summary>
public int MaxAccuracyScoreValue => NumericResultForAccuracy(MAX_HIT_RESULT); public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
public override string ResultString => TaikoResult.GetDescription();
public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
/// <summary> /// <summary>
/// Whether this Judgement has a secondary hit in the case of finishers. /// Whether this Judgement has a secondary hit in the case of finishers.
/// </summary> /// </summary>
public bool SecondHit; public virtual bool SecondHit { get; set; }
/// <summary> /// <summary>
/// Computes the numeric score value for the combo portion of the score. /// Computes the numeric result value for the combo portion of the score.
/// For the accuracy portion of the score (including accuracy percentage), see <see cref="NumericResultForAccuracy(TaikoHitResult)"/>. /// For the accuracy portion of the score (including accuracy percentage), see <see cref="NumericResultForAccuracy(TaikoHitResult)"/>.
/// </summary> /// </summary>
/// <param name="result">The result to compute the score value for.</param> /// <param name="result">The result to compute the value for.</param>
/// <returns>The numeric score value.</returns> /// <returns>The numeric result value.</returns>
protected virtual int NumericResultForScore(TaikoHitResult result) protected virtual int NumericResultForScore(TaikoHitResult result)
{ {
switch (result) switch (result)
@ -62,11 +67,11 @@ namespace osu.Game.Modes.Taiko.Judgements
} }
/// <summary> /// <summary>
/// Computes the numeric score value for the accuracy portion of the score. /// Computes the numeric result value for the accuracy portion of the score.
/// For the combo portion of the score, see <see cref="NumericResultForScore(TaikoHitResult)"/>. /// For the combo portion of the score, see <see cref="NumericResultForScore(TaikoHitResult)"/>.
/// </summary> /// </summary>
/// <param name="result">The result to compute the score value for.</param> /// <param name="result">The result to compute the value for.</param>
/// <returns>The numeric score value.</returns> /// <returns>The numeric result value.</returns>
protected virtual int NumericResultForAccuracy(TaikoHitResult result) protected virtual int NumericResultForAccuracy(TaikoHitResult result)
{ {
switch (result) switch (result)

View File

@ -0,0 +1,25 @@
// 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.Judgements;
namespace osu.Game.Modes.Taiko.Judgements
{
public class TaikoStrongHitJudgement : TaikoJudgement, IPartialJudgement
{
public bool Changed { get; set; }
public override bool SecondHit
{
get { return base.SecondHit; }
set
{
if (base.SecondHit == value)
return;
base.SecondHit = value;
Changed = true;
}
}
}
}

View File

@ -1,7 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Mods; using osu.Game.Modes.Mods;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.Replays;
using osu.Game.Users;
namespace osu.Game.Modes.Taiko.Mods namespace osu.Game.Modes.Taiko.Mods
{ {
@ -61,4 +66,13 @@ namespace osu.Game.Modes.Taiko.Mods
{ {
} }
public class TaikoModAutoplay : ModAutoplay<TaikoHitObject>
{
protected override Score CreateReplayScore(Beatmap<TaikoHitObject> beatmap) => new Score
{
User = new User { Username = "mekkadosu!" },
Replay = new TaikoAutoReplay(beatmap)
};
}
} }

View File

@ -0,0 +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.Modes.Taiko.Objects
{
public class CentreHit : Hit
{
}
}

View File

@ -0,0 +1,35 @@
// 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;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
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()
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.PinkDarker;
}
}
}

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.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

@ -0,0 +1,53 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Input;
using osu.Game.Modes.Taiko.Judgements;
using System;
using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableDrumRollTick : DrawableTaikoHitObject
{
private readonly DrumRollTick tick;
public DrawableDrumRollTick(DrumRollTick tick)
: base(tick)
{
this.tick = tick;
}
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement();
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
if (Judgement.TimeOffset > tick.HitWindow)
Judgement.Result = HitResult.Miss;
return;
}
if (Math.Abs(Judgement.TimeOffset) < tick.HitWindow)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
}
}
protected override void UpdateState(ArmedState state)
{
}
protected override void UpdateScrollPosition(double time)
{
// Drum roll ticks shouldn't move
}
protected override bool HandleKeyPress(Key key)
{
return Judgement.Result == HitResult.None && UpdateJudgement(true);
}
}
}

View File

@ -0,0 +1,104 @@
// 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;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public abstract class DrawableHit : DrawableTaikoHitObject
{
/// <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)
Judgement.Result = HitResult.Miss;
return;
}
double hitOffset = Math.Abs(Judgement.TimeOffset);
if (hitOffset > hit.HitWindowMiss)
return;
if (!validKeyPressed)
Judgement.Result = HitResult.Miss;
else if (hitOffset < hit.HitWindowGood)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = hitOffset < hit.HitWindowGreat ? TaikoHitResult.Great : TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
}
protected override bool HandleKeyPress(Key key)
{
if (Judgement.Result != HitResult.None)
return false;
validKeyPressed = HitKeys.Contains(key);
return UpdateJudgement(true);
}
protected override void UpdateState(ArmedState state)
{
Delay(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true);
switch (State)
{
case ArmedState.Idle:
Delay(hit.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);
break;
}
Expire();
}
}
}

View File

@ -0,0 +1,35 @@
// 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 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()
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.BlueDarker;
}
}
}

View File

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

@ -0,0 +1,89 @@
// 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;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public abstract class DrawableStrongHit : DrawableHit
{
/// <summary>
/// The lenience for the second key press.
/// This does not adjust by map difficulty in ScoreV2 yet.
/// </summary>
private const double second_hit_window = 30;
private double firstHitTime;
private bool firstKeyHeld;
private Key firstHitKey;
protected DrawableStrongHit(Hit hit)
: base(hit)
{
}
protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement();
protected override void CheckJudgement(bool userTriggered)
{
if (Judgement.Result == HitResult.None)
{
base.CheckJudgement(userTriggered);
return;
}
if (!userTriggered)
return;
// If we get here, we're assured that the key pressed is the correct secondary key
if (Math.Abs(firstHitTime - Time.Current) < second_hit_window)
Judgement.SecondHit = true;
}
protected override bool HandleKeyPress(Key key)
{
// Check if we've handled the first key
if (Judgement.Result == HitResult.None)
{
// First key hasn't been handled yet, attempt to handle it
bool handled = base.HandleKeyPress(key);
if (handled)
{
firstHitTime = Time.Current;
firstHitKey = key;
}
return handled;
}
// If we've already hit the second key, don't handle this object any further
if (Judgement.SecondHit)
return false;
// Don't handle represses of the first key
if (firstHitKey == key)
return false;
// Don't handle invalid hit key presses
if (!HitKeys.Contains(key))
return false;
// Assume the intention was to hit the strong hit with both keys only if the first key is still being held down
return firstKeyHeld && UpdateJudgement(true);
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
firstKeyHeld = state.Keyboard.Keys.Contains(firstHitKey);
return base.OnKeyDown(state, args);
}
}
}

View File

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

@ -0,0 +1,242 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
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;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableSwell : DrawableTaikoHitObject
{
/// <summary>
/// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime.
/// This is only ever invoked once.
/// </summary>
public event Action OnStart;
private const float target_ring_thick_border = 1.4f;
private const float target_ring_thin_border = 1f;
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;
private readonly CirclePiece circlePiece;
private readonly Key[] rimKeys = { Key.D, Key.K };
private readonly Key[] centreKeys = { Key.F, Key.J };
private Key[] lastKeySet;
/// <summary>
/// The amount of times the user has hit this swell.
/// </summary>
private int userHits;
private bool hasStarted;
private readonly SwellSymbolPiece symbol;
public DrawableSwell(Swell swell)
: base(swell)
{
this.swell = swell;
Children = new Framework.Graphics.Drawable[]
{
bodyContainer = new Container
{
Children = new Framework.Graphics.Drawable[]
{
expandingRing = new CircularContainer
{
Name = "Expanding ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Alpha = 0,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
BlendingMode = BlendingMode.Additive,
Masking = true,
Children = new []
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = inner_ring_alpha,
}
}
},
targetRing = new CircularContainer
{
Name = "Target ring (thick border)",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
Masking = true,
BorderThickness = target_ring_thick_border,
BlendingMode = BlendingMode.Additive,
Children = new Framework.Graphics.Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
},
new CircularContainer
{
Name = "Target ring (thin border)",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderThickness = target_ring_thin_border,
BorderColour = Color4.White,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
}
}
},
circlePiece = new CirclePiece
{
Children = new []
{
symbol = new SwellSymbolPiece()
}
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
circlePiece.AccentColour = colours.YellowDark;
expandingRing.Colour = colours.YellowLight;
targetRing.BorderColour = colours.YellowDark.Opacity(0.25f);
}
protected override void CheckJudgement(bool userTriggered)
{
if (userTriggered)
{
userHits++;
var completion = (float)userHits / swell.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);
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);
if (userHits == swell.RequiredHits)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
}
}
else
{
if (Judgement.TimeOffset < 0)
return;
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
if (userHits > swell.RequiredHits / 2)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Good;
}
else
Judgement.Result = HitResult.Miss;
}
}
protected override void UpdateState(ArmedState state)
{
const float preempt = 100;
Delay(HitObject.StartTime - Time.Current - preempt, true);
targetRing.ScaleTo(target_ring_scale, preempt * 4, EasingTypes.OutQuint);
Delay(preempt, true);
Delay(Judgement.TimeOffset + swell.Duration, true);
const float out_transition_time = 300;
switch (state)
{
case ArmedState.Hit:
bodyContainer.ScaleTo(1.4f, out_transition_time);
break;
}
FadeOut(out_transition_time, EasingTypes.Out);
Expire();
}
protected override void UpdateScrollPosition(double time)
{
// Make the swell stop at the hit target
double t = Math.Min(HitObject.StartTime, time);
if (t == HitObject.StartTime && !hasStarted)
{
OnStart?.Invoke();
hasStarted = true;
}
base.UpdateScrollPosition(t);
}
protected override bool HandleKeyPress(Key key)
{
if (Judgement.Result != HitResult.None)
return false;
// Don't handle keys before the swell starts
if (Time.Current < HitObject.StartTime)
return false;
// Find the keyset which this key corresponds to
var keySet = rimKeys.Contains(key) ? rimKeys : centreKeys;
// Ensure alternating keysets
if (keySet == lastKeySet)
return false;
lastKeySet = keySet;
UpdateJudgement(true);
return true;
}
}
}

View File

@ -1,39 +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.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Transforms;
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
internal class DrawableTaikoHit : Sprite
{
private TaikoHitObject h;
public DrawableTaikoHit(TaikoHitObject h)
{
this.h = h;
Origin = Anchor.Centre;
Scale = new Vector2(0.2f);
RelativePositionAxes = Axes.Both;
Position = new Vector2(1.1f, 0.5f);
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Texture = textures.Get(@"Menu/logo");
double duration = 0;
Transforms.Add(new TransformPositionX { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = 1.1f, EndValue = 0.1f });
Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
Expire(true);
}
}
}

View File

@ -0,0 +1,70 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Input;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using System.Collections.Generic;
using osu.Framework.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public abstract class DrawableTaikoHitObject : DrawableHitObject<TaikoHitObject, TaikoJudgement>
{
/// <summary>
/// A list of keys which this hit object will accept. These are the standard Taiko keys for now.
/// These should be moved to bindings later.
/// </summary>
private readonly List<Key> validKeys = new List<Key>(new[] { Key.D, Key.F, Key.J, Key.K });
protected DrawableTaikoHitObject(TaikoHitObject hitObject)
: base(hitObject)
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
RelativePositionAxes = Axes.X;
}
protected override void LoadComplete()
{
LifetimeStart = HitObject.StartTime - HitObject.PreEmpt * 2;
base.LoadComplete();
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
/// <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 override void Update()
{
UpdateScrollPosition(Time.Current);
}
protected virtual bool HandleKeyPress(Key key) => false;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
// Make sure we don't handle held-down keys
if (args.Repeat)
return false;
// Check if we've pressed a valid taiko key
if (!validKeys.Contains(args.Key))
return false;
// Handle it!
return HandleKeyPress(args.Key);
}
}
}

View File

@ -0,0 +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.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
{
/// <summary>
/// The symbol used for centre hit pieces.
/// </summary>
public class CentreHitSymbolPiece : CircularContainer
{
public CentreHitSymbolPiece()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Size = new Vector2(CirclePiece.SYMBOL_INNER_SIZE);
Masking = true;
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both
}
};
}
}
}

View File

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

@ -0,0 +1,36 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawable.Pieces
{
/// <summary>
/// The symbol used for rim hit pieces.
/// </summary>
public class RimHitSymbolPiece : CircularContainer
{
public RimHitSymbolPiece()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Size = new Vector2(CirclePiece.SYMBOL_SIZE);
BorderThickness = CirclePiece.SYMBOL_BORDER;
BorderColour = Color4.White;
Masking = true;
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
};
}
}
}

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