mirror of
https://github.com/ppy/osu.git
synced 2026-05-14 06:42:34 +08:00
Compare commits
558 Commits
Vendored
+23
-7
@@ -11,7 +11,11 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Debug)",
|
||||
"env": {},
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@@ -24,7 +28,11 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Release)",
|
||||
"env": {},
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@@ -33,11 +41,15 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"env": {},
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@@ -46,12 +58,16 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"env": {},
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
# osu! [](https://ci.appveyor.com/project/peppy/osu) [](https://www.codefactor.io/repository/github/ppy/osu) [](https://discord.gg/ppy)
|
||||
|
||||
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era!
|
||||
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Commonly known by the codename "osu!lazer". Pew pew.
|
||||
|
||||
# Status
|
||||
|
||||
This is still heavily under development and is not intended for end-user use. This repository is intended for developer collaboration. You're welcome to try and use it but please do not submit bug reports without a patch. Please do not ask for help building or using this software.
|
||||
This project is still heavily under development, but is in a state where users are encouraged to try it out and keep it installed alongside the stable osu! client. It will continue to evolve over the coming months and hopefully bring some new unique features to the table.
|
||||
|
||||
We are accepting bug reports (please report with as much detail as possible). Feature requests are welcome as long as you read and understand the contribution guidelines listed below.
|
||||
|
||||
# Requirements
|
||||
|
||||
- A desktop platform that can compile .NET 4.7.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
|
||||
- A desktop platform with the [.NET Core SDK 2.1](https://www.microsoft.com/net/learn/get-started) or higher installed.
|
||||
- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio Code](https://code.visualstudio.com/) (with the C# plugin installed) or [Jetbrains Rider](https://www.jetbrains.com/rider/) (commercial).
|
||||
|
||||
# Getting Started
|
||||
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
|
||||
- Build in your IDE of choice (recommended IDEs automatically restore nuget packages; if you are using an alternative make sure to `nuget restore`)
|
||||
# Building and running
|
||||
|
||||
If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled (download and run the install executable for your platform).
|
||||
|
||||
Clone the repository including submodules
|
||||
|
||||
`git clone --recurse-submodules https://github.com/ppy/osu`
|
||||
|
||||
Build and run
|
||||
|
||||
- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
|
||||
- From command line using `dotnet run --project osu.Desktop`
|
||||
|
||||
If you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`). Visual Studio Code users must run `Restore` task from debug tab before attempt to build.
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
+6
-5
@@ -2,20 +2,21 @@ clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017
|
||||
configuration: Debug
|
||||
cache:
|
||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: choco install resharper-clt -y
|
||||
- cmd: choco install nvika -y
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe
|
||||
- cmd: dotnet tool install CodeFileSanity --version 0.0.16 --global
|
||||
before_build:
|
||||
- cmd: CodeFileSanity.exe
|
||||
- cmd: CodeFileSanity
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
environment:
|
||||
TargetFramework: net471
|
||||
build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
|
||||
+3
-5
@@ -16,17 +16,15 @@ build_script:
|
||||
- cd osu-deploy
|
||||
- nuget restore -verbosity quiet
|
||||
- msbuild osu.Desktop.Deploy.csproj
|
||||
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\net471\osu.Desktop.Deploy.exe.config
|
||||
- cd bin\Debug\net471\
|
||||
- osu.Desktop.Deploy.exe %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
|
||||
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\netcoreapp2.1\osu.Desktop.Deploy.dll.config
|
||||
- dotnet bin/Debug/netcoreapp2.1/osu.Desktop.Deploy.dll %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
|
||||
environment:
|
||||
TargetFramework: net471
|
||||
decode_secret:
|
||||
secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY=
|
||||
code_signing_password:
|
||||
secure: 34tLNqvjmmZEi97MLKfrnQ==
|
||||
artifacts:
|
||||
- path: 'Releases\*'
|
||||
- path: 'osu-deploy/releases/*'
|
||||
deploy:
|
||||
- provider: Environment
|
||||
name: github
|
||||
@@ -12,6 +12,8 @@ using osu.Framework.Platform;
|
||||
using osu.Game;
|
||||
using OpenTK.Input;
|
||||
using Microsoft.Win32;
|
||||
using osu.Desktop.Updater;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Platform.Windows;
|
||||
|
||||
namespace osu.Desktop
|
||||
@@ -38,6 +40,51 @@ namespace osu.Desktop
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (!noVersionOverlay)
|
||||
{
|
||||
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
|
||||
{
|
||||
Add(v);
|
||||
v.State = Visibility.Visible;
|
||||
});
|
||||
|
||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||
Add(new SquirrelUpdateManager());
|
||||
else
|
||||
Add(new SimpleUpdateManager());
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetHost(GameHost host)
|
||||
{
|
||||
base.SetHost(host);
|
||||
var desktopWindow = host.Window as DesktopGameWindow;
|
||||
if (desktopWindow != null)
|
||||
{
|
||||
desktopWindow.CursorState |= CursorState.Hidden;
|
||||
|
||||
desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
|
||||
desktopWindow.Title = Name;
|
||||
|
||||
desktopWindow.FileDrop += fileDrop;
|
||||
}
|
||||
}
|
||||
|
||||
private void fileDrop(object sender, FileDropEventArgs e)
|
||||
{
|
||||
var filePaths = new[] { e.FileName };
|
||||
|
||||
var firstExtension = Path.GetExtension(filePaths.First());
|
||||
|
||||
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
|
||||
|
||||
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method of accessing an osu-stable install in a controlled fashion.
|
||||
/// </summary>
|
||||
@@ -77,45 +124,5 @@ namespace osu.Desktop
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (!noVersionOverlay)
|
||||
{
|
||||
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
|
||||
{
|
||||
Add(v);
|
||||
v.State = Visibility.Visible;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetHost(GameHost host)
|
||||
{
|
||||
base.SetHost(host);
|
||||
var desktopWindow = host.Window as DesktopGameWindow;
|
||||
if (desktopWindow != null)
|
||||
{
|
||||
desktopWindow.CursorState |= CursorState.Hidden;
|
||||
|
||||
desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
|
||||
desktopWindow.Title = Name;
|
||||
|
||||
desktopWindow.FileDrop += fileDrop;
|
||||
}
|
||||
}
|
||||
|
||||
private void fileDrop(object sender, FileDropEventArgs e)
|
||||
{
|
||||
var filePaths = new[] { e.FileName };
|
||||
|
||||
var firstExtension = Path.GetExtension(filePaths.First());
|
||||
|
||||
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
|
||||
|
||||
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,10 +91,6 @@ namespace osu.Desktop.Overlays
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
Add(new SquirrelUpdateManager());
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
||||
@@ -7,9 +7,6 @@ using System.Linq;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.IPC;
|
||||
#if NET_FRAMEWORK
|
||||
using System.Runtime;
|
||||
#endif
|
||||
|
||||
namespace osu.Desktop
|
||||
{
|
||||
@@ -18,11 +15,6 @@ namespace osu.Desktop
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
// required to initialise native SQLite libraries on some platforms.
|
||||
|
||||
if (!RuntimeInfo.IsMono)
|
||||
useMulticoreJit();
|
||||
|
||||
// Back up the cwd before DesktopGameHost changes it
|
||||
var cwd = Environment.CurrentDirectory;
|
||||
|
||||
@@ -53,14 +45,5 @@ namespace osu.Desktop
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void useMulticoreJit()
|
||||
{
|
||||
#if NET_FRAMEWORK
|
||||
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
|
||||
ProfileOptimization.SetProfileRoot(directory.FullName);
|
||||
ProfileOptimization.StartProfile("Startup.Profile");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
|
||||
namespace osu.Desktop.Updater
|
||||
{
|
||||
/// <summary>
|
||||
/// An update manager that shows notifications if a newer release is detected.
|
||||
/// Installation is left up to the user.
|
||||
/// </summary>
|
||||
internal class SimpleUpdateManager : CompositeDrawable
|
||||
{
|
||||
private NotificationOverlay notificationOverlay;
|
||||
private string version;
|
||||
private GameHost host;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(NotificationOverlay notification, OsuGameBase game, GameHost host)
|
||||
{
|
||||
notificationOverlay = notification;
|
||||
|
||||
this.host = host;
|
||||
version = game.Version;
|
||||
|
||||
if (game.IsDeployedBuild)
|
||||
Schedule(() => Task.Run(() => checkForUpdateAsync()));
|
||||
}
|
||||
|
||||
private async void checkForUpdateAsync()
|
||||
{
|
||||
var releases = new JsonWebRequest<GitHubRelease>("https://api.github.com/repos/ppy/osu/releases/latest");
|
||||
await releases.PerformAsync();
|
||||
|
||||
var latest = releases.ResponseObject;
|
||||
|
||||
if (latest.TagName != version)
|
||||
{
|
||||
notificationOverlay.Post(new SimpleNotification
|
||||
{
|
||||
Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n"
|
||||
+ "Click here to download the new version, which can be installed over the top of your existing installation",
|
||||
Icon = FontAwesome.fa_upload,
|
||||
Activated = () =>
|
||||
{
|
||||
host.OpenUrlExternally(getBestUrl(latest));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private string getBestUrl(GitHubRelease release)
|
||||
{
|
||||
GitHubAsset bestAsset = null;
|
||||
|
||||
switch (RuntimeInfo.OS)
|
||||
{
|
||||
case RuntimeInfo.Platform.Windows:
|
||||
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe"));
|
||||
break;
|
||||
case RuntimeInfo.Platform.MacOsx:
|
||||
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".app.zip"));
|
||||
break;
|
||||
}
|
||||
|
||||
return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
|
||||
}
|
||||
|
||||
public class GitHubRelease
|
||||
{
|
||||
[JsonProperty("html_url")]
|
||||
public string HtmlUrl { get; set; }
|
||||
|
||||
[JsonProperty("tag_name")]
|
||||
public string TagName { get; set; }
|
||||
|
||||
[JsonProperty("assets")]
|
||||
public List<GitHubAsset> Assets { get; set; }
|
||||
}
|
||||
|
||||
public class GitHubAsset
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("browser_download_url")]
|
||||
public string BrowserDownloadUrl { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
@@ -16,7 +16,7 @@ using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using Squirrel;
|
||||
|
||||
namespace osu.Desktop.Overlays
|
||||
namespace osu.Desktop.Updater
|
||||
{
|
||||
public class SquirrelUpdateManager : Component
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace osu.Desktop.Overlays
|
||||
notificationOverlay = notification;
|
||||
|
||||
if (game.IsDeployedBuild)
|
||||
Schedule(() => checkForUpdateAsync());
|
||||
Schedule(() => Task.Run(() => checkForUpdateAsync()));
|
||||
}
|
||||
|
||||
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
|
||||
@@ -161,4 +161,3 @@ namespace osu.Desktop.Overlays
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.Game.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@@ -13,9 +13,6 @@
|
||||
<Version>0.0.0</Version>
|
||||
<FileVersion>0.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Defines">
|
||||
<DefineConstants Condition="'$(TargetFramework)' == 'net471'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>osu.Desktop.Program</StartupObject>
|
||||
</PropertyGroup>
|
||||
@@ -29,11 +26,12 @@
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>osulazer</id>
|
||||
<version>0.0.0</version>
|
||||
<title>osulazer</title>
|
||||
<title>osu!lazer</title>
|
||||
<authors>ppy Pty Ltd</authors>
|
||||
<owners>Dean Herbert</owners>
|
||||
<projectUrl>https://osu.ppy.sh/</projectUrl>
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -28,18 +28,20 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||
{
|
||||
if (hitObject is JuiceStream stream)
|
||||
switch (hitObject)
|
||||
{
|
||||
foreach (var nested in stream.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
case JuiceStream stream:
|
||||
foreach (var nested in stream.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
break;
|
||||
case BananaShower shower:
|
||||
foreach (var nested in shower.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
break;
|
||||
default:
|
||||
yield return new ConvertValue((CatchHitObject)hitObject);
|
||||
break;
|
||||
}
|
||||
else if (hitObject is BananaShower shower)
|
||||
{
|
||||
foreach (var nested in shower.NestedHitObjects)
|
||||
yield return new ConvertValue((CatchHitObject)nested);
|
||||
}
|
||||
else
|
||||
yield return new ConvertValue((CatchHitObject)hitObject);
|
||||
}
|
||||
|
||||
protected override Ruleset CreateRuleset() => new CatchRuleset();
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperdashState(status ? 2 : 1);
|
||||
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperDashState(status ? 2 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
private DrawableFruit createDrawable(int index)
|
||||
{
|
||||
Fruit fruit = index == 5
|
||||
? new BananaShower.Banana
|
||||
? new Banana
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@ using osu.Game.Rulesets.Catch.Objects;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
|
||||
public class TestCaseHyperDash : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseHyperdash()
|
||||
public TestCaseHyperDash()
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
{
|
||||
public class CatchBeatmapProcessor : BeatmapProcessor
|
||||
{
|
||||
public const int RNG_SEED = 1337;
|
||||
|
||||
public CatchBeatmapProcessor(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
@@ -22,12 +24,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
|
||||
public override void PostProcess()
|
||||
{
|
||||
base.PostProcess();
|
||||
|
||||
applyPositionOffsets();
|
||||
|
||||
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
|
||||
|
||||
base.PostProcess();
|
||||
|
||||
int index = 0;
|
||||
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
|
||||
{
|
||||
@@ -37,8 +39,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
public const int RNG_SEED = 1337;
|
||||
|
||||
private void applyPositionOffsets()
|
||||
{
|
||||
var rng = new FastRandom(RNG_SEED);
|
||||
@@ -49,9 +49,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
switch (obj)
|
||||
{
|
||||
case BananaShower bananaShower:
|
||||
foreach (var nested in bananaShower.NestedHitObjects)
|
||||
foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
|
||||
{
|
||||
((BananaShower.Banana)nested).X = (float)rng.NextDouble();
|
||||
banana.X = (float)rng.NextDouble();
|
||||
rng.Next(); // osu!stable retrieved a random banana type
|
||||
rng.Next(); // osu!stable retrieved a random banana rotation
|
||||
rng.Next(); // osu!stable retrieved a random banana colour
|
||||
|
||||
@@ -46,13 +46,16 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
|
||||
foreach (var hitObject in beatmap.HitObjects)
|
||||
{
|
||||
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
|
||||
if (hitObject is Fruit)
|
||||
switch (hitObject)
|
||||
{
|
||||
difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, halfCatchWidth));
|
||||
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
|
||||
case Fruit fruit:
|
||||
difficultyHitObjects.Add(new CatchDifficultyHitObject(fruit, halfCatchWidth));
|
||||
break;
|
||||
case JuiceStream _:
|
||||
difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType<CatchHitObject>().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
|
||||
break;
|
||||
}
|
||||
if (hitObject is JuiceStream)
|
||||
difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType<CatchHitObject>().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
|
||||
}
|
||||
|
||||
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
|
||||
@@ -61,12 +64,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
return new CatchDifficultyAttributes(mods, 0);
|
||||
|
||||
// this is the same as osu!, so there's potential to share the implementation... maybe
|
||||
double preEmpt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
|
||||
double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
|
||||
double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;
|
||||
|
||||
return new CatchDifficultyAttributes(mods, starRating)
|
||||
{
|
||||
ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0,
|
||||
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
|
||||
MaxCombo = difficultyHitObjects.Count
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Judgements
|
||||
{
|
||||
public class CatchBananaJudgement : CatchJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
public override bool ShouldExplode => true;
|
||||
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 1100;
|
||||
}
|
||||
}
|
||||
|
||||
protected override float HealthIncreaseFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Judgements
|
||||
{
|
||||
public class CatchDropletJudgement : CatchJudgement
|
||||
{
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
||||
protected override float HealthIncreaseFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,51 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Judgements
|
||||
{
|
||||
public class CatchJudgement : Judgement
|
||||
{
|
||||
// todo: wangs
|
||||
public override HitResult MaxResult => HitResult.Perfect;
|
||||
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The base health increase for the result achieved.
|
||||
/// </summary>
|
||||
public float HealthIncrease => HealthIncreaseFor(Result);
|
||||
|
||||
/// <summary>
|
||||
/// Whether fruit on the platter should explode or drop.
|
||||
/// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" />
|
||||
/// </summary>
|
||||
public virtual bool ShouldExplode => IsHit;
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="HitResult"/> to a base health increase.
|
||||
/// </summary>
|
||||
/// <param name="result">The value to convert.</param>
|
||||
/// <returns>The base health increase.</returns>
|
||||
protected virtual float HealthIncreaseFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 10.2f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Judgements
|
||||
{
|
||||
public class CatchTinyDropletJudgement : CatchJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
protected override float HealthIncreaseFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case HitResult.Perfect:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
public class Banana : Fruit
|
||||
{
|
||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,5 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
public double EndTime => StartTime + Duration;
|
||||
|
||||
public double Duration { get; set; }
|
||||
|
||||
public class Banana : Fruit
|
||||
{
|
||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableBanana : DrawableFruit
|
||||
{
|
||||
public DrawableBanana(Banana h)
|
||||
: base(h)
|
||||
{
|
||||
}
|
||||
|
||||
protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,7 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@@ -24,15 +22,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
|
||||
InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>())
|
||||
foreach (var b in s.NestedHitObjects.Cast<Banana>())
|
||||
AddNested(getVisualRepresentation?.Invoke(b));
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (timeOffset >= 0)
|
||||
AddJudgement(new Judgement { Result = NestedHitObjects.Cast<DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
|
||||
}
|
||||
protected override bool ProvidesJudgement => false;
|
||||
|
||||
protected override void AddNested(DrawableHitObject h)
|
||||
{
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@@ -58,9 +58,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
if (CheckPosition == null) return;
|
||||
|
||||
if (timeOffset >= 0)
|
||||
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
|
||||
{
|
||||
var judgement = CreateJudgement();
|
||||
judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
|
||||
AddJudgement(judgement);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@@ -23,6 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
Masking = false;
|
||||
}
|
||||
|
||||
protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableTinyDroplet : DrawableDroplet
|
||||
{
|
||||
public DrawableTinyDroplet(Droplet h)
|
||||
: base(h)
|
||||
{
|
||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
|
||||
}
|
||||
|
||||
protected override CatchJudgement CreateJudgement() => new CatchTinyDropletJudgement();
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
return;
|
||||
}
|
||||
|
||||
if (h is BananaShower.Banana)
|
||||
if (h is Banana)
|
||||
{
|
||||
// auto bananas unrealistically warp to catch 100% combo.
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
@@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
{
|
||||
switch (nestedObj)
|
||||
{
|
||||
case BananaShower.Banana _:
|
||||
case Banana _:
|
||||
case TinyDroplet _:
|
||||
case Droplet _:
|
||||
case Fruit _:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright (c) 2007-2018 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.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
@@ -17,28 +19,57 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
||||
{
|
||||
}
|
||||
|
||||
private float hpDrainRate;
|
||||
|
||||
protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
|
||||
{
|
||||
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
||||
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case JuiceStream stream:
|
||||
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
foreach (var nestedObject in stream.NestedHitObjects)
|
||||
switch (nestedObject)
|
||||
{
|
||||
case TinyDroplet _:
|
||||
AddJudgement(new CatchTinyDropletJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
case Droplet _:
|
||||
AddJudgement(new CatchDropletJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
case Fruit _:
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BananaShower shower:
|
||||
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
AddJudgement(new CatchBananaJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
case Fruit _:
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.SimulateAutoplay(beatmap);
|
||||
private const double harshness = 0.01;
|
||||
|
||||
protected override void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
base.OnNewJudgement(judgement);
|
||||
|
||||
if (judgement.Result == HitResult.Miss)
|
||||
{
|
||||
if (!judgement.IsBonus)
|
||||
Health.Value -= hpDrainRate * (harshness * 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (judgement is CatchJudgement catchJudgement)
|
||||
Health.Value += Math.Max(catchJudgement.HealthIncrease - hpDrainRate, 0) * harshness;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private readonly CatcherArea catcherArea;
|
||||
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation)
|
||||
: base(ScrollingDirection.Down, BASE_WIDTH)
|
||||
: base(BASE_WIDTH)
|
||||
{
|
||||
Direction.Value = ScrollingDirection.Down;
|
||||
|
||||
Container explodingFruitContainer;
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
|
||||
@@ -38,14 +38,16 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
switch (h)
|
||||
{
|
||||
case Banana banana:
|
||||
return new DrawableBanana(banana);
|
||||
case Fruit fruit:
|
||||
return new DrawableFruit(fruit);
|
||||
case JuiceStream stream:
|
||||
return new DrawableJuiceStream(stream, GetVisualRepresentation);
|
||||
case BananaShower banana:
|
||||
return new DrawableBananaShower(banana, GetVisualRepresentation);
|
||||
case BananaShower shower:
|
||||
return new DrawableBananaShower(shower, GetVisualRepresentation);
|
||||
case TinyDroplet tiny:
|
||||
return new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) };
|
||||
return new DrawableTinyDroplet(tiny);
|
||||
case Droplet droplet:
|
||||
return new DrawableDroplet(droplet);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
@@ -51,6 +52,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
void runAfterLoaded(Action action)
|
||||
{
|
||||
if (lastPlateableFruit == null)
|
||||
return;
|
||||
|
||||
// this is required to make this run after the last caught fruit runs UpdateState at least once.
|
||||
// TODO: find a better alternative
|
||||
if (lastPlateableFruit.IsLoaded)
|
||||
@@ -78,12 +82,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (!fruit.StaysOnPlate)
|
||||
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
|
||||
|
||||
}
|
||||
|
||||
if (fruit.HitObject.LastInCombo)
|
||||
{
|
||||
if (judgement.IsHit)
|
||||
if (((CatchJudgement)judgement).ShouldExplode)
|
||||
runAfterLoaded(() => MovableCatcher.Explode());
|
||||
else
|
||||
MovableCatcher.Drop();
|
||||
@@ -255,11 +258,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition;
|
||||
double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
|
||||
|
||||
SetHyperdashState(Math.Abs(velocity), target.X);
|
||||
SetHyperDashState(Math.Abs(velocity), target.X);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetHyperdashState();
|
||||
SetHyperDashState();
|
||||
}
|
||||
|
||||
return validCatch;
|
||||
@@ -270,18 +273,18 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private float hyperDashTargetPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we are hypderdashing or not.
|
||||
/// Whether we are hyper-dashing or not.
|
||||
/// </summary>
|
||||
public bool HyperDashing => hyperDashModifier != 1;
|
||||
|
||||
/// <summary>
|
||||
/// Set hyperdash state.
|
||||
/// Set hyper-dash state.
|
||||
/// </summary>
|
||||
/// <param name="modifier">The speed multiplier. If this is less or equals to 1, this catcher will be non-hyperdashing state.</param>
|
||||
/// <param name="targetPosition">When this catcher crosses this position, this catcher ends hyperdashing.</param>
|
||||
public void SetHyperdashState(double modifier = 1, float targetPosition = -1)
|
||||
/// <param name="modifier">The speed multiplier. If this is less or equals to 1, this catcher will be non-hyper-dashing state.</param>
|
||||
/// <param name="targetPosition">When this catcher crosses this position, this catcher ends hyper-dashing.</param>
|
||||
public void SetHyperDashState(double modifier = 1, float targetPosition = -1)
|
||||
{
|
||||
const float hyperdash_transition_length = 180;
|
||||
const float hyper_dash_transition_length = 180;
|
||||
|
||||
bool previouslyHyperDashing = HyperDashing;
|
||||
if (modifier <= 1 || X == targetPosition)
|
||||
@@ -291,8 +294,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (previouslyHyperDashing)
|
||||
{
|
||||
this.FadeColour(Color4.White, hyperdash_transition_length, Easing.OutQuint);
|
||||
this.FadeTo(1, hyperdash_transition_length, Easing.OutQuint);
|
||||
this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
|
||||
this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -303,8 +306,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (!previouslyHyperDashing)
|
||||
{
|
||||
this.FadeColour(Color4.OrangeRed, hyperdash_transition_length, Easing.OutQuint);
|
||||
this.FadeTo(0.2f, hyperdash_transition_length, Easing.OutQuint);
|
||||
this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint);
|
||||
this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
|
||||
Trail = true;
|
||||
}
|
||||
}
|
||||
@@ -370,7 +373,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
hyperDashDirection < 0 && hyperDashTargetPosition > X)
|
||||
{
|
||||
X = hyperDashTargetPosition;
|
||||
SetHyperdashState();
|
||||
SetHyperDashState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -5,6 +5,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@@ -13,11 +15,10 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||
|
||||
[NonParallelizable]
|
||||
[TestCase("basic")]
|
||||
public new void Test(string name)
|
||||
{
|
||||
@@ -34,9 +35,35 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
};
|
||||
}
|
||||
|
||||
protected override ManiaConvertMapping CreateConvertMapping() => new ManiaConvertMapping(Converter);
|
||||
|
||||
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||
}
|
||||
|
||||
public class ManiaConvertMapping : ConvertMapping<ConvertValue>, IEquatable<ManiaConvertMapping>
|
||||
{
|
||||
public uint RandomW;
|
||||
public uint RandomX;
|
||||
public uint RandomY;
|
||||
public uint RandomZ;
|
||||
|
||||
public ManiaConvertMapping()
|
||||
{
|
||||
}
|
||||
|
||||
public ManiaConvertMapping(IBeatmapConverter converter)
|
||||
{
|
||||
var maniaConverter = (ManiaBeatmapConverter)converter;
|
||||
RandomW = maniaConverter.Random.W;
|
||||
RandomX = maniaConverter.Random.X;
|
||||
RandomY = maniaConverter.Random.Y;
|
||||
RandomZ = maniaConverter.Random.Z;
|
||||
}
|
||||
|
||||
public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
|
||||
public override bool Equals(ConvertMapping<ConvertValue> other) => base.Equals(other) && Equals(other as ManiaConvertMapping);
|
||||
}
|
||||
|
||||
public struct ConvertValue : IEquatable<ConvertValue>
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }});
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
|
||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
columns[i].Add(new DrawableNote(obj, columns[i].Action));
|
||||
columns[i].Add(new DrawableNote(obj));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,19 +80,19 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
|
||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
columns[i].Add(new DrawableHoldNote(obj, columns[i].Action));
|
||||
columns[i].Add(new DrawableHoldNote(obj));
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable createColumn(ScrollingDirection direction, ManiaAction action)
|
||||
{
|
||||
var column = new Column(direction)
|
||||
var column = new Column
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Height = 0.85f,
|
||||
AccentColour = Color4.OrangeRed,
|
||||
Action = action,
|
||||
Action = { Value = action },
|
||||
VisibleTimeRange = { Value = 2000 }
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@@ -61,9 +62,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
return new ScrollingTestContainer(direction)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}")
|
||||
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = new DrawableNote(note, ManiaAction.Key1) { AccentColour = Color4.OrangeRed }
|
||||
Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -76,9 +77,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
return new ScrollingTestContainer(direction)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}")
|
||||
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = new DrawableHoldNote(note, ManiaAction.Key1)
|
||||
Child = new DrawableHoldNote(note)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
AccentColour = Color4.OrangeRed,
|
||||
@@ -136,6 +137,13 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
};
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
@@ -145,9 +153,6 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
if (!(obj.HitObject is IHasEndTime endTime))
|
||||
continue;
|
||||
|
||||
if (!obj.HasNestedHitObjects)
|
||||
continue;
|
||||
|
||||
foreach (var nested in obj.NestedHitObjects)
|
||||
{
|
||||
double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
|
||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
stage.Add(new DrawableNote(obj, stage.Columns[i].Action));
|
||||
stage.Add(new DrawableNote(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
|
||||
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
stage.Add(new DrawableHoldNote(obj, stage.Columns[i].Action));
|
||||
stage.Add(new DrawableHoldNote(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
var specialAction = ManiaAction.Special1;
|
||||
|
||||
var stage = new ManiaStage(direction, 0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) { VisibleTimeRange = { Value = 2000 } };
|
||||
var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) { VisibleTimeRange = { Value = 2000 } };
|
||||
stages.Add(stage);
|
||||
|
||||
return new ScrollingTestContainer(direction)
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
|
||||
@@ -5,6 +5,7 @@ using osu.Game.Rulesets.Mania.Objects;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@@ -28,8 +29,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
public int TargetColumns;
|
||||
public readonly bool IsForCurrentRuleset;
|
||||
|
||||
// Internal for testing purposes
|
||||
internal FastRandom Random { get; private set; }
|
||||
|
||||
private Pattern lastPattern = new Pattern();
|
||||
private FastRandom random;
|
||||
|
||||
private ManiaBeatmap beatmap;
|
||||
|
||||
@@ -62,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
||||
|
||||
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
|
||||
random = new FastRandom(seed);
|
||||
Random = new FastRandom(seed);
|
||||
|
||||
return base.ConvertBeatmap(original);
|
||||
}
|
||||
@@ -100,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
|
||||
private double lastTime;
|
||||
private Vector2 lastPosition;
|
||||
private PatternType lastStair;
|
||||
private PatternType lastStair = PatternType.Stair;
|
||||
private void recordNote(double time, Vector2 position)
|
||||
{
|
||||
lastTime = time;
|
||||
@@ -115,12 +118,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// <returns>The hit objects generated.</returns>
|
||||
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap)
|
||||
{
|
||||
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
|
||||
var generator = new SpecificBeatmapPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap);
|
||||
|
||||
Pattern newPattern = generator.Generate();
|
||||
lastPattern = newPattern;
|
||||
foreach (var newPattern in generator.Generate())
|
||||
{
|
||||
lastPattern = newPattern;
|
||||
|
||||
return newPattern.HitObjects;
|
||||
foreach (var obj in newPattern.HitObjects)
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -138,27 +144,44 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
Patterns.PatternGenerator conversion = null;
|
||||
|
||||
if (distanceData != null)
|
||||
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
|
||||
{
|
||||
var generator = new DistanceObjectPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap);
|
||||
conversion = generator;
|
||||
|
||||
for (double time = original.StartTime; !Precision.DefinitelyBigger(time, generator.EndTime); time += generator.SegmentDuration)
|
||||
{
|
||||
recordNote(time, positionData?.Position ?? Vector2.Zero);
|
||||
computeDensity(time);
|
||||
}
|
||||
}
|
||||
else if (endTimeData != null)
|
||||
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, originalBeatmap);
|
||||
{
|
||||
conversion = new EndTimeObjectPatternGenerator(Random, original, beatmap, originalBeatmap);
|
||||
|
||||
recordNote(endTimeData.EndTime, new Vector2(256, 192));
|
||||
computeDensity(endTimeData.EndTime);
|
||||
}
|
||||
else if (positionData != null)
|
||||
{
|
||||
computeDensity(original.StartTime);
|
||||
|
||||
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
|
||||
conversion = new HitObjectPatternGenerator(Random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap);
|
||||
|
||||
recordNote(original.StartTime, positionData.Position);
|
||||
}
|
||||
|
||||
if (conversion == null)
|
||||
return null;
|
||||
yield break;
|
||||
|
||||
Pattern newPattern = conversion.Generate();
|
||||
foreach (var newPattern in conversion.Generate())
|
||||
{
|
||||
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
|
||||
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
|
||||
|
||||
lastPattern = conversion is EndTimeObjectPatternGenerator ? lastPattern : newPattern;
|
||||
lastStair = (conversion as HitObjectPatternGenerator)?.StairType ?? lastStair;
|
||||
foreach (var obj in newPattern.HitObjects)
|
||||
yield return obj;
|
||||
|
||||
return newPattern.HitObjects;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -171,7 +194,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
{
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
public override IEnumerable<Pattern> Generate()
|
||||
{
|
||||
yield return generate();
|
||||
}
|
||||
|
||||
private Pattern generate()
|
||||
{
|
||||
var endTimeData = HitObject as IHasEndTime;
|
||||
var positionData = HitObject as IHasXPosition;
|
||||
|
||||
+62
-32
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
@@ -24,8 +25,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
/// </summary>
|
||||
private const float osu_base_scoring_distance = 100;
|
||||
|
||||
private readonly double endTime;
|
||||
private readonly double segmentDuration;
|
||||
public readonly double EndTime;
|
||||
public readonly double SegmentDuration;
|
||||
|
||||
private readonly int spanCount;
|
||||
|
||||
private PatternType convertType;
|
||||
@@ -52,77 +54,105 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
// The duration of the osu! hit object
|
||||
double osuDuration = distance / osuVelocity;
|
||||
|
||||
endTime = hitObject.StartTime + osuDuration;
|
||||
segmentDuration = (endTime - HitObject.StartTime) / spanCount;
|
||||
EndTime = hitObject.StartTime + osuDuration;
|
||||
SegmentDuration = (EndTime - HitObject.StartTime) / spanCount;
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
public override IEnumerable<Pattern> Generate()
|
||||
{
|
||||
var originalPattern = generate();
|
||||
|
||||
if (originalPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
yield return originalPattern;
|
||||
yield break;
|
||||
}
|
||||
|
||||
// We need to split the intermediate pattern into two new patterns:
|
||||
// 1. A pattern containing all objects that do not end at our EndTime.
|
||||
// 2. A pattern containing all objects that end at our EndTime. This will be used for further pattern generation.
|
||||
var intermediatePattern = new Pattern();
|
||||
var endTimePattern = new Pattern();
|
||||
|
||||
foreach (var obj in originalPattern.HitObjects)
|
||||
{
|
||||
if (!Precision.AlmostEquals(EndTime, (obj as IHasEndTime)?.EndTime ?? obj.StartTime))
|
||||
intermediatePattern.Add(obj);
|
||||
else
|
||||
endTimePattern.Add(obj);
|
||||
}
|
||||
|
||||
yield return intermediatePattern;
|
||||
yield return endTimePattern;
|
||||
}
|
||||
|
||||
private Pattern generate()
|
||||
{
|
||||
if (TotalColumns == 1)
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
addToPattern(pattern, 0, HitObject.StartTime, endTime);
|
||||
addToPattern(pattern, 0, HitObject.StartTime, EndTime);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (spanCount > 1)
|
||||
{
|
||||
if (segmentDuration <= 90)
|
||||
if (SegmentDuration <= 90)
|
||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||
|
||||
if (segmentDuration <= 120)
|
||||
if (SegmentDuration <= 120)
|
||||
{
|
||||
convertType |= PatternType.ForceNotStack;
|
||||
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
||||
}
|
||||
|
||||
if (segmentDuration <= 160)
|
||||
if (SegmentDuration <= 160)
|
||||
return generateStair(HitObject.StartTime);
|
||||
|
||||
if (segmentDuration <= 200 && ConversionDifficulty > 3)
|
||||
if (SegmentDuration <= 200 && ConversionDifficulty > 3)
|
||||
return generateRandomMultipleNotes(HitObject.StartTime);
|
||||
|
||||
double duration = endTime - HitObject.StartTime;
|
||||
double duration = EndTime - HitObject.StartTime;
|
||||
if (duration >= 4000)
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
||||
|
||||
if (segmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
||||
if (SegmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
||||
return generateTiledHoldNotes(HitObject.StartTime);
|
||||
|
||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||
}
|
||||
|
||||
if (segmentDuration <= 110)
|
||||
if (SegmentDuration <= 110)
|
||||
{
|
||||
if (PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
convertType |= PatternType.ForceNotStack;
|
||||
else
|
||||
convertType &= ~PatternType.ForceNotStack;
|
||||
return generateRandomNotes(HitObject.StartTime, segmentDuration < 80 ? 1 : 2);
|
||||
return generateRandomNotes(HitObject.StartTime, SegmentDuration < 80 ? 1 : 2);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 6.5)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.78, 0.3, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.85, 0.36, 0.03);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 4)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.43, 0.08, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.56, 0.18, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 2.5)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.3, 0, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.37, 0.08, 0);
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.17, 0, 0);
|
||||
return generateNRandomNotes(HitObject.StartTime, 0.27, 0, 0);
|
||||
}
|
||||
@@ -148,7 +178,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
}
|
||||
|
||||
// This is can't be combined with the above loop due to RNG
|
||||
@@ -156,7 +186,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@@ -179,7 +209,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
var pattern = new Pattern();
|
||||
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
@@ -193,7 +223,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
|
||||
lastColumn = nextColumn;
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@@ -223,7 +253,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
for (int i = 0; i <= spanCount; i++)
|
||||
{
|
||||
addToPattern(pattern, column, startTime, startTime);
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
|
||||
// Check if we're at the borders of the stage, and invert the pattern if so
|
||||
if (increasing)
|
||||
@@ -284,7 +314,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@@ -331,7 +361,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
bool isDoubleSample(SampleInfo sample) => sample.Name == SampleInfo.HIT_CLAP || sample.Name == SampleInfo.HIT_FINISH;
|
||||
|
||||
bool canGenerateTwoNotes = (convertType & PatternType.LowProbability) == 0;
|
||||
bool canGenerateTwoNotes = !convertType.HasFlag(PatternType.LowProbability);
|
||||
canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample);
|
||||
|
||||
if (canGenerateTwoNotes)
|
||||
@@ -361,7 +391,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
||||
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
@@ -372,8 +402,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
|
||||
addToPattern(pattern, nextColumn, startTime, endTime);
|
||||
startTime += segmentDuration;
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@@ -395,14 +425,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
var pattern = new Pattern();
|
||||
|
||||
int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(holdColumn))
|
||||
holdColumn = Random.Next(RandomStart, TotalColumns);
|
||||
}
|
||||
|
||||
// Create the hold note
|
||||
addToPattern(pattern, holdColumn, startTime, endTime);
|
||||
addToPattern(pattern, holdColumn, startTime, EndTime);
|
||||
|
||||
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
int noteCount;
|
||||
@@ -434,7 +464,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
pattern.Add(rowPattern);
|
||||
rowPattern.Clear();
|
||||
|
||||
startTime += segmentDuration;
|
||||
startTime += SegmentDuration;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@@ -452,7 +482,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
if (curveData == null)
|
||||
return HitObject.Samples;
|
||||
|
||||
double segmentTime = (endTime - HitObject.StartTime) / spanCount;
|
||||
double segmentTime = (EndTime - HitObject.StartTime) / spanCount;
|
||||
|
||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||
return curveData.RepeatSamples[index];
|
||||
|
||||
@@ -19,26 +19,33 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap)
|
||||
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
|
||||
{
|
||||
var endtimeData = HitObject as IHasEndTime;
|
||||
|
||||
endTime = endtimeData?.EndTime ?? 0;
|
||||
endTime = (HitObject as IHasEndTime)?.EndTime ?? 0;
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
public override IEnumerable<Pattern> Generate()
|
||||
{
|
||||
yield return generate();
|
||||
}
|
||||
|
||||
private Pattern generate()
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
|
||||
bool generateHold = endTime - HitObject.StartTime >= 100;
|
||||
|
||||
if (TotalColumns == 8)
|
||||
switch (TotalColumns)
|
||||
{
|
||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000)
|
||||
case 8 when HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000:
|
||||
addToPattern(pattern, 0, generateHold);
|
||||
else
|
||||
break;
|
||||
case 8:
|
||||
addToPattern(pattern, getNextRandomColumn(RandomStart), generateHold);
|
||||
break;
|
||||
default:
|
||||
if (TotalColumns > 0)
|
||||
addToPattern(pattern, getNextRandomColumn(0), generateHold);
|
||||
break;
|
||||
}
|
||||
else if (TotalColumns > 0)
|
||||
addToPattern(pattern, getNextRandomColumn(0), generateHold);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using osu.Game.Audio;
|
||||
@@ -20,7 +21,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
private readonly PatternType convertType;
|
||||
|
||||
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair, IBeatmap originalBeatmap)
|
||||
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density,
|
||||
PatternType lastStair, IBeatmap originalBeatmap)
|
||||
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
||||
{
|
||||
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
|
||||
@@ -78,131 +80,137 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
else
|
||||
convertType |= PatternType.LowProbability;
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) == 0)
|
||||
if (!convertType.HasFlag(PatternType.KeepSingle))
|
||||
{
|
||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
|
||||
convertType |= PatternType.Mirror;
|
||||
else
|
||||
else if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP))
|
||||
convertType |= PatternType.Gathered;
|
||||
}
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
public override IEnumerable<Pattern> Generate()
|
||||
{
|
||||
if (TotalColumns == 1)
|
||||
yield return generate();
|
||||
}
|
||||
|
||||
private Pattern generate()
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
|
||||
try
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
addToPattern(pattern, 0);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
|
||||
|
||||
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
// Generate a new pattern by copying the last hit objects in reverse-column order
|
||||
var pattern = new Pattern();
|
||||
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
if (PreviousPattern.ColumnHasObject(i))
|
||||
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.Cycle) > 0 && PreviousPattern.HitObjects.Count() == 1
|
||||
// If we convert to 7K + 1, let's not overload the special key
|
||||
&& (TotalColumns != 8 || lastColumn != 0)
|
||||
// Make sure the last column was not the centre column
|
||||
&& (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
|
||||
{
|
||||
// Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object)
|
||||
var pattern = new Pattern();
|
||||
|
||||
int column = RandomStart + TotalColumns - lastColumn - 1;
|
||||
addToPattern(pattern, column);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.ForceStack) > 0 && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
// Generate a new pattern by placing on the already filled columns
|
||||
var pattern = new Pattern();
|
||||
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
if (PreviousPattern.ColumnHasObject(i))
|
||||
addToPattern(pattern, i);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.Stair) > 0 && PreviousPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
// Generate a new pattern by placing on the next column, cycling back to the start if there is no "next"
|
||||
var pattern = new Pattern();
|
||||
|
||||
int targetColumn = lastColumn + 1;
|
||||
if (targetColumn == TotalColumns)
|
||||
if (TotalColumns == 1)
|
||||
{
|
||||
targetColumn = RandomStart;
|
||||
StairType = PatternType.ReverseStair;
|
||||
addToPattern(pattern, 0);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
|
||||
|
||||
if ((convertType & PatternType.ReverseStair) > 0 && PreviousPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
|
||||
var pattern = new Pattern();
|
||||
|
||||
int targetColumn = lastColumn - 1;
|
||||
if (targetColumn == RandomStart - 1)
|
||||
if (convertType.HasFlag(PatternType.Reverse) && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
targetColumn = TotalColumns - 1;
|
||||
StairType = PatternType.Stair;
|
||||
// Generate a new pattern by copying the last hit objects in reverse-column order
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
if (PreviousPattern.ColumnHasObject(i))
|
||||
addToPattern(pattern, RandomStart + TotalColumns - i - 1);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
if (convertType.HasFlag(PatternType.Cycle) && PreviousPattern.HitObjects.Count() == 1
|
||||
// If we convert to 7K + 1, let's not overload the special key
|
||||
&& (TotalColumns != 8 || lastColumn != 0)
|
||||
// Make sure the last column was not the centre column
|
||||
&& (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2))
|
||||
{
|
||||
// Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object)
|
||||
int column = RandomStart + TotalColumns - lastColumn - 1;
|
||||
addToPattern(pattern, column);
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) > 0)
|
||||
return generateRandomNotes(1);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (convertType.HasFlag(PatternType.ForceStack) && PreviousPattern.HitObjects.Any())
|
||||
{
|
||||
// Generate a new pattern by placing on the already filled columns
|
||||
for (int i = RandomStart; i < TotalColumns; i++)
|
||||
if (PreviousPattern.ColumnHasObject(i))
|
||||
addToPattern(pattern, i);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (PreviousPattern.HitObjects.Count() == 1)
|
||||
{
|
||||
if (convertType.HasFlag(PatternType.Stair))
|
||||
{
|
||||
// Generate a new pattern by placing on the next column, cycling back to the start if there is no "next"
|
||||
int targetColumn = lastColumn + 1;
|
||||
if (targetColumn == TotalColumns)
|
||||
targetColumn = RandomStart;
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (convertType.HasFlag(PatternType.ReverseStair))
|
||||
{
|
||||
// Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous"
|
||||
int targetColumn = lastColumn - 1;
|
||||
if (targetColumn == RandomStart - 1)
|
||||
targetColumn = TotalColumns - 1;
|
||||
|
||||
addToPattern(pattern, targetColumn);
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
if (convertType.HasFlag(PatternType.KeepSingle))
|
||||
return pattern = generateRandomNotes(1);
|
||||
|
||||
if (convertType.HasFlag(PatternType.Mirror))
|
||||
{
|
||||
if (ConversionDifficulty > 6.5)
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
|
||||
if (ConversionDifficulty > 4)
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0.17, 0);
|
||||
return pattern = generateRandomPatternWithMirrored(0.12, 0, 0);
|
||||
}
|
||||
|
||||
if ((convertType & PatternType.Mirror) > 0)
|
||||
{
|
||||
if (ConversionDifficulty > 6.5)
|
||||
return generateRandomPatternWithMirrored(0.12, 0.38, 0.12);
|
||||
{
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return pattern = generateRandomPattern(0.78, 0.42, 0, 0);
|
||||
return pattern = generateRandomPattern(1, 0.62, 0, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 4)
|
||||
return generateRandomPatternWithMirrored(0.12, 0.17, 0);
|
||||
return generateRandomPatternWithMirrored(0.12, 0, 0);
|
||||
}
|
||||
{
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return pattern = generateRandomPattern(0.35, 0.08, 0, 0);
|
||||
return pattern = generateRandomPattern(0.52, 0.15, 0, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 6.5)
|
||||
if (ConversionDifficulty > 2)
|
||||
{
|
||||
if (convertType.HasFlag(PatternType.LowProbability))
|
||||
return pattern = generateRandomPattern(0.18, 0, 0, 0);
|
||||
return pattern = generateRandomPattern(0.45, 0, 0, 0);
|
||||
}
|
||||
|
||||
return pattern = generateRandomPattern(0, 0, 0, 0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
return generateRandomPattern(0.78, 0.42, 0, 0);
|
||||
return generateRandomPattern(1, 0.62, 0, 0);
|
||||
foreach (var obj in pattern.HitObjects)
|
||||
{
|
||||
if (convertType.HasFlag(PatternType.Stair) && obj.Column == TotalColumns - 1)
|
||||
StairType = PatternType.ReverseStair;
|
||||
if (convertType.HasFlag(PatternType.ReverseStair) && obj.Column == RandomStart)
|
||||
StairType = PatternType.Stair;
|
||||
}
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 4)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
return generateRandomPattern(0.35, 0.08, 0, 0);
|
||||
return generateRandomPattern(0.52, 0.15, 0, 0);
|
||||
}
|
||||
|
||||
if (ConversionDifficulty > 2)
|
||||
{
|
||||
if ((convertType & PatternType.LowProbability) > 0)
|
||||
return generateRandomPattern(0.18, 0, 0, 0);
|
||||
return generateRandomPattern(0.45, 0, 0, 0);
|
||||
}
|
||||
|
||||
return generateRandomPattern(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -218,7 +226,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
|
||||
bool allowStacking = (convertType & PatternType.ForceNotStack) == 0;
|
||||
bool allowStacking = !convertType.HasFlag(PatternType.ForceNotStack);
|
||||
|
||||
if (!allowStacking)
|
||||
noteCount = Math.Min(noteCount, TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects);
|
||||
@@ -228,7 +236,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking)
|
||||
{
|
||||
if ((convertType & PatternType.Gathered) > 0)
|
||||
if (convertType.HasFlag(PatternType.Gathered))
|
||||
{
|
||||
nextColumn++;
|
||||
if (nextColumn == TotalColumns)
|
||||
@@ -360,7 +368,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
addToCentre = false;
|
||||
|
||||
if ((convertType & PatternType.ForceNotStack) > 0)
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack))
|
||||
return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3);
|
||||
|
||||
switch (TotalColumns)
|
||||
|
||||
@@ -103,17 +103,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault();
|
||||
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault();
|
||||
|
||||
double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0);
|
||||
drainTime -= OriginalBeatmap.TotalBreakTime;
|
||||
// Drain time in seconds
|
||||
int drainTime = (int)(((lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0) - OriginalBeatmap.TotalBreakTime) / 1000);
|
||||
|
||||
if (drainTime == 0)
|
||||
drainTime = 10000000;
|
||||
|
||||
// We need this in seconds
|
||||
drainTime /= 1000;
|
||||
drainTime = 10000;
|
||||
|
||||
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
||||
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
|
||||
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
|
||||
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
||||
|
||||
return conversionDifficulty.Value;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
@@ -42,9 +43,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the pattern for <see cref="HitObject"/>, filled with hit objects.
|
||||
/// Generates the patterns for <see cref="HitObject"/>, each filled with hit objects.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
|
||||
public abstract Pattern Generate();
|
||||
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
||||
public abstract IEnumerable<Pattern> Generate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mania.Judgements
|
||||
public class HoldNoteJudgement : ManiaJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ namespace osu.Game.Rulesets.Mania
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ManiaConfigManager config)
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsEnumDropdown<ManiaScrollingDirection>
|
||||
{
|
||||
LabelText = "Scrolling direction",
|
||||
Bindable = config.GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
|
||||
Bindable = ((ManiaConfigManager)Config).GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,11 +15,15 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
private const uint y = 842502087;
|
||||
private const uint z = 3579807591;
|
||||
private const uint w = 273326509;
|
||||
private uint _x, _y = y, _z = z, _w = w;
|
||||
|
||||
internal uint X { get; private set; }
|
||||
internal uint Y { get; private set; } = y;
|
||||
internal uint Z { get; private set; } = z;
|
||||
internal uint W { get; private set; } = w;
|
||||
|
||||
public FastRandom(int seed)
|
||||
{
|
||||
_x = (uint)seed;
|
||||
X = (uint)seed;
|
||||
}
|
||||
|
||||
public FastRandom()
|
||||
@@ -33,11 +37,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
/// <returns>The random value.</returns>
|
||||
public uint NextUInt()
|
||||
{
|
||||
uint t = _x ^ _x << 11;
|
||||
_x = _y;
|
||||
_y = _z;
|
||||
_z = _w;
|
||||
return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
|
||||
uint t = X ^ X << 11;
|
||||
X = Y;
|
||||
Y = Z;
|
||||
Z = W;
|
||||
return W = W ^ W >> 19 ^ t ^ t >> 8;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -38,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
||||
|
||||
public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
|
||||
: base(hitObject, action)
|
||||
public DrawableHoldNote(HoldNote hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
@@ -57,12 +57,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
HoldStartTime = () => holdStartTime
|
||||
})
|
||||
},
|
||||
head = new DrawableHeadNote(this, action)
|
||||
head = new DrawableHeadNote(this)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
},
|
||||
tail = new DrawableTailNote(this, action)
|
||||
tail = new DrawableTailNote(this)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
@@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
||||
return false;
|
||||
|
||||
if (action != Action)
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
||||
@@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (!holdStartTime.HasValue)
|
||||
return false;
|
||||
|
||||
if (action != Action)
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
holdStartTime = null;
|
||||
@@ -154,8 +154,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
private readonly DrawableHoldNote holdNote;
|
||||
|
||||
public DrawableHeadNote(DrawableHoldNote holdNote, ManiaAction action)
|
||||
: base(holdNote.HitObject.Head, action)
|
||||
public DrawableHeadNote(DrawableHoldNote holdNote)
|
||||
: base(holdNote.HitObject.Head)
|
||||
{
|
||||
this.holdNote = holdNote;
|
||||
}
|
||||
@@ -191,8 +191,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
private readonly DrawableHoldNote holdNote;
|
||||
|
||||
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
||||
: base(holdNote.HitObject.Tail, action)
|
||||
public DrawableTailNote(DrawableHoldNote holdNote)
|
||||
: base(holdNote.HitObject.Tail)
|
||||
{
|
||||
this.holdNote = holdNote;
|
||||
}
|
||||
@@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (!holdNote.holdStartTime.HasValue)
|
||||
return false;
|
||||
|
||||
if (action != Action)
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
UpdateJudgement(true);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
@@ -10,30 +11,26 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject>
|
||||
where TObject : ManiaHitObject
|
||||
public abstract class DrawableManiaHitObject : DrawableHitObject<ManiaHitObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// The key that will trigger input for this hit object.
|
||||
/// The <see cref="ManiaAction"/> which causes this <see cref="DrawableManiaHitObject{TObject}"/> to be hit.
|
||||
/// </summary>
|
||||
protected ManiaAction Action { get; }
|
||||
|
||||
public new TObject HitObject;
|
||||
protected readonly IBindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||
|
||||
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null)
|
||||
protected DrawableManiaHitObject(ManiaHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
|
||||
if (action != null)
|
||||
Action = action.Value;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load([CanBeNull] IBindable<ManiaAction> action, [NotNull] IScrollingInfo scrollingInfo)
|
||||
{
|
||||
if (action != null)
|
||||
Action.BindTo(action);
|
||||
|
||||
Direction.BindTo(scrollingInfo.Direction);
|
||||
Direction.BindValueChanged(OnDirectionChanged, true);
|
||||
}
|
||||
@@ -42,6 +39,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
|
||||
where TObject : ManiaHitObject
|
||||
{
|
||||
public new readonly TObject HitObject;
|
||||
|
||||
protected DrawableManiaHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
private readonly NotePiece headPiece;
|
||||
|
||||
public DrawableNote(Note hitObject, ManiaAction action)
|
||||
: base(hitObject, action)
|
||||
public DrawableNote(Note hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
@@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
public virtual bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action != Action)
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
return UpdateJudgement(true);
|
||||
|
||||
@@ -56,10 +56,15 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
{
|
||||
foreach (var point in group)
|
||||
{
|
||||
if (point is HitPoint)
|
||||
actions.Add(columnActions[point.Column]);
|
||||
if (point is ReleasePoint)
|
||||
actions.Remove(columnActions[point.Column]);
|
||||
switch (point)
|
||||
{
|
||||
case HitPoint _:
|
||||
actions.Add(columnActions[point.Column]);
|
||||
break;
|
||||
case ReleasePoint _:
|
||||
actions.Remove(columnActions[point.Column]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray()));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Replays
|
||||
|
||||
+129
-100
@@ -1,103 +1,132 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 500,
|
||||
"Objects": [{
|
||||
"StartTime": 500,
|
||||
"EndTime": 2500,
|
||||
"Column": 0
|
||||
},
|
||||
{
|
||||
"StartTime": 1500,
|
||||
"EndTime": 2500,
|
||||
"Column": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"StartTime": 3000,
|
||||
"Objects": [{
|
||||
"StartTime": 3000,
|
||||
"EndTime": 4000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 4500,
|
||||
"Objects": [{
|
||||
"StartTime": 4500,
|
||||
"EndTime": 5500,
|
||||
"Column": 4
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 6000,
|
||||
"Objects": [{
|
||||
"StartTime": 6000,
|
||||
"EndTime": 6500,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 7000,
|
||||
"Objects": [{
|
||||
"StartTime": 7000,
|
||||
"EndTime": 8000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 8500,
|
||||
"Objects": [{
|
||||
"StartTime": 8500,
|
||||
"EndTime": 11000,
|
||||
"Column": 0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 11500,
|
||||
"Objects": [{
|
||||
"StartTime": 11500,
|
||||
"EndTime": 12000,
|
||||
"Column": 1
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 12500,
|
||||
"Objects": [{
|
||||
"StartTime": 12500,
|
||||
"EndTime": 16500,
|
||||
"Column": 4
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 17000,
|
||||
"Objects": [{
|
||||
"StartTime": 17000,
|
||||
"EndTime": 18000,
|
||||
"Column": 2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 18500,
|
||||
"Objects": [{
|
||||
"StartTime": 18500,
|
||||
"EndTime": 19450,
|
||||
"Column": 0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"StartTime": 19875,
|
||||
"Objects": [{
|
||||
"StartTime": 19875,
|
||||
"EndTime": 23875,
|
||||
"Column": 1
|
||||
},
|
||||
{
|
||||
"StartTime": 19875,
|
||||
"EndTime": 23875,
|
||||
"Column": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"RandomW": 2659373485,
|
||||
"RandomX": 3579807591,
|
||||
"RandomY": 273326509,
|
||||
"RandomZ": 272969173,
|
||||
"StartTime": 500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 500.0,
|
||||
"EndTime": 2500.0,
|
||||
"Column": 0
|
||||
}, {
|
||||
"StartTime": 1500.0,
|
||||
"EndTime": 2500.0,
|
||||
"Column": 1
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 3083803045,
|
||||
"RandomX": 273326509,
|
||||
"RandomY": 272969173,
|
||||
"RandomZ": 2659373485,
|
||||
"StartTime": 3000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 3000.0,
|
||||
"EndTime": 4000.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 4073554232,
|
||||
"RandomX": 272969173,
|
||||
"RandomY": 2659373485,
|
||||
"RandomZ": 3083803045,
|
||||
"StartTime": 4500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 4500.0,
|
||||
"EndTime": 5500.0,
|
||||
"Column": 4
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 3420401969,
|
||||
"RandomX": 2659373485,
|
||||
"RandomY": 3083803045,
|
||||
"RandomZ": 4073554232,
|
||||
"StartTime": 6000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 6000.0,
|
||||
"EndTime": 6500.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 1129881182,
|
||||
"RandomX": 3083803045,
|
||||
"RandomY": 4073554232,
|
||||
"RandomZ": 3420401969,
|
||||
"StartTime": 7000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 7000.0,
|
||||
"EndTime": 8000.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 315568458,
|
||||
"RandomX": 3420401969,
|
||||
"RandomY": 1129881182,
|
||||
"RandomZ": 2358617505,
|
||||
"StartTime": 8500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 8500.0,
|
||||
"EndTime": 11000.0,
|
||||
"Column": 0
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 548134043,
|
||||
"RandomX": 1129881182,
|
||||
"RandomY": 2358617505,
|
||||
"RandomZ": 315568458,
|
||||
"StartTime": 11500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 11500.0,
|
||||
"EndTime": 12000.0,
|
||||
"Column": 1
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 3979422122,
|
||||
"RandomX": 548134043,
|
||||
"RandomY": 2810584254,
|
||||
"RandomZ": 2250186050,
|
||||
"StartTime": 12500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 12500.0,
|
||||
"EndTime": 16500.0,
|
||||
"Column": 4
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 2466283411,
|
||||
"RandomX": 2810584254,
|
||||
"RandomY": 2250186050,
|
||||
"RandomZ": 3979422122,
|
||||
"StartTime": 17000.0,
|
||||
"Objects": [{
|
||||
"StartTime": 17000.0,
|
||||
"EndTime": 18000.0,
|
||||
"Column": 2
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 83157665,
|
||||
"RandomX": 2250186050,
|
||||
"RandomY": 3979422122,
|
||||
"RandomZ": 2466283411,
|
||||
"StartTime": 18500.0,
|
||||
"Objects": [{
|
||||
"StartTime": 18500.0,
|
||||
"EndTime": 19450.0,
|
||||
"Column": 0
|
||||
}]
|
||||
}, {
|
||||
"RandomW": 2383087700,
|
||||
"RandomX": 83157665,
|
||||
"RandomY": 2055150192,
|
||||
"RandomZ": 510071020,
|
||||
"StartTime": 19875.0,
|
||||
"Objects": [{
|
||||
"StartTime": 19875.0,
|
||||
"EndTime": 23875.0,
|
||||
"Column": 1
|
||||
}, {
|
||||
"StartTime": 19875.0,
|
||||
"EndTime": 23875.0,
|
||||
"Column": 0
|
||||
}]
|
||||
}]
|
||||
}
|
||||
@@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.UI.Components;
|
||||
@@ -19,21 +21,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private const float column_width = 45;
|
||||
private const float special_column_width = 70;
|
||||
|
||||
private ManiaAction action;
|
||||
|
||||
public ManiaAction Action
|
||||
{
|
||||
get => action;
|
||||
set
|
||||
{
|
||||
if (action == value)
|
||||
return;
|
||||
action = value;
|
||||
|
||||
background.Action = value;
|
||||
keyArea.Action = value;
|
||||
}
|
||||
}
|
||||
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||
|
||||
private readonly ColumnBackground background;
|
||||
private readonly ColumnKeyArea keyArea;
|
||||
@@ -44,8 +32,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
protected override Container<Drawable> Content => hitObjectArea;
|
||||
|
||||
public Column(ScrollingDirection direction)
|
||||
: base(direction)
|
||||
public Column()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = column_width;
|
||||
@@ -130,6 +117,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IBindable<ManiaAction>>(Action);
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a DrawableHitObject to this Playfield.
|
||||
/// </summary>
|
||||
@@ -144,7 +138,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (!judgement.IsHit || !judgedObject.DisplayJudgement)
|
||||
if (!judgement.IsHit || !judgedObject.DisplayJudgement || !DisplayJudgements)
|
||||
return;
|
||||
|
||||
explosionContainer.Add(new HitExplosion(judgedObject)
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||
{
|
||||
public ManiaAction Action;
|
||||
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
|
||||
|
||||
private Box background;
|
||||
private Box backgroundOverlay;
|
||||
@@ -25,8 +25,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
this.action.BindTo(action);
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
background = new Box
|
||||
@@ -91,14 +93,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == Action)
|
||||
if (action == this.action.Value)
|
||||
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnReleased(ManiaAction action)
|
||||
{
|
||||
if (action == Action)
|
||||
if (action == this.action.Value)
|
||||
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,15 +21,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
private const float key_icon_size = 10;
|
||||
private const float key_icon_corner_radius = 3;
|
||||
|
||||
public ManiaAction Action;
|
||||
|
||||
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container keyIcon;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
this.action.BindTo(action);
|
||||
|
||||
Drawable gradient;
|
||||
|
||||
InternalChildren = new[]
|
||||
@@ -107,14 +108,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == Action)
|
||||
if (action == this.action.Value)
|
||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnReleased(ManiaAction action)
|
||||
{
|
||||
if (action == Action)
|
||||
if (action == this.action.Value)
|
||||
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@@ -21,8 +19,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
|
||||
public ManiaPlayfield(ScrollingDirection direction, List<StageDefinition> stageDefinitions)
|
||||
: base(direction)
|
||||
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||
{
|
||||
if (stageDefinitions == null)
|
||||
throw new ArgumentNullException(nameof(stageDefinitions));
|
||||
@@ -42,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
int firstColumnIndex = 0;
|
||||
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||
{
|
||||
var newStage = new ManiaStage(direction, firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
newStage.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||
|
||||
playfieldGrid.Content[0][i] = newStage;
|
||||
@@ -76,10 +73,5 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
maniaConfig.BindWith(ManiaSetting.ScrollTime, VisibleTimeRange);
|
||||
}
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,24 +70,24 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ManiaConfigManager config)
|
||||
private void load()
|
||||
{
|
||||
BarLines.ForEach(Playfield.Add);
|
||||
|
||||
config.BindWith(ManiaSetting.ScrollDirection, configDirection);
|
||||
((ManiaConfigManager)Config).BindWith(ManiaSetting.ScrollDirection, configDirection);
|
||||
configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true);
|
||||
}
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo());
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(scrollingInfo.Direction, Beatmap.Stages)
|
||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@@ -101,17 +101,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
||||
{
|
||||
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
|
||||
|
||||
var holdNote = h as HoldNote;
|
||||
if (holdNote != null)
|
||||
return new DrawableHoldNote(holdNote, action);
|
||||
|
||||
var note = h as Note;
|
||||
if (note != null)
|
||||
return new DrawableNote(note, action);
|
||||
|
||||
return null;
|
||||
switch (h)
|
||||
{
|
||||
case HoldNote holdNote:
|
||||
return new DrawableHoldNote(holdNote);
|
||||
case Note note:
|
||||
return new DrawableNote(note);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
|
||||
|
||||
@@ -11,11 +11,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
public ManiaScrollingPlayfield(ScrollingDirection direction)
|
||||
: base(direction)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
|
||||
@@ -43,8 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
private readonly int firstColumnIndex;
|
||||
|
||||
public ManiaStage(ScrollingDirection direction, int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||
: base(direction)
|
||||
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||
{
|
||||
this.firstColumnIndex = firstColumnIndex;
|
||||
|
||||
@@ -124,10 +123,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
for (int i = 0; i < definition.Columns; i++)
|
||||
{
|
||||
var isSpecial = definition.IsSpecialColumn(i);
|
||||
var column = new Column(direction)
|
||||
var column = new Column
|
||||
{
|
||||
IsSpecial = isSpecial,
|
||||
Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++
|
||||
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
|
||||
};
|
||||
|
||||
AddColumn(column);
|
||||
@@ -164,7 +163,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (!judgedObject.DisplayJudgement)
|
||||
if (!judgedObject.DisplayJudgement || !DisplayJudgements)
|
||||
return;
|
||||
|
||||
judgements.Clear();
|
||||
|
||||
+4
-32
@@ -2,35 +2,7 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"name": "VisualTests (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -38,12 +10,12 @@
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"name": "VisualTests (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
@@ -51,7 +23,7 @@
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
+3
-43
@@ -4,43 +4,13 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Debug, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, msbuild)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -49,14 +19,13 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,16 +35,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
"restore"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"label": "Restore",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
public struct ConvertValue : IEquatable<ConvertValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// A sane value to account for osu!stable using ints everwhere.
|
||||
/// A sane value to account for osu!stable using <see cref="int"/>s everywhere.
|
||||
/// </summary>
|
||||
private const double conversion_lenience = 2;
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostProcess()
|
||||
public override void PreProcess()
|
||||
{
|
||||
base.PreProcess();
|
||||
applyStacking((Beatmap<OsuHitObject>)Beatmap);
|
||||
base.PostProcess();
|
||||
}
|
||||
|
||||
private void applyStacking(Beatmap<OsuHitObject> beatmap)
|
||||
@@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
continue;
|
||||
|
||||
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
|
||||
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
||||
|
||||
if (objectN.StartTime - endTime > stackThreshold)
|
||||
//We are no longer within stacking range of the next object.
|
||||
@@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
OsuHitObject objectI = beatmap.HitObjects[i];
|
||||
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
||||
|
||||
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
||||
|
||||
/* If this object is a hitcircle, then we enter this "special" case.
|
||||
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
||||
|
||||
@@ -61,19 +61,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
|
||||
|
||||
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
|
||||
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future
|
||||
double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
|
||||
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
|
||||
double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
|
||||
|
||||
int maxCombo = beatmap.HitObjects.Count();
|
||||
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
||||
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
|
||||
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||
|
||||
return new OsuDifficultyAttributes(mods, starRating)
|
||||
{
|
||||
AimStrain = aimRating,
|
||||
SpeedStrain = speedRating,
|
||||
ApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5,
|
||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||
MaxCombo = maxCombo
|
||||
};
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
public class OsuEditPlayfield : OsuPlayfield
|
||||
{
|
||||
protected override bool DisplayJudgements => false;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit
|
||||
@@ -16,8 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
}
|
||||
|
||||
protected override Playfield CreatePlayfield() => new OsuEditPlayfield();
|
||||
|
||||
protected override Vector2 PlayfieldArea => Vector2.One;
|
||||
|
||||
protected override CursorContainer CreateCursor() => null;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@@ -12,11 +11,6 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
||||
{
|
||||
public override HitResult MaxResult => HitResult.Great;
|
||||
|
||||
/// <summary>
|
||||
/// The positional hit offset.
|
||||
/// </summary>
|
||||
public Vector2 PositionOffset;
|
||||
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
||||
public class OsuSliderTailJudgement : OsuJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||
{
|
||||
void adjustFadeIn(OsuHitObject h) => h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier;
|
||||
void adjustFadeIn(OsuHitObject h) => h.TimeFadeIn = h.TimePreempt * fade_in_duration_multiplier;
|
||||
|
||||
foreach (var d in drawables.OfType<DrawableOsuHitObject>())
|
||||
{
|
||||
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
var h = d.HitObject;
|
||||
|
||||
var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadein;
|
||||
var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadeIn;
|
||||
var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier;
|
||||
|
||||
// new duration from completed fade in to end (before fading out)
|
||||
|
||||
@@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
@@ -20,27 +21,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Masking = true;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
CornerRadius = width / 2;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
Child = new SkinnableDrawable("Play/osu/followpoint", _ => new Container
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = Color4.White.Opacity(0.2f),
|
||||
Radius = 4,
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
Masking = true,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
CornerRadius = width / 2,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = Color4.White.Opacity(0.2f),
|
||||
Radius = 4,
|
||||
},
|
||||
Child = new Box
|
||||
{
|
||||
Size = new Vector2(width),
|
||||
Blending = BlendingMode.Additive,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
};
|
||||
}
|
||||
}, restrictSize: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
Vector2 distanceVector = endPosition - startPosition;
|
||||
int distance = (int)distanceVector.Length;
|
||||
float rotation = (float)Math.Atan2(distanceVector.Y, distanceVector.X);
|
||||
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
|
||||
double duration = endTime - startTime;
|
||||
|
||||
for (int d = (int)(PointDistance * 1.5); d < distance - PointDistance; d += PointDistance)
|
||||
@@ -96,12 +96,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||
{
|
||||
fp.FadeIn(currHitObject.TimeFadein);
|
||||
fp.ScaleTo(1, currHitObject.TimeFadein, Easing.Out);
|
||||
fp.FadeIn(currHitObject.TimeFadeIn);
|
||||
fp.ScaleTo(1, currHitObject.TimeFadeIn, Easing.Out);
|
||||
|
||||
fp.MoveTo(pointEndPosition, currHitObject.TimeFadein, Easing.Out);
|
||||
fp.MoveTo(pointEndPosition, currHitObject.TimeFadeIn, Easing.Out);
|
||||
|
||||
fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadein);
|
||||
fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadeIn);
|
||||
}
|
||||
|
||||
fp.Expire(true);
|
||||
|
||||
@@ -93,7 +93,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
AddJudgement(new OsuJudgement
|
||||
{
|
||||
Result = result,
|
||||
PositionOffset = Vector2.Zero //todo: set to correct value
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
base.UpdatePreemptState();
|
||||
|
||||
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadein * 2, HitObject.TimePreempt));
|
||||
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
|
||||
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@@ -32,7 +34,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
UpdatePreemptState();
|
||||
|
||||
using (BeginDelayedSequence(HitObject.TimePreempt + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
|
||||
var judgementOffset = Math.Min(HitObject.HitWindows.HalfWindowFor(HitResult.Miss), Judgements.FirstOrDefault()?.TimeOffset ?? 0);
|
||||
|
||||
using (BeginDelayedSequence(HitObject.TimePreempt + judgementOffset, true))
|
||||
UpdateCurrentState(state);
|
||||
}
|
||||
}
|
||||
@@ -45,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
|
||||
}
|
||||
|
||||
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadein);
|
||||
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
|
||||
|
||||
protected virtual void UpdateCurrentState(ArmedState state)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using OpenTK;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@@ -33,11 +34,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new SpriteIcon
|
||||
new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Icon = FontAwesome.fa_chevron_right
|
||||
}
|
||||
}, restrictSize: false)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,6 +75,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
private bool hasRotation;
|
||||
|
||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||
{
|
||||
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
|
||||
@@ -87,15 +90,33 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
int searchStart = isRepeatAtEnd ? curve.Count - 1 : 0;
|
||||
int direction = isRepeatAtEnd ? -1 : 1;
|
||||
|
||||
Vector2 aimRotationVector = Vector2.Zero;
|
||||
|
||||
// find the next vector2 in the curve which is not equal to our current position to infer a rotation.
|
||||
for (int i = searchStart; i >= 0 && i < curve.Count; i += direction)
|
||||
{
|
||||
if (Precision.AlmostEquals(curve[i], Position))
|
||||
continue;
|
||||
|
||||
Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - Position.Y, curve[i].X - Position.X));
|
||||
aimRotationVector = curve[i];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
float aimRotation = MathHelper.RadiansToDegrees((float)Math.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
|
||||
while (Math.Abs(aimRotation - Rotation) > 180)
|
||||
aimRotation += aimRotation < Rotation ? 360 : -360;
|
||||
|
||||
if (!hasRotation)
|
||||
{
|
||||
Rotation = aimRotation;
|
||||
hasRotation = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're already snaking, interpolate to smooth out sharp curves (linear sliders, mainly).
|
||||
Rotation = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 100), Rotation, aimRotation, 0, 50, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +93,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
base.AccentColour = value;
|
||||
Body.AccentColour = AccentColour;
|
||||
Ball.AccentColour = AccentColour;
|
||||
if (HasNestedHitObjects)
|
||||
foreach (var drawableHitObject in NestedHitObjects)
|
||||
drawableHitObject.AccentColour = AccentColour;
|
||||
|
||||
foreach (var drawableHitObject in NestedHitObjects)
|
||||
drawableHitObject.AccentColour = AccentColour;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
if (!userTriggered && Time.Current >= slider.EndTime)
|
||||
{
|
||||
var judgementsCount = NestedHitObjects.Count;
|
||||
var judgementsCount = NestedHitObjects.Count();
|
||||
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
||||
|
||||
var hitFraction = (double)judgementsHit / judgementsCount;
|
||||
|
||||
@@ -8,6 +8,8 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@@ -22,23 +24,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||
{
|
||||
Size = new Vector2(16) * sliderTick.Scale;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = Size.X / 2;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
BorderThickness = 2;
|
||||
BorderColour = Color4.White;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new Container
|
||||
{
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Alpha = 0.3f,
|
||||
}
|
||||
Origin = Anchor.Centre,
|
||||
CornerRadius = Size.X / 2,
|
||||
|
||||
BorderThickness = 2,
|
||||
BorderColour = Color4.White,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Alpha = 0.3f,
|
||||
}
|
||||
}, restrictSize: false)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton);
|
||||
if (!spmCounter.IsPresent && Disc.Tracking)
|
||||
spmCounter.FadeIn(HitObject.TimeFadein);
|
||||
spmCounter.FadeIn(HitObject.TimeFadeIn);
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.EventArgs;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
@@ -17,6 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
private const float width = 128;
|
||||
|
||||
private Color4 accentColour = Color4.Black;
|
||||
|
||||
/// <summary>
|
||||
/// The colour that is used for the slider ball.
|
||||
/// </summary>
|
||||
@@ -26,14 +29,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
if (ball != null)
|
||||
ball.Colour = value;
|
||||
if (drawableBall != null)
|
||||
drawableBall.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Slider slider;
|
||||
public readonly Box FollowCircle;
|
||||
private readonly Box ball;
|
||||
public readonly Drawable FollowCircle;
|
||||
private Drawable drawableBall;
|
||||
|
||||
public SliderBall(Slider slider)
|
||||
{
|
||||
@@ -42,19 +45,30 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Blending = BlendingMode.Additive;
|
||||
Origin = Anchor.Centre;
|
||||
BorderThickness = 10;
|
||||
BorderColour = Color4.Orange;
|
||||
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
FollowCircle = new Box
|
||||
FollowCircle = new Container
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Colour = Color4.Orange,
|
||||
Width = width,
|
||||
Height = width,
|
||||
Alpha = 0,
|
||||
Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = 5,
|
||||
BorderColour = Color4.Orange,
|
||||
Blending = BlendingMode.Additive,
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.Orange,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.2f,
|
||||
}
|
||||
}),
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
@@ -62,18 +76,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
BorderThickness = 10,
|
||||
BorderColour = Color4.White,
|
||||
Alpha = 1,
|
||||
Children = new[]
|
||||
Child = new Container
|
||||
{
|
||||
ball = new Box
|
||||
Width = width,
|
||||
Height = width,
|
||||
// TODO: support skin filename animation (sliderb0, sliderb1...)
|
||||
Child = new SkinnableDrawable("Play/osu/sliderb", _ => new CircularContainer
|
||||
{
|
||||
Colour = AccentColour,
|
||||
Alpha = 0.4f,
|
||||
Width = width,
|
||||
Height = width,
|
||||
},
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
BorderThickness = 10,
|
||||
BorderColour = Color4.White,
|
||||
Alpha = 1,
|
||||
Child = drawableBall = new Box
|
||||
{
|
||||
Colour = AccentColour,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.4f,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -110,6 +132,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
}
|
||||
|
||||
private bool tracking;
|
||||
|
||||
public bool Tracking
|
||||
{
|
||||
get { return tracking; }
|
||||
@@ -119,8 +142,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
return;
|
||||
tracking = value;
|
||||
|
||||
FollowCircle.ScaleTo(tracking ? 2.8f : 1, 300, Easing.OutQuint);
|
||||
FollowCircle.FadeTo(tracking ? 0.2f : 0, 300, Easing.OutQuint);
|
||||
FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint);
|
||||
FollowCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
var spanProgress = slider.ProgressAt(completionProgress);
|
||||
|
||||
double start = 0;
|
||||
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadein, 0, 1) : 1;
|
||||
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
|
||||
|
||||
if (span >= slider.SpanCount() - 1)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public event Action<Vector2> PositionChanged;
|
||||
|
||||
public double TimePreempt = 600;
|
||||
public double TimeFadein = 400;
|
||||
public double TimeFadeIn = 400;
|
||||
|
||||
private Vector2 position;
|
||||
|
||||
@@ -54,9 +54,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
public virtual bool NewCombo { get; set; }
|
||||
|
||||
public int IndexInCurrentCombo { get; set; }
|
||||
public virtual int IndexInCurrentCombo { get; set; }
|
||||
|
||||
public int ComboIndex { get; set; }
|
||||
public virtual int ComboIndex { get; set; }
|
||||
|
||||
public bool LastInCombo { get; set; }
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
||||
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
||||
TimeFadeIn = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
||||
|
||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
// Out preempt should be one span early to give the user ample warning.
|
||||
TimePreempt += SpanDuration;
|
||||
|
||||
// We want to show the first RepeatPoint as the TimePreempt dictates but on short (and possibly fast) sliders
|
||||
// we may need to cut down this time on following RepeatPoints to only show up to two RepeatPoints at any given time.
|
||||
if (RepeatIndex > 0)
|
||||
|
||||
@@ -26,6 +26,28 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t);
|
||||
public override Vector2 EndPosition => Position + this.CurvePositionAt(1);
|
||||
|
||||
public override int ComboIndex
|
||||
{
|
||||
get => base.ComboIndex;
|
||||
set
|
||||
{
|
||||
base.ComboIndex = value;
|
||||
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
|
||||
n.ComboIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int IndexInCurrentCombo
|
||||
{
|
||||
get => base.IndexInCurrentCombo;
|
||||
set
|
||||
{
|
||||
base.IndexInCurrentCombo = value;
|
||||
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
|
||||
n.IndexInCurrentCombo = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SliderCurve Curve { get; } = new SliderCurve();
|
||||
|
||||
public List<Vector2> ControlPoints
|
||||
@@ -147,7 +169,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
var distanceProgress = d / length;
|
||||
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
|
||||
|
||||
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
|
||||
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL)
|
||||
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
|
||||
var sampleList = new List<SampleInfo>();
|
||||
|
||||
if (firstSample != null)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
// This is so on repeats ticks don't appear too late to be visually processed by the player.
|
||||
offset = 200;
|
||||
else
|
||||
offset = TimeFadein * 0.66f;
|
||||
offset = TimeFadeIn * 0.66f;
|
||||
|
||||
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.Z, OsuAction.LeftButton),
|
||||
new KeyBinding(InputKey.X, OsuAction.RightButton),
|
||||
new KeyBinding(InputKey.A, OsuAction.LeftButton),
|
||||
new KeyBinding(InputKey.S, OsuAction.RightButton),
|
||||
new KeyBinding(InputKey.MouseLeft, OsuAction.LeftButton),
|
||||
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
||||
};
|
||||
|
||||
@@ -285,44 +285,45 @@ namespace osu.Game.Rulesets.Osu.Replays
|
||||
|
||||
AddFrameToReplay(startFrame);
|
||||
|
||||
// We add intermediate frames for spinning / following a slider here.
|
||||
if (h is Spinner)
|
||||
switch (h)
|
||||
{
|
||||
Spinner s = h as Spinner;
|
||||
|
||||
Vector2 difference = startPosition - SPINNER_CENTRE;
|
||||
|
||||
float radius = difference.Length;
|
||||
float angle = radius == 0 ? 0 : (float)Math.Atan2(difference.Y, difference.X);
|
||||
|
||||
double t;
|
||||
|
||||
for (double j = h.StartTime + FrameDelay; j < s.EndTime; j += FrameDelay)
|
||||
// We add intermediate frames for spinning / following a slider here.
|
||||
case Spinner spinner:
|
||||
{
|
||||
t = ApplyModsToTime(j - h.StartTime) * spinnerDirection;
|
||||
Vector2 difference = startPosition - SPINNER_CENTRE;
|
||||
|
||||
Vector2 pos = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
AddFrameToReplay(new OsuReplayFrame((int)j, new Vector2(pos.X, pos.Y), action));
|
||||
float radius = difference.Length;
|
||||
float angle = radius == 0 ? 0 : (float)Math.Atan2(difference.Y, difference.X);
|
||||
|
||||
double t;
|
||||
|
||||
for (double j = h.StartTime + FrameDelay; j < spinner.EndTime; j += FrameDelay)
|
||||
{
|
||||
t = ApplyModsToTime(j - h.StartTime) * spinnerDirection;
|
||||
|
||||
Vector2 pos = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
AddFrameToReplay(new OsuReplayFrame((int)j, new Vector2(pos.X, pos.Y), action));
|
||||
}
|
||||
|
||||
t = ApplyModsToTime(spinner.EndTime - h.StartTime) * spinnerDirection;
|
||||
Vector2 endPosition = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(spinner.EndTime, new Vector2(endPosition.X, endPosition.Y), action));
|
||||
|
||||
endFrame.Position = endPosition;
|
||||
break;
|
||||
}
|
||||
|
||||
t = ApplyModsToTime(s.EndTime - h.StartTime) * spinnerDirection;
|
||||
Vector2 endPosition = SPINNER_CENTRE + CirclePosition(t / 20 + angle, SPIN_RADIUS);
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(s.EndTime, new Vector2(endPosition.X, endPosition.Y), action));
|
||||
|
||||
endFrame.Position = endPosition;
|
||||
}
|
||||
else if (h is Slider)
|
||||
{
|
||||
Slider s = h as Slider;
|
||||
|
||||
for (double j = FrameDelay; j < s.Duration; j += FrameDelay)
|
||||
case Slider slider:
|
||||
{
|
||||
Vector2 pos = s.StackedPositionAt(j / s.Duration);
|
||||
AddFrameToReplay(new OsuReplayFrame(h.StartTime + j, new Vector2(pos.X, pos.Y), action));
|
||||
}
|
||||
for (double j = FrameDelay; j < slider.Duration; j += FrameDelay)
|
||||
{
|
||||
Vector2 pos = slider.StackedPositionAt(j / slider.Duration);
|
||||
AddFrameToReplay(new OsuReplayFrame(h.StartTime + j, new Vector2(pos.X, pos.Y), action));
|
||||
}
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(s.EndTime, new Vector2(s.StackedEndPosition.X, s.StackedEndPosition.Y), action));
|
||||
AddFrameToReplay(new OsuReplayFrame(slider.EndTime, new Vector2(slider.StackedEndPosition.X, slider.StackedEndPosition.Y), action));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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!
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using OpenTK;
|
||||
|
||||
@@ -12,6 +12,7 @@ using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Timing;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
private int downCount;
|
||||
|
||||
private const float pressed_scale = 1.2f;
|
||||
private const float released_scale = 1f;
|
||||
|
||||
private float targetScale => downCount > 0 ? pressed_scale : released_scale;
|
||||
|
||||
public bool OnPressed(OsuAction action)
|
||||
{
|
||||
switch (action)
|
||||
@@ -46,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
case OsuAction.LeftButton:
|
||||
case OsuAction.RightButton:
|
||||
downCount++;
|
||||
ActiveCursor.ScaleTo(1).ScaleTo(1.2f, 100, Easing.OutQuad);
|
||||
ActiveCursor.ScaleTo(released_scale).ScaleTo(targetScale, 100, Easing.OutQuad);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -60,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
case OsuAction.LeftButton:
|
||||
case OsuAction.RightButton:
|
||||
if (--downCount == 0)
|
||||
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
|
||||
ActiveCursor.ScaleTo(targetScale, 200, Easing.OutQuad);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -72,13 +77,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
protected override void PopIn()
|
||||
{
|
||||
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(targetScale, 400, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(targetScale * 0.8f, 450, Easing.OutQuint);
|
||||
}
|
||||
|
||||
public class OsuCursor : Container
|
||||
|
||||
@@ -11,7 +11,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
@@ -21,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
|
||||
|
||||
protected virtual bool DisplayJudgements => true;
|
||||
|
||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||
|
||||
public OsuPlayfield()
|
||||
@@ -75,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset
|
||||
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
|
||||
};
|
||||
|
||||
judgementLayer.Add(explosion);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2018 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.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
@@ -33,19 +34,30 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
protected override DrawableHitObject<OsuHitObject> GetVisualRepresentation(OsuHitObject h)
|
||||
{
|
||||
if (h is HitCircle circle)
|
||||
return new DrawableHitCircle(circle);
|
||||
switch (h)
|
||||
{
|
||||
case HitCircle circle:
|
||||
return new DrawableHitCircle(circle);
|
||||
case Slider slider:
|
||||
return new DrawableSlider(slider);
|
||||
case Spinner spinner:
|
||||
return new DrawableSpinner(spinner);
|
||||
}
|
||||
|
||||
if (h is Slider slider)
|
||||
return new DrawableSlider(slider);
|
||||
|
||||
if (h is Spinner spinner)
|
||||
return new DrawableSpinner(spinner);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay);
|
||||
|
||||
public override double GameplayStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
var first = (OsuHitObject)Objects.First();
|
||||
return first.StartTime - first.TimePreempt;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 GetAspectAdjustedSize()
|
||||
{
|
||||
var aspectSize = DrawSize.X * 0.75f < DrawSize.Y ? new Vector2(DrawSize.X, DrawSize.X * 0.75f) : new Vector2(DrawSize.Y * 4f / 3f, DrawSize.Y);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user