1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-21 03:53:21 +08:00
This commit is contained in:
DrabWeb 2017-04-09 04:04:13 -03:00
commit 963cd09bd0
280 changed files with 4841 additions and 2311 deletions

View File

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

@ -1 +1 @@
Subproject commit 51737ec1320b4ea9dce4978f24e1d77a28f0a98e
Subproject commit 45e75163b272b7aa023afec7801ea079aba4ee69

@ -1 +1 @@
Subproject commit f85c594c182db2b01233e29ca52639b7baa00402
Subproject commit 0cba3cbc167cfe94e07fe5b629c925e190be939e

View File

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

View File

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

View File

@ -56,7 +56,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BenchmarkTest.cs" />
<Compile Include="VisualTests.cs" />
</ItemGroup>
<ItemGroup>
<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

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

View File

@ -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 const double time_per_test = 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 {time_per_test}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 * time_per_test);
}
Scheduler.AddDelayed(Host.Exit, f.TestCount * time_per_test);
}
}
}

View File

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

View File

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

View File

@ -3,7 +3,7 @@
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Game.Screens.Select;
namespace osu.Desktop.VisualTests.Tests

View File

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

View File

@ -1,17 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseChatDisplay : TestCase
{
private ScheduledDelegate messageRequest;
public override string Description => @"Testing chat api and overlay";
public override void Reset()

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
@ -20,7 +20,7 @@ namespace osu.Desktop.VisualTests.Tests
Add(overlay = new DialogOverlay());
AddButton("dialog #1", () => overlay.Push(new PopupDialog
AddStep("dialog #1", () => overlay.Push(new PopupDialog
{
Icon = FontAwesome.fa_trash_o,
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,
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
using System.Collections.Generic;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Game.Screens.Tournament;
using osu.Game.Screens.Tournament.Teams;
using osu.Game.Users;

View File

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

View File

@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Drawables;
@ -93,19 +93,28 @@ namespace osu.Desktop.VisualTests.Tests
playbackSpeed.TriggerChange();
AddButton(@"circles", () => load(HitObjectType.Circle));
AddButton(@"slider", () => load(HitObjectType.Slider));
AddButton(@"spinner", () => load(HitObjectType.Spinner));
AddStep(@"circles", () => load(HitObjectType.Circle));
AddStep(@"slider", () => load(HitObjectType.Slider));
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" });
ButtonsContainer.Add(new BasicSliderBar<double>
Add(new Container
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Bindable = playbackSpeed
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new SpriteText { Text = "Playback Speed" },
new BasicSliderBar<double>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Value = playbackSpeed
}
}
});
framedClock.ProcessFrame();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Framework.MathUtils;
using osu.Game.Overlays;
using System.Linq;
@ -30,13 +30,13 @@ namespace osu.Desktop.VisualTests.Tests
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);
AddButton(@"simple #2", sendNotification2);
AddButton(@"progress #1", sendProgress1);
AddButton(@"progress #2", sendProgress2);
AddButton(@"barrage", () => sendBarrage());
AddStep(@"simple #1", sendNotification1);
AddStep(@"simple #2", sendNotification2);
AddStep(@"progress #1", sendProgress1);
AddStep(@"progress #2", sendProgress2);
AddStep(@"barrage", () => sendBarrage());
}
private void sendBarrage(int remaining = 100)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Modes.UI;
@ -22,8 +22,6 @@ namespace osu.Desktop.VisualTests.Tests
int numerator = 0, denominator = 0;
bool maniaHold = false;
ScoreCounter score = new ScoreCounter(7)
{
Origin = Anchor.TopRight,
@ -68,7 +66,7 @@ namespace osu.Desktop.VisualTests.Tests
};
Add(starsLabel);
AddButton(@"Reset all", delegate
AddStep(@"Reset all", delegate
{
score.Current.Value = 0;
comboCounter.Current.Value = 0;
@ -78,7 +76,7 @@ namespace osu.Desktop.VisualTests.Tests
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);
comboCounter.Increment();
@ -86,20 +84,20 @@ namespace osu.Desktop.VisualTests.Tests
accuracyCounter.SetFraction(numerator, denominator);
});
AddButton(@"miss...", delegate
AddStep(@"miss...", delegate
{
comboCounter.Current.Value = 0;
denominator++;
accuracyCounter.SetFraction(numerator, denominator);
});
AddButton(@"Alter stars", delegate
AddStep(@"Alter stars", delegate
{
stars.Count = RNG.NextSingle() * (stars.StarCount + 1);
starsLabel.Text = stars.Count.ToString("0.00");
});
AddButton(@"Stop counters", delegate
AddStep(@"Stop counters", delegate
{
score.StopRolling();
comboCounter.StopRolling();

View File

@ -3,7 +3,7 @@
using OpenTK;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Select.Filter;
@ -36,9 +36,9 @@ namespace osu.Desktop.VisualTests.Tests
filter.PinItem(GroupMode.All);
filter.PinItem(GroupMode.RecentlyPlayed);
filter.ItemChanged += (sender, mode) =>
filter.SelectedItem.ValueChanged += newFilter =>
{
text.Text = "Currently Selected: " + mode.ToString();
text.Text = "Currently Selected: " + newFilter.ToString();
};
}
}

View File

@ -0,0 +1,121 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Modes.Taiko.Objects.Drawables.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;
updateKiaiState();
});
Add(new CirclePiece
{
Position = new Vector2(100, 100),
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
{
new CentreHitSymbolPiece()
}
});
Add(new CirclePiece(true)
{
Position = new Vector2(350, 100),
AccentColour = Color4.DarkRed,
KiaiMode = kiai,
Children = new[]
{
new CentreHitSymbolPiece()
}
});
Add(new CirclePiece
{
Position = new Vector2(100, 300),
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
{
new RimHitSymbolPiece()
}
});
Add(new CirclePiece(true)
{
Position = new Vector2(350, 300),
AccentColour = Color4.DarkBlue,
KiaiMode = kiai,
Children = new[]
{
new RimHitSymbolPiece()
}
});
Add(new CirclePiece
{
Position = new Vector2(100, 500),
AccentColour = Color4.Orange,
KiaiMode = kiai,
Children = new[]
{
new SwellSymbolPiece()
}
});
Add(new ElongatedCirclePiece
{
Position = new Vector2(575, 100),
AccentColour = Color4.Orange,
KiaiMode = kiai,
Length = 0.10f,
PlayfieldLengthReference = () => DrawSize.X
});
Add(new ElongatedCirclePiece(true)
{
Position = new Vector2(575, 300),
AccentColour = Color4.Orange,
KiaiMode = kiai,
Length = 0.10f,
PlayfieldLengthReference = () => DrawSize.X
});
}
private void updateKiaiState()
{
foreach (var c in Children.OfType<CirclePiece>())
c.KiaiMode = kiai;
}
private abstract class BaseCircle : Container
{
protected readonly CirclePiece Piece;
protected BaseCircle(CirclePiece piece)
{
Piece = piece;
Add(Piece);
}
}
}
}

View File

@ -1,11 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.Objects.Drawables;
using osu.Game.Modes.Taiko.UI;
namespace osu.Desktop.VisualTests.Tests
@ -16,16 +20,40 @@ namespace osu.Desktop.VisualTests.Tests
private TaikoPlayfield playfield;
protected override double TimePerAction => default_duration * 2;
private const double default_duration = 300;
private const float scroll_time = 1000;
public override void Reset()
{
base.Reset();
AddButton("Hit!", addHitJudgement);
AddButton("Miss :(", addMissJudgement);
AddStep("Hit!", addHitJudgement);
AddStep("Miss :(", addMissJudgement);
AddStep("DrumRoll", () => addDrumRoll(false));
AddStep("Strong DrumRoll", () => addDrumRoll(true));
AddStep("Swell", () => addSwell());
AddStep("Centre", () => addCentreHit(false));
AddStep("Strong Centre", () => addCentreHit(true));
AddStep("Rim", () => addRimHit(false));
AddStep("Strong Rim", () => addRimHit(true));
AddStep("Add bar line", () => addBarLine(false));
AddStep("Add major bar line", () => addBarLine(true));
Add(playfield = new TaikoPlayfield
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
Add(new Container
{
Y = 200
Clock = new FramedClock(rateAdjustClock),
RelativeSizeAxes = Axes.X,
Y = 200,
Children = new[]
{
playfield = new TaikoPlayfield()
}
});
}
@ -41,7 +69,6 @@ namespace osu.Desktop.VisualTests.Tests
Result = HitResult.Hit,
TaikoResult = hitResult,
TimeOffset = 0,
ComboAtHit = 1,
SecondHit = RNG.Next(10) == 0
}
});
@ -54,12 +81,76 @@ namespace osu.Desktop.VisualTests.Tests
Judgement = new TaikoJudgement
{
Result = HitResult.Miss,
TimeOffset = 0,
ComboAtHit = 0
TimeOffset = 0
}
});
}
private void addBarLine(bool major, double delay = scroll_time)
{
BarLine bl = new BarLine
{
StartTime = playfield.Time.Current + delay,
ScrollTime = scroll_time
};
playfield.AddBarLine(major ? new DrawableBarLineMajor(bl) : new DrawableBarLine(bl));
}
private void addSwell(double duration = default_duration)
{
playfield.Add(new DrawableSwell(new Swell
{
StartTime = playfield.Time.Current + scroll_time,
Duration = duration,
ScrollTime = scroll_time
}));
}
private void addDrumRoll(bool strong, double duration = default_duration)
{
addBarLine(true);
addBarLine(true, scroll_time + duration);
var d = new DrumRoll
{
StartTime = playfield.Time.Current + scroll_time,
IsStrong = strong,
Duration = duration,
ScrollTime = scroll_time,
};
playfield.Add(new DrawableDrumRoll(d));
}
private void addCentreHit(bool strong)
{
Hit h = new Hit
{
StartTime = playfield.Time.Current + scroll_time,
ScrollTime = scroll_time
};
if (strong)
playfield.Add(new DrawableCentreHitStrong(h));
else
playfield.Add(new DrawableCentreHit(h));
}
private void addRimHit(bool strong)
{
Hit h = new Hit
{
StartTime = playfield.Time.Current + scroll_time,
ScrollTime = scroll_time
};
if (strong)
playfield.Add(new DrawableRimHitStrong(h));
else
playfield.Add(new DrawableRimHit(h));
}
private class DrawableTestHit : DrawableHitObject<TaikoHitObject, TaikoJudgement>
{
public DrawableTestHit(TaikoHitObject hitObject)

View File

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

View File

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

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Platform;
using osu.Framework.Screens.Testing;
using osu.Framework.Testing;
using osu.Game;
using osu.Game.Screens.Backgrounds;
@ -14,7 +14,7 @@ namespace osu.Desktop.VisualTests
{
base.LoadComplete();
new BackgroundScreenDefault { Depth = 10 }.LoadAsync(this, AddInternal);
LoadComponentAsync(new BackgroundScreenDefault { Depth = 10 }, AddInternal);
// Have to construct this here, rather than in the constructor, because
// we depend on some dependencies to be loaded within OsuGameBase.load().
@ -24,6 +24,11 @@ namespace osu.Desktop.VisualTests
public override void SetHost(GameHost 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;
}
}

View File

@ -150,6 +150,10 @@
<Project>{65dc628f-a640-4111-ab35-3a5652bc1e17}</Project>
<Name>osu.Framework.Desktop</Name>
</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">
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
<Name>osu.Framework</Name>
@ -180,11 +184,12 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Benchmark.cs" />
<Compile Include="AutomatedVisualTestGame.cs" />
<Compile Include="Program.cs" />
<Compile Include="Tests\TestCaseChatDisplay.cs" />
<Compile Include="Tests\TestCaseDrawings.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseMenuOverlays.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" />
<Compile Include="Tests\TestCaseNotificationManager.cs" />
<Compile Include="Tests\TestCasePlayer.cs" />
@ -194,6 +199,7 @@
<Compile Include="Tests\TestCaseReplay.cs" />
<Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTabControl.cs" />
<Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
@ -201,7 +207,6 @@
<Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseOptions.cs" />
<Compile Include="Tests\TestCasePauseOverlay.cs" />
<Compile Include="Tests\TestCaseModSelectOverlay.cs" />
<Compile Include="Tests\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />
@ -211,9 +216,7 @@
</ItemGroup>
<ItemGroup />
<ItemGroup />
<ItemGroup>
<Folder Include="Beatmaps\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- 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.

View File

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

View File

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

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

View File

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

View File

@ -123,7 +123,10 @@
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</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">
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
@ -150,6 +153,7 @@
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
</None>
<None Include="OpenTK.dll.config" />
<None Include="osu!.res" />
<None Include="packages.config" />
<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="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="ppy.OpenTK" version="2.0.50727.1340" targetFramework="net45" />
<package id="Splat" version="2.0.0" targetFramework="net45" />
<package id="squirrel.windows" version="1.5.2" targetFramework="net45" />
</packages>

View File

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

View File

@ -7,8 +7,8 @@ namespace osu.Game.Modes.Catch.Judgements
{
public class CatchJudgement : Judgement
{
public override string ScoreString => string.Empty;
public override string ResultString => string.Empty;
public override string MaxScoreString => string.Empty;
public override string MaxResultString => string.Empty;
}
}

View File

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

View File

@ -3,9 +3,10 @@
using osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Catch
namespace osu.Game.Modes.Catch.Scoring
{
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgement>
{
@ -18,7 +19,7 @@ namespace osu.Game.Modes.Catch
{
}
protected override void UpdateCalculations(CatchJudgement newJudgement)
protected override void OnNewJudgement(CatchJudgement judgement)
{
}
}

View File

@ -5,7 +5,9 @@ using osu.Game.Beatmaps;
using osu.Game.Modes.Catch.Beatmaps;
using osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.Catch.Scoring;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Catch.UI

View File

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

View File

@ -7,8 +7,8 @@ namespace osu.Game.Modes.Mania.Judgements
{
public class ManiaJudgement : Judgement
{
public override string ScoreString => string.Empty;
public override string ResultString => string.Empty;
public override string MaxScoreString => 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.Screens.Play;
using System.Collections.Generic;
using osu.Game.Modes.Mania.Scoring;
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Mania
{

View File

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

View File

@ -3,9 +3,10 @@
using osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania
namespace osu.Game.Modes.Mania.Scoring
{
internal class ManiaScoreProcessor : ScoreProcessor<ManiaBaseHit, ManiaJudgement>
{
@ -18,7 +19,7 @@ namespace osu.Game.Modes.Mania
{
}
protected override void UpdateCalculations(ManiaJudgement newJudgement)
protected override void OnNewJudgement(ManiaJudgement judgement)
{
}
}

View File

@ -5,7 +5,9 @@ using osu.Game.Beatmaps;
using osu.Game.Modes.Mania.Beatmaps;
using osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.Mania.Scoring;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania.UI

View File

@ -51,7 +51,7 @@
<Compile Include="Beatmaps\ManiaBeatmapProcessor.cs" />
<Compile Include="Judgements\ManiaJudgement.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="ManiaScoreProcessor.cs" />
<Compile Include="Scoring\ManiaScoreProcessor.cs" />
<Compile Include="Objects\Drawable\DrawableNote.cs" />
<Compile Include="Objects\HoldNote.cs" />
<Compile Include="Objects\ManiaBaseHit.cs" />

View File

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

View File

@ -25,9 +25,9 @@ namespace osu.Game.Modes.Osu.Judgements
/// </summary>
public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
public override string ScoreString => Score.GetDescription();
public override string ResultString => Score.GetDescription();
public override string MaxScoreString => MaxScore.GetDescription();
public override string MaxResultString => MaxScore.GetDescription();
public int ScoreValue => scoreToInt(Score);

View File

@ -7,6 +7,7 @@ using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Objects;
using System;
using System.Linq;
using osu.Game.Modes.Scoring;
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.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Modes.Osu.Objects.Drawables.Connections
{
@ -33,7 +32,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Connections
Colour = Color4.White.Opacity(0.2f),
Radius = 4,
};
Children = new Drawable[]
{
new Box

View File

@ -3,7 +3,6 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
using OpenTK;
@ -39,7 +38,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Colour = AccentColour,
Hit = () =>
{
if (Judgement.Result.HasValue) return false;
if (Judgement.Result != HitResult.None) return false;
Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value
UpdateJudgement(true);

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;

View File

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

View File

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

View File

@ -4,7 +4,6 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;

View File

@ -4,7 +4,6 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input;
using OpenTK.Graphics;

View File

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

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Modes.Osu.Objects;
@ -10,11 +9,13 @@ using osu.Game.Modes.Osu.Objects.Drawables;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Replays;
namespace osu.Game.Modes.Osu
{
public class OsuAutoReplay : LegacyReplay
public class OsuAutoReplay : Replay
{
private static readonly Vector2 spinner_centre = new Vector2(256, 192);
@ -29,17 +30,20 @@ namespace osu.Game.Modes.Osu
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);
}
}
private static readonly IComparer<LegacyReplayFrame> replay_frame_comparer = 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, replay_frame_comparer);
@ -59,7 +63,7 @@ namespace osu.Game.Modes.Osu
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));
@ -74,9 +78,9 @@ namespace osu.Game.Modes.Osu
EasingTypes preferredEasing = DelayedMovements ? EasingTypes.InOutCubic : EasingTypes.Out;
addFrameToReplay(new LegacyReplayFrame(-100000, 256, 500, LegacyButtonState.None));
addFrameToReplay(new LegacyReplayFrame(beatmap.HitObjects[0].StartTime - 1500, 256, 500, LegacyButtonState.None));
addFrameToReplay(new LegacyReplayFrame(beatmap.HitObjects[0].StartTime - 1000, 256, 192, LegacyButtonState.None));
addFrameToReplay(new ReplayFrame(-100000, 256, 500, ReplayButtonState.None));
addFrameToReplay(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1500, 256, 500, ReplayButtonState.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.
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).
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 (!(h is Spinner)) addFrameToReplay(new LegacyReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.Position.X, h.Position.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 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)
{
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 (!(h is Spinner)) addFrameToReplay(new LegacyReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.Position.X, h.Position.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 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)
{
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 (!(h is Spinner)) addFrameToReplay(new LegacyReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.Position.X, h.Position.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 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
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.
double waitTime = h.StartTime - Math.Max(0.0, DrawableOsuHitObject.TIME_PREEMPT - reactionTime);
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);
}
@ -196,7 +200,7 @@ namespace osu.Game.Modes.Osu
for (double time = lastFrame.Time + frameDelay; time < h.StartTime; time += frameDelay)
{
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;
@ -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;
LegacyReplayFrame newFrame = new LegacyReplayFrame(h.StartTime, targetPosition.X, targetPosition.Y, button);
LegacyReplayFrame endFrame = new LegacyReplayFrame(hEndTime + endDelay, h.EndPosition.X, h.EndPosition.Y, LegacyButtonState.None);
ReplayFrame newFrame = new ReplayFrame(h.StartTime, targetPosition.X, targetPosition.Y, button);
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
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!
if (index >= 0)
{
LegacyReplayFrame previousFrame = Frames[index];
ReplayFrame previousFrame = Frames[index];
var previousButton = previousFrame.ButtonState;
// 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.
if (previousButton == button)
{
button = (LegacyButtonState.Left1 | LegacyButtonState.Right1) & ~button;
newFrame.SetButtonStates(button);
button = (ReplayButtonState.Left1 | ReplayButtonState.Right1) & ~button;
newFrame.ButtonState = button;
}
// 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!
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;
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;
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.MouseY = endPosition.Y;
@ -288,10 +292,10 @@ namespace osu.Game.Modes.Osu
for (double j = frameDelay; j < s.Duration; j += frameDelay)
{
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!

View File

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

View File

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

View File

@ -1,7 +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.Osu
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Osu.Scoring
{
internal class OsuScore : Score
{

View File

@ -4,9 +4,10 @@
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Osu
namespace osu.Game.Modes.Osu.Scoring
{
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
{
@ -27,7 +28,7 @@ namespace osu.Game.Modes.Osu
Accuracy.Value = 1;
}
protected override void UpdateCalculations(OsuJudgement judgement)
protected override void OnNewJudgement(OsuJudgement judgement)
{
if (judgement != null)
{

View File

@ -7,6 +7,8 @@ using osu.Game.Modes.Osu.Beatmaps;
using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects;
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.Screens.Play;

View File

@ -21,6 +21,8 @@ namespace osu.Game.Modes.Osu.UI
private readonly Container judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
public override bool ProvidingUserCursor => true;
public override Vector2 Size
{
get

View File

@ -72,8 +72,8 @@
<Compile Include="OsuAutoReplay.cs" />
<Compile Include="OsuDifficultyCalculator.cs" />
<Compile Include="OsuKeyConversionInputManager.cs" />
<Compile Include="OsuScore.cs" />
<Compile Include="OsuScoreProcessor.cs" />
<Compile Include="Scoring\OsuScore.cs" />
<Compile Include="Scoring\OsuScoreProcessor.cs" />
<Compile Include="UI\OsuHitRenderer.cs" />
<Compile Include="UI\OsuPlayfield.cs" />
<Compile Include="OsuRuleset.cs" />

View File

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

View File

@ -8,12 +8,14 @@ namespace osu.Game.Modes.Taiko.Judgements
/// <summary>
/// Drum roll ticks don't display judgement text.
/// </summary>
public override string ScoreString => string.Empty;
public override string ResultString => string.Empty;
/// <summary>
/// Drum roll ticks don't display judgement text.
/// </summary>
public override string MaxScoreString => string.Empty;
public override string MaxResultString => string.Empty;
public override bool AffectsCombo => false;
protected override int NumericResultForScore(TaikoHitResult result)
{

View File

@ -3,56 +3,57 @@
using osu.Game.Modes.Judgements;
using osu.Framework.Extensions;
using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Taiko.Judgements
{
public class TaikoJudgement : Judgement
{
/// <summary>
/// The maximum score value.
/// The maximum result.
/// </summary>
public const TaikoHitResult MAX_HIT_RESULT = TaikoHitResult.Great;
/// <summary>
/// The score value.
/// The result.
/// </summary>
public TaikoHitResult TaikoResult;
/// <summary>
/// The score value for the combo portion of the score.
/// The result value for the combo portion of the score.
/// </summary>
public int ScoreValue => NumericResultForScore(TaikoResult);
/// <summary>
/// The score value for the accuracy portion of the score.
/// </summary>
public int AccuracyScoreValue => NumericResultForAccuracy(TaikoResult);
public int ResultValueForScore => Result == HitResult.Miss ? 0 : NumericResultForScore(TaikoResult);
/// <summary>
/// The maximum score value for the combo portion of the score.
/// The result value for the accuracy portion of the score.
/// </summary>
public int MaxScoreValue => NumericResultForScore(MAX_HIT_RESULT);
/// <summary>
/// The maximum score value for the accuracy portion of the score.
/// </summary>
public int MaxAccuracyScoreValue => NumericResultForAccuracy(MAX_HIT_RESULT);
public override string ScoreString => TaikoResult.GetDescription();
public override string MaxScoreString => MAX_HIT_RESULT.GetDescription();
public int ResultValueForAccuracy => Result == HitResult.Miss ? 0 : NumericResultForAccuracy(TaikoResult);
/// <summary>
/// Whether this Judgement has a secondary hit in the case of finishers.
/// The maximum result value for the combo portion of the score.
/// </summary>
public bool SecondHit;
public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT);
/// <summary>
/// Computes the numeric score value for the combo portion of the score.
/// The maximum result value for the accuracy portion of the score.
/// </summary>
public int MaxResultValueForAccuracy => NumericResultForAccuracy(MAX_HIT_RESULT);
public override string ResultString => TaikoResult.GetDescription();
public override string MaxResultString => MAX_HIT_RESULT.GetDescription();
/// <summary>
/// Whether this Judgement has a secondary hit in the case of strong hits.
/// </summary>
public virtual bool SecondHit { get; set; }
/// <summary>
/// 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)"/>.
/// </summary>
/// <param name="result">The result to compute the score value for.</param>
/// <returns>The numeric score value.</returns>
/// <param name="result">The result to compute the value for.</param>
/// <returns>The numeric result value.</returns>
protected virtual int NumericResultForScore(TaikoHitResult result)
{
switch (result)
@ -67,11 +68,11 @@ namespace osu.Game.Modes.Taiko.Judgements
}
/// <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)"/>.
/// </summary>
/// <param name="result">The result to compute the score value for.</param>
/// <returns>The numeric score value.</returns>
/// <param name="result">The result to compute the value for.</param>
/// <returns>The numeric result value.</returns>
protected virtual int NumericResultForAccuracy(TaikoHitResult 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>.
// 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.Scoring;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.Replays;
using osu.Game.Users;
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

@ -1,10 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
namespace osu.Game.Modes.Taiko.Objects
{
public class HitSampleInfo : SampleInfo
public class BarLine : TaikoHitObject
{
public SampleType Type { get; set; }
}
}

View File

@ -1,30 +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.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Modes.Objects.Types;
namespace osu.Game.Modes.Taiko.Objects
{
public class Bash : TaikoHitObject, IHasEndTime
{
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
/// <summary>
/// The number of hits required to complete the bash successfully.
/// </summary>
public int RequiredHits { get; protected set; }
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
double spinnerRotationRatio = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5);
RequiredHits = (int)Math.Max(1, Duration / 1000f * spinnerRotationRatio);
}
}
}

View File

@ -1,11 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
namespace osu.Game.Modes.Taiko.Objects
{
public class SampleInfo
public class CentreHit : Hit
{
public SampleBank Bank;
public SampleSet Set;
}
}

View File

@ -1,46 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public abstract class DrawableTaikoHitObject : DrawableHitObject<TaikoHitObject, TaikoJudgement>
{
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;
LifetimeEnd = HitObject.StartTime + HitObject.PreEmpt;
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);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,63 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using OpenTK.Input;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableDrumRollTick : DrawableTaikoHitObject<DrumRollTick>
{
public DrawableDrumRollTick(DrumRollTick tick)
: base(tick)
{
}
protected override TaikoPiece CreateMainPiece() => new TickPiece
{
Filled = HitObject.FirstTick
};
protected override TaikoJudgement CreateJudgement() => new TaikoDrumRollTickJudgement { SecondHit = HitObject.IsStrong };
protected override void CheckJudgement(bool userTriggered)
{
if (!userTriggered)
{
if (Judgement.TimeOffset > HitObject.HitWindow)
Judgement.Result = HitResult.Miss;
return;
}
if (Math.Abs(Judgement.TimeOffset) < HitObject.HitWindow)
{
Judgement.Result = HitResult.Hit;
Judgement.TaikoResult = TaikoHitResult.Great;
}
}
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
Content.ScaleTo(0, 100, EasingTypes.OutQuint);
break;
}
}
protected override void UpdateScrollPosition(double time)
{
// Ticks don't move
}
protected override bool HandleKeyPress(Key key)
{
return Judgement.Result == HitResult.None && UpdateJudgement(true);
}
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,243 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.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.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public class DrawableSwell : DrawableTaikoHitObject<Swell>
{
/// <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 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)
{
Children = new Drawable[]
{
bodyContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new 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 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
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new []
{
symbol = new SwellSymbolPiece()
}
}
}
}
};
circlePiece.KiaiMode = HitObject.Kiai;
}
[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 / HitObject.RequiredHits;
expandingRing.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50);
expandingRing.Delay(50);
expandingRing.FadeTo(completion / 8, 2000, EasingTypes.OutQuint);
expandingRing.DelayReset();
symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, EasingTypes.OutQuint);
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);
if (userHits == HitObject.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 > HitObject.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 + HitObject.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

@ -0,0 +1,93 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Modes.Taiko.Objects.Drawables
{
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableHitObject<TaikoHitObject, TaikoJudgement>
where TaikoHitType : TaikoHitObject
{
/// <summary>
/// A list of keys which this hit object will accept. These are the standard Taiko keys for now.
/// 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 });
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
protected override Container<Drawable> Content => bodyContainer;
protected readonly TaikoPiece MainPiece;
private readonly Container bodyContainer;
public new TaikoHitType HitObject;
protected DrawableTaikoHitObject(TaikoHitType hitObject)
: base(hitObject)
{
HitObject = hitObject;
Anchor = Anchor.CentreLeft;
Origin = Anchor.Custom;
AutoSizeAxes = Axes.Both;
RelativePositionAxes = Axes.X;
AddInternal(bodyContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new[]
{
MainPiece = CreateMainPiece()
}
});
MainPiece.KiaiMode = HitObject.Kiai;
LifetimeStart = HitObject.StartTime - HitObject.ScrollTime * 2;
}
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement();
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(HitObject.IsStrong);
/// <summary>
/// Sets the scroll position of the DrawableHitObject relative to the offset between
/// a time value and the HitObject's StartTime.
/// </summary>
/// <param name="time"></param>
protected virtual void UpdateScrollPosition(double time) => X = (float)((HitObject.StartTime - time) / HitObject.ScrollTime);
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;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Modes.Taiko.Objects.Drawables.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,157 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Backgrounds;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.Pieces
{
/// <summary>
/// A circle piece which is used uniformly through osu!taiko to visualise hitobjects.
/// <para>
/// Note that this can actually be non-circle if the width is changed. See <see cref="ElongatedCirclePiece"/>
/// for a usage example.
/// </para>
/// </summary>
public class CirclePiece : TaikoPiece
{
public const float SYMBOL_SIZE = TaikoHitObject.CIRCLE_RADIUS * 2f * 0.45f;
public const float SYMBOL_BORDER = 8;
public const float SYMBOL_INNER_SIZE = SYMBOL_SIZE - 2 * SYMBOL_BORDER;
/// <summary>
/// The amount to scale up the base circle to show it as a "strong" piece.
/// </summary>
private const float strong_scale = 1.5f;
/// <summary>
/// The colour of the inner circle and outer glows.
/// </summary>
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
base.AccentColour = value;
background.Colour = AccentColour;
resetEdgeEffects();
}
}
/// <summary>
/// Whether Kiai mode effects are enabled for this circle piece.
/// </summary>
public override bool KiaiMode
{
get { return base.KiaiMode; }
set
{
base.KiaiMode = value;
resetEdgeEffects();
}
}
protected override Container<Drawable> Content => content;
private readonly Container content;
private readonly Container background;
public Box FlashBox;
public CirclePiece(bool isStrong = false)
{
AddInternal(new Drawable[]
{
background = new CircularContainer
{
Name = "Background",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
{
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
},
new Triangles
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
ColourLight = Color4.White,
ColourDark = Color4.White.Darken(0.1f)
}
}
},
new CircularContainer
{
Name = "Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
BorderThickness = 8,
BorderColour = Color4.White,
Masking = true,
Children = new[]
{
FlashBox = new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
BlendingMode = BlendingMode.Additive,
Alpha = 0,
AlwaysPresent = true
}
}
},
content = new Container
{
RelativeSizeAxes = Axes.Both,
Name = "Content",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
if (isStrong)
{
Size *= strong_scale;
//default for symbols etc.
Content.Scale *= strong_scale;
}
}
protected override void Update()
{
base.Update();
//we want to allow for width of content to remain mapped to the area inside us, regardless of the scale applied above.
Content.Width = 1 / Content.Scale.X;
}
private void resetEdgeEffects()
{
background.EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Colour = AccentColour,
Radius = KiaiMode ? 50 : 8
};
}
}
}

View File

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

View File

@ -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;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Taiko.Objects.Drawables.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