Merge branch 'master' into news-overlay-header

This commit is contained in:
Dean Herbert 2019-09-16 00:59:18 +09:00 committed by GitHub
commit 9d8eb42ac7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
427 changed files with 8936 additions and 2748 deletions

View File

@ -6,7 +6,7 @@ GEM
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 4.0)
atomos (0.1.3) atomos (0.1.3)
babosa (1.0.2) babosa (1.0.2)
claide (1.0.2) claide (1.0.3)
colored (1.2) colored (1.2)
colored2 (3.1.2) colored2 (3.1.2)
commander-fastlane (4.4.6) commander-fastlane (4.4.6)
@ -14,11 +14,11 @@ GEM
declarative (0.0.10) declarative (0.0.10)
declarative-option (0.1.0) declarative-option (0.1.0)
digest-crc (0.4.1) digest-crc (0.4.1)
domain_name (0.5.20180417) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.1) dotenv (2.7.5)
emoji_regex (1.0.1) emoji_regex (1.0.1)
excon (0.62.0) excon (0.66.0)
faraday (0.15.4) faraday (0.15.4)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6) faraday-cookie_jar (0.0.6)
@ -27,7 +27,7 @@ GEM
faraday_middleware (0.13.1) faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0) faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5) fastimage (2.1.5)
fastlane (2.117.0) fastlane (2.129.0)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0) addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0) babosa (>= 1.0.2, < 2.0.0)
@ -46,8 +46,8 @@ GEM
google-cloud-storage (>= 1.15.0, < 2.0.0) google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0) highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0) json (< 3.0.0)
mini_magick (~> 4.5.1) jwt (~> 2.1.0)
multi_json mini_magick (>= 4.9.4, < 5.0.0)
multi_xml (~> 0.5) multi_xml (~> 0.5)
multipart-post (~> 2.0.0) multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0) plist (>= 3.1.0, < 4.0.0)
@ -56,15 +56,15 @@ GEM
security (= 0.1.3) security (= 0.1.3)
simctl (~> 1.6.3) simctl (~> 1.6.3)
slack-notifier (>= 2.0.0, < 3.0.0) slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 1.6.2, < 2.0.0) terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0) terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0) tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0) word_wrap (~> 1.0.0)
xcodeproj (>= 1.6.0, < 2.0.0) xcodeproj (>= 1.8.1, < 2.0.0)
xcpretty (~> 0.3.0) xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3) xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-clean_testflight_testers (0.2.0) fastlane-plugin-clean_testflight_testers (0.3.0)
fastlane-plugin-souyuz (0.8.1) fastlane-plugin-souyuz (0.8.1)
souyuz (>= 0.8.1) souyuz (>= 0.8.1)
fastlane-plugin-xamarin (0.6.3) fastlane-plugin-xamarin (0.6.3)
@ -79,7 +79,7 @@ GEM
signet (~> 0.9) signet (~> 0.9)
google-cloud-core (1.3.0) google-cloud-core (1.3.0)
google-cloud-env (~> 1.0) google-cloud-env (~> 1.0)
google-cloud-env (1.0.5) google-cloud-env (1.2.0)
faraday (~> 0.11) faraday (~> 0.11)
google-cloud-storage (1.16.0) google-cloud-storage (1.16.0)
digest-crc (~> 0.4) digest-crc (~> 0.4)
@ -102,17 +102,17 @@ GEM
memoist (0.16.0) memoist (0.16.0)
mime-types (3.2.2) mime-types (3.2.2)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2018.0812) mime-types-data (3.2019.0331)
mini_magick (4.5.1) mini_magick (4.9.5)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
multi_json (1.13.1) multi_json (1.13.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
nanaimo (0.2.6) nanaimo (0.2.6)
naturally (2.2.0) naturally (2.2.0)
nokogiri (1.10.1) nokogiri (1.10.4)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
os (1.0.0) os (1.0.1)
plist (3.5.0) plist (3.5.0)
public_suffix (2.0.5) public_suffix (2.0.5)
representable (3.0.4) representable (3.0.4)
@ -121,7 +121,7 @@ GEM
uber (< 0.2.0) uber (< 0.2.0)
retriable (3.1.2) retriable (3.1.2)
rouge (2.0.7) rouge (2.0.7)
rubyzip (1.2.2) rubyzip (1.2.3)
security (0.1.3) security (0.1.3)
signet (0.11.0) signet (0.11.0)
addressable (~> 2.3) addressable (~> 2.3)
@ -136,20 +136,20 @@ GEM
fastlane (>= 2.29.0) fastlane (>= 2.29.0)
highline (~> 1.7) highline (~> 1.7)
nokogiri (~> 1.7) nokogiri (~> 1.7)
terminal-notifier (1.8.0) terminal-notifier (2.0.0)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.6.1) tty-cursor (0.7.0)
tty-screen (0.6.5) tty-screen (0.7.0)
tty-spinner (0.9.0) tty-spinner (0.9.1)
tty-cursor (~> 0.6.0) tty-cursor (~> 0.7)
uber (0.1.0) uber (0.1.0)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.5) unf_ext (0.0.7.6)
unicode-display_width (1.4.1) unicode-display_width (1.6.0)
word_wrap (1.0.0) word_wrap (1.0.0)
xcodeproj (1.8.1) xcodeproj (1.12.0)
CFPropertyList (>= 2.3.3, < 4.0) CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3) atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)

View File

@ -2,7 +2,5 @@ clone_depth: 1
version: '{branch}-{build}' version: '{branch}-{build}'
image: Previous Visual Studio 2017 image: Previous Visual Studio 2017
test: off test: off
install:
- cmd: git submodule update --init --recursive --depth=5
build_script: build_script:
- cmd: PowerShell -Version 2.0 .\build.ps1 - cmd: PowerShell -Version 2.0 .\build.ps1

10
appveyor_deploy.yml Normal file
View File

@ -0,0 +1,10 @@
clone_depth: 1
version: '{build}'
image: Previous Visual Studio 2017
test: off
skip_non_tags: true
build_script:
- cmd: PowerShell -Version 2.0 .\build.ps1
deploy:
- provider: Environment
name: nuget

View File

@ -1,22 +1,6 @@
update_fastlane update_fastlane
default_platform(:ios)
platform :ios do platform :ios do
lane :testflight_prune_dry do
clean_testflight_testers(days_of_inactivity:45, dry_run: true)
end
# Specify a custom number for what's "inactive"
lane :testflight_prune do
clean_testflight_testers(days_of_inactivity: 45) # 120 days, so about 4 months
end
lane :update_version do |options|
options[:plist_path] = '../osu.iOS/Info.plist'
app_version(options)
end
desc 'Deploy to testflight' desc 'Deploy to testflight'
lane :beta do |options| lane :beta do |options|
update_version(options) update_version(options)
@ -62,4 +46,17 @@ platform :ios do
match(options) match(options)
end end
lane :update_version do |options|
options[:plist_path] = '../osu.iOS/Info.plist'
app_version(options)
end
lane :testflight_prune_dry do
clean_testflight_testers(days_of_inactivity:45, dry_run: true)
end
lane :testflight_prune do
clean_testflight_testers(days_of_inactivity: 45)
end
end end

View File

@ -16,21 +16,6 @@ or alternatively using `brew cask install fastlane`
# Available Actions # Available Actions
## iOS ## iOS
### ios testflight_prune_dry
```
fastlane ios testflight_prune_dry
```
### ios testflight_prune
```
fastlane ios testflight_prune
```
### ios update_version
```
fastlane ios update_version
```
### ios beta ### ios beta
``` ```
fastlane ios beta fastlane ios beta
@ -46,6 +31,21 @@ Compile the project
fastlane ios provision fastlane ios provision
``` ```
Install provisioning profiles using match Install provisioning profiles using match
### ios update_version
```
fastlane ios update_version
```
### ios testflight_prune_dry
```
fastlane ios testflight_prune_dry
```
### ios testflight_prune
```
fastlane ios testflight_prune
```
---- ----

View File

@ -1,5 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputPath>bin\$(Configuration)</OutputPath> <OutputPath>bin\$(Configuration)</OutputPath>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
@ -35,7 +37,7 @@
<DebugType>None</DebugType> <DebugType>None</DebugType>
<Optimize>True</Optimize> <Optimize>True</Optimize>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<EnableLLVM>true</EnableLLVM> <EnableLLVM>true</EnableLLVM>
<AndroidManagedSymbols>false</AndroidManagedSymbols> <AndroidManagedSymbols>false</AndroidManagedSymbols>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>SdkOnly</AndroidLinkMode>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
@ -60,7 +62,7 @@
<Reference Include="Java.Interop" /> <Reference Include="Java.Interop" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.809.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.913.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.814.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2019.911.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -14,7 +14,9 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
@ -81,25 +83,24 @@ namespace osu.Game.Rulesets.Catch.Tests
remove { } remove { }
} }
public Drawable GetDrawableComponent(string componentName) public Drawable GetDrawableComponent(ISkinComponent component)
{ {
switch (componentName) switch (component.LookupName)
{ {
case "Play/Catch/fruit-catcher-idle": case "Gameplay/catch/fruit-catcher-idle":
return new CatcherCustomSkin(); return new CatcherCustomSkin();
} }
return null; return null;
} }
public SampleChannel GetSample(string sampleName) => public SampleChannel GetSample(ISampleInfo sampleInfo) =>
throw new NotImplementedException(); throw new NotImplementedException();
public Texture GetTexture(string componentName) => public Texture GetTexture(string componentName) =>
throw new NotImplementedException(); throw new NotImplementedException();
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
throw new NotImplementedException();
} }
} }
} }

View File

@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
} }
protected override bool Autoplay => true;
[Test] [Test]
public void TestHyperDash() public void TestHyperDash()
{ {

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -23,10 +23,12 @@ namespace osu.Game.Rulesets.Catch
{ {
public class CatchRuleset : Ruleset public class CatchRuleset : Ruleset
{ {
public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) => new DrawableCatchRuleset(this, beatmap, mods); public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods) => new DrawableCatchRuleset(this, beatmap, mods);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
public const string SHORT_NAME = "fruits";
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[] public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{ {
new KeyBinding(InputKey.Z, CatchAction.MoveLeft), new KeyBinding(InputKey.Z, CatchAction.MoveLeft),
@ -117,7 +119,7 @@ namespace osu.Game.Rulesets.Catch
public override string Description => "osu!catch"; public override string Description => "osu!catch";
public override string ShortName => "fruits"; public override string ShortName => SHORT_NAME;
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetCatch }; public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetCatch };

View File

@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch
{
public class CatchSkinComponent : GameplaySkinComponent<CatchSkinComponents>
{
public CatchSkinComponent(CatchSkinComponents component)
: base(component)
{
}
protected override string RulesetPrefix => "catch"; // todo: use CatchRuleset.SHORT_NAME;
protected override string ComponentName => Component.ToString().ToLower();
}
}

View File

@ -0,0 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Rulesets.Catch
{
public enum CatchSkinComponents
{
}
}

View File

@ -6,6 +6,7 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {

View File

@ -50,6 +50,10 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
public Func<CatchHitObject, bool> CheckPosition; public Func<CatchHitObject, bool> CheckPosition;
public bool IsOnPlate;
public override bool RemoveWhenNotAlive => IsOnPlate;
protected override void CheckForResult(bool userTriggered, double timeOffset) protected override void CheckForResult(bool userTriggered, double timeOffset)
{ {
if (CheckPosition == null) return; if (CheckPosition == null) return;
@ -58,14 +62,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss); ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
} }
protected override bool UseTransformStateManagement => false; protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
protected override void UpdateState(ArmedState state) protected override void UpdateInitialTransforms() => this.FadeInFromZero(200);
protected override void UpdateStateTransforms(ArmedState state)
{ {
// TODO: update to use new state management.
using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt))
this.FadeIn(200);
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
using (BeginAbsoluteSequence(endTime, true)) using (BeginAbsoluteSequence(endTime, true))
@ -73,11 +75,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
switch (state) switch (state)
{ {
case ArmedState.Miss: case ArmedState.Miss:
this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire(); this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out);
break; break;
case ArmedState.Hit: case ArmedState.Hit:
this.FadeOut().Expire(); this.FadeOut();
break; break;
} }
} }

View File

@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
AccentColour = Color4.Red, AccentColour = Color4.Red,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0.5f, Alpha = 0.5f,
Scale = new Vector2(1.333f) Scale = new Vector2(1.333f)
}); });

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Colour = Color4.White.Opacity(0.9f); Colour = Color4.White.Opacity(0.9f);
} }

View File

@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Catch.Replays
protected Replay Replay; protected Replay Replay;
private CatchReplayFrame currentFrame;
public override Replay Generate() public override Replay Generate()
{ {
// todo: add support for HT DT // todo: add support for HT DT
@ -36,7 +38,7 @@ namespace osu.Game.Rulesets.Catch.Replays
double lastTime = 0; double lastTime = 0;
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition)); addFrame(-100000, lastPosition);
void moveToNext(CatchHitObject h) void moveToNext(CatchHitObject h)
{ {
@ -58,18 +60,18 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
//we are already in the correct range. //we are already in the correct range.
lastTime = h.StartTime; lastTime = h.StartTime;
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition)); addFrame(h.StartTime, lastPosition);
return; return;
} }
if (impossibleJump) if (impossibleJump)
{ {
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
else if (h.HyperDash) else if (h.HyperDash)
{ {
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition)); addFrame(h.StartTime - timeAvailable, lastPosition);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
else if (dashRequired) else if (dashRequired)
{ {
@ -81,16 +83,16 @@ namespace osu.Game.Rulesets.Catch.Replays
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable); float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
//dash movement //dash movement
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, true)); addFrame(h.StartTime - timeAvailable + 1, lastPosition, true);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition)); addFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
else else
{ {
double timeBefore = positionChange / movement_speed; double timeBefore = positionChange / movement_speed;
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition)); addFrame(h.StartTime - timeBefore, lastPosition);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
lastTime = h.StartTime; lastTime = h.StartTime;
@ -122,5 +124,12 @@ namespace osu.Game.Rulesets.Catch.Replays
return Replay; return Replay;
} }
private void addFrame(double time, float? position = null, bool dashing = false)
{
var last = currentFrame;
currentFrame = new CatchReplayFrame(time, position, dashing, last);
Replay.Frames.Add(currentFrame);
}
} }
} }

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using osu.Framework.Input.StateChanges; using osu.Framework.Input.StateChanges;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Replays; using osu.Game.Replays;
@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
} }
protected override bool IsImportant(CatchReplayFrame frame) => frame.Position > 0; protected override bool IsImportant(CatchReplayFrame frame) => frame.Actions.Any();
protected float? Position protected float? Position
{ {
@ -38,21 +39,11 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
if (!Position.HasValue) return new List<IInput>(); if (!Position.HasValue) return new List<IInput>();
var actions = new List<CatchAction>();
if (CurrentFrame.Dashing)
actions.Add(CatchAction.Dash);
if (Position.Value > CurrentFrame.Position)
actions.Add(CatchAction.MoveRight);
else if (Position.Value < CurrentFrame.Position)
actions.Add(CatchAction.MoveLeft);
return new List<IInput> return new List<IInput>
{ {
new CatchReplayState new CatchReplayState
{ {
PressedActions = actions, PressedActions = CurrentFrame?.Actions ?? new List<CatchAction>(),
CatcherX = Position.Value CatcherX = Position.Value
}, },
}; };

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy; using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame
{ {
public List<CatchAction> Actions = new List<CatchAction>();
public float Position; public float Position;
public bool Dashing; public bool Dashing;
@ -18,17 +21,40 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
} }
public CatchReplayFrame(double time, float? position = null, bool dashing = false) public CatchReplayFrame(double time, float? position = null, bool dashing = false, CatchReplayFrame lastFrame = null)
: base(time) : base(time)
{ {
Position = position ?? -1; Position = position ?? -1;
Dashing = dashing; Dashing = dashing;
if (Dashing)
Actions.Add(CatchAction.Dash);
if (lastFrame != null)
{
if (Position > lastFrame.Position)
lastFrame.Actions.Add(CatchAction.MoveRight);
else if (Position < lastFrame.Position)
lastFrame.Actions.Add(CatchAction.MoveLeft);
}
} }
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap) public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
{ {
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH; Position = currentFrame.Position.X / CatchPlayfield.BASE_WIDTH;
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1; Dashing = currentFrame.ButtonState == ReplayButtonState.Left1;
if (Dashing)
Actions.Add(CatchAction.Dash);
// this probably needs some cross-checking with osu-stable to ensure it is actually correct.
if (lastFrame is CatchReplayFrame lastCatchFrame)
{
if (Position > lastCatchFrame.Position)
lastCatchFrame.Actions.Add(CatchAction.MoveRight);
else if (Position < lastCatchFrame.Position)
Actions.Add(CatchAction.MoveLeft);
}
} }
} }
} }

View File

@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Scoring
{ {
public class CatchHitWindows : HitWindows public class CatchHitWindows : HitWindows
{ {

View File

@ -4,7 +4,6 @@
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;

View File

@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (lastPlateableFruit == null) if (lastPlateableFruit == null)
return; return;
// this is required to make this run after the last caught fruit runs UpdateState at least once. // this is required to make this run after the last caught fruit runs updateState() at least once.
// TODO: find a better alternative // TODO: find a better alternative
if (lastPlateableFruit.IsLoaded) if (lastPlateableFruit.IsLoaded)
action(); action();
@ -69,10 +69,12 @@ namespace osu.Game.Rulesets.Catch.UI
caughtFruit.RelativePositionAxes = Axes.None; caughtFruit.RelativePositionAxes = Axes.None;
caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(fruit.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0); caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(fruit.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0);
caughtFruit.IsOnPlate = true;
caughtFruit.Anchor = Anchor.TopCentre; caughtFruit.Anchor = Anchor.TopCentre;
caughtFruit.Origin = Anchor.Centre; caughtFruit.Origin = Anchor.Centre;
caughtFruit.Scale *= 0.7f; caughtFruit.Scale *= 0.7f;
caughtFruit.LifetimeStart = caughtFruit.HitObject.StartTime;
caughtFruit.LifetimeEnd = double.MaxValue; caughtFruit.LifetimeEnd = double.MaxValue;
MovableCatcher.Add(caughtFruit); MovableCatcher.Add(caughtFruit);
@ -201,11 +203,12 @@ namespace osu.Game.Rulesets.Catch.UI
additive.Scale = Scale; additive.Scale = Scale;
additive.Colour = HyperDashing ? Color4.Red : Color4.White; additive.Colour = HyperDashing ? Color4.Red : Color4.White;
additive.RelativePositionAxes = RelativePositionAxes; additive.RelativePositionAxes = RelativePositionAxes;
additive.Blending = BlendingMode.Additive; additive.Blending = BlendingParameters.Additive;
AdditiveTarget.Add(additive); AdditiveTarget.Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire(); additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
additive.Expire(true);
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
} }
@ -300,6 +303,7 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint); this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint); this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
Trail &= Dashing;
} }
} }
else else
@ -406,6 +410,9 @@ namespace osu.Game.Rulesets.Catch.UI
f.MoveToY(f.Y + 75, 750, Easing.InSine); f.MoveToY(f.Y + 75, 750, Easing.InSine);
f.FadeOut(750); f.FadeOut(750);
// todo: this shouldn't exist once DrawableHitObject's ClearTransformsAfter overrides are repaired.
f.LifetimeStart = Time.Current;
f.Expire(); f.Expire();
} }
} }
@ -436,10 +443,13 @@ namespace osu.Game.Rulesets.Catch.UI
ExplodingFruitTarget.Add(fruit); ExplodingFruitTarget.Add(fruit);
} }
fruit.ClearTransforms();
fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine).Then().MoveToY(fruit.Y + 50, 500, Easing.InSine); fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine).Then().MoveToY(fruit.Y + 50, 500, Easing.InSine);
fruit.MoveToX(fruit.X + originalX * 6, 1000); fruit.MoveToX(fruit.X + originalX * 6, 1000);
fruit.FadeOut(750); fruit.FadeOut(750);
// todo: this shouldn't exist once DrawableHitObject's ClearTransformsAfter overrides are repaired.
fruit.LifetimeStart = Time.Current;
fruit.Expire(); fruit.Expire();
} }
} }

View File

@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.UI
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
InternalChild = new SkinnableSprite(@"Play/Catch/fruit-catcher-idle") InternalChild = new SkinnableSprite("Gameplay/catch/fruit-catcher-idle")
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,

View File

@ -25,11 +25,11 @@ namespace osu.Game.Rulesets.Catch.UI
protected override bool UserScrollSpeedAdjustment => false; protected override bool UserScrollSpeedAdjustment => false;
public DrawableCatchRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) public DrawableCatchRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
Direction.Value = ScrollingDirection.Down; Direction.Value = ScrollingDirection.Down;
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450); TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
} }
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this); public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);

View File

@ -3,6 +3,7 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Replays;
@ -12,6 +13,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests namespace osu.Game.Rulesets.Mania.Tests
{ {
[TestFixture] [TestFixture]
[HeadlessTest]
public class TestSceneAutoGeneration : OsuTestScene public class TestSceneAutoGeneration : OsuTestScene
{ {
[Test] [Test]

View File

@ -0,0 +1,62 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class TestSceneHitExplosion : OsuTestScene
{
private ScrollingTestContainer scrolling;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(DrawableNote),
typeof(DrawableManiaHitObject),
};
protected override void LoadComplete()
{
base.LoadComplete();
Child = scrolling = new ScrollingTestContainer(ScrollingDirection.Down)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.Y,
Y = -0.25f,
Size = new Vector2(Column.COLUMN_WIDTH, NotePiece.NOTE_HEIGHT),
};
int runcount = 0;
AddRepeatStep("explode", () =>
{
runcount++;
if (runcount % 15 > 12)
return;
scrolling.AddRange(new Drawable[]
{
new HitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
}, 100);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
@ -11,6 +11,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -40,6 +41,7 @@ namespace osu.Game.Rulesets.Mania.Tests
{ {
Child = new FillFlowContainer Child = new FillFlowContainer
{ {
Clock = new FramedClock(new ManualClock()),
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -62,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Tests
private Drawable createNoteDisplay(ScrollingDirection direction, int identifier, out DrawableNote hitObject) private Drawable createNoteDisplay(ScrollingDirection direction, int identifier, out DrawableNote hitObject)
{ {
var note = new Note { StartTime = 999999999 }; var note = new Note { StartTime = 0 };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
return new ScrollingTestContainer(direction) return new ScrollingTestContainer(direction)
@ -77,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
private Drawable createHoldNoteDisplay(ScrollingDirection direction, int identifier, out DrawableHoldNote hitObject) private Drawable createHoldNoteDisplay(ScrollingDirection direction, int identifier, out DrawableHoldNote hitObject)
{ {
var note = new HoldNote { StartTime = 999999999, Duration = 5000 }; var note = new HoldNote { StartTime = 0, Duration = 5000 };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
return new ScrollingTestContainer(direction) return new ScrollingTestContainer(direction)
@ -133,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Width = 1.25f, Width = 1.25f,
Colour = Color4.Black.Opacity(0.5f) Colour = Color4.Green.Opacity(0.5f)
}, },
content = new Container { RelativeSizeAxes = Axes.Both } content = new Container { RelativeSizeAxes = Axes.Both }
} }

View File

@ -15,6 +15,7 @@ using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK; using osuTK;
@ -114,8 +115,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new BarLine var obj = new BarLine
{ {
StartTime = Time.Current + 2000, StartTime = Time.Current + 2000,
ControlPoint = new TimingControlPoint(), Major = major,
BeatIndex = major ? 0 : 1
}; };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Configuration
{ {
base.InitialiseDefaults(); base.InitialiseDefaults();
Set(ManiaRulesetSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0); Set(ManiaRulesetSetting.ScrollTime, 1500.0, 50.0, 5000.0, 50.0);
Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down); Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
} }

View File

@ -11,7 +11,9 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing; using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
using osu.Game.Rulesets.Mania.Difficulty.Skills; using osu.Game.Rulesets.Mania.Difficulty.Skills;
using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Difficulty namespace osu.Game.Rulesets.Mania.Difficulty
{ {
@ -32,12 +34,15 @@ namespace osu.Game.Rulesets.Mania.Difficulty
if (beatmap.HitObjects.Count == 0) if (beatmap.HitObjects.Count == 0)
return new ManiaDifficultyAttributes { Mods = mods, Skills = skills }; return new ManiaDifficultyAttributes { Mods = mods, Skills = skills };
HitWindows hitWindows = new ManiaHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
return new ManiaDifficultyAttributes return new ManiaDifficultyAttributes
{ {
StarRating = difficultyValue(skills) * star_scaling_factor, StarRating = difficultyValue(skills) * star_scaling_factor,
Mods = mods, Mods = mods,
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate, GreatHitWindow = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate,
Skills = skills Skills = skills
}; };
} }

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Edit
{ {
public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; public new IScrollingInfo ScrollingInfo => base.ScrollingInfo;
public DrawableManiaEditRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) public DrawableManiaEditRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
} }

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Edit
[Cached(Type = typeof(IManiaHitObjectComposer))] [Cached(Type = typeof(IManiaHitObjectComposer))]
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>, IManiaHitObjectComposer public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>, IManiaHitObjectComposer
{ {
protected new DrawableManiaEditRuleset DrawableRuleset { get; private set; } private DrawableManiaEditRuleset drawableRuleset;
public ManiaHitObjectComposer(Ruleset ruleset) public ManiaHitObjectComposer(Ruleset ruleset)
: base(ruleset) : base(ruleset)
@ -33,23 +33,23 @@ namespace osu.Game.Rulesets.Mania.Edit
/// </summary> /// </summary>
/// <param name="screenSpacePosition">The screen-space position.</param> /// <param name="screenSpacePosition">The screen-space position.</param>
/// <returns>The column which intersects with <paramref name="screenSpacePosition"/>.</returns> /// <returns>The column which intersects with <paramref name="screenSpacePosition"/>.</returns>
public Column ColumnAt(Vector2 screenSpacePosition) => DrawableRuleset.GetColumnByPosition(screenSpacePosition); public Column ColumnAt(Vector2 screenSpacePosition) => drawableRuleset.GetColumnByPosition(screenSpacePosition);
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); => dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
public int TotalColumns => ((ManiaPlayfield)DrawableRuleset.Playfield).TotalColumns; public int TotalColumns => ((ManiaPlayfield)drawableRuleset.Playfield).TotalColumns;
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
{ {
DrawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods); drawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods);
// This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it // This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it
dependencies.CacheAs(DrawableRuleset.ScrollingInfo); dependencies.CacheAs(drawableRuleset.ScrollingInfo);
return DrawableRuleset; return drawableRuleset;
} }
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[] protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]

View File

@ -31,10 +31,12 @@ namespace osu.Game.Rulesets.Mania
{ {
public class ManiaRuleset : Ruleset public class ManiaRuleset : Ruleset
{ {
public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) => new DrawableManiaRuleset(this, beatmap, mods); public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods) => new DrawableManiaRuleset(this, beatmap, mods);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
public const string SHORT_NAME = "mania";
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this); public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
@ -163,7 +165,7 @@ namespace osu.Game.Rulesets.Mania
public override string Description => "osu!mania"; public override string Description => "osu!mania";
public override string ShortName => "mania"; public override string ShortName => SHORT_NAME;
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania }; public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania };

View File

@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania
{
public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents>
{
public ManiaSkinComponent(ManiaSkinComponents component)
: base(component)
{
}
protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME;
protected override string ComponentName => Component.ToString().ToLower();
}
}

View File

@ -0,0 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Rulesets.Mania
{
public enum ManiaSkinComponents
{
}
}

View File

@ -1,21 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Mania.Objects
{
public class BarLine : ManiaHitObject
{
/// <summary>
/// The control point which this bar line is part of.
/// </summary>
public TimingControlPoint ControlPoint;
/// <summary>
/// The index of the beat which this bar line represents within the control point.
/// This is a "major" bar line if <see cref="BeatIndex"/> % <see cref="TimingControlPoint.TimeSignature"/> == 0.
/// </summary>
public int BeatIndex;
}
}

View File

@ -4,6 +4,7 @@
using osuTK; using osuTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osuTK.Graphics; using osuTK.Graphics;
@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// Visualises a <see cref="BarLine"/>. Although this derives DrawableManiaHitObject, /// Visualises a <see cref="BarLine"/>. Although this derives DrawableManiaHitObject,
/// this does not handle input/sound like a normal hit object. /// this does not handle input/sound like a normal hit object.
/// </summary> /// </summary>
public class DrawableBarLine : DrawableManiaHitObject<BarLine> public class DrawableBarLine : DrawableHitObject<BarLine>
{ {
/// <summary> /// <summary>
/// Height of major bar line triangles. /// Height of major bar line triangles.
@ -40,9 +41,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Colour = new Color4(255, 204, 33, 255), Colour = new Color4(255, 204, 33, 255),
}); });
bool isMajor = barLine.BeatIndex % (int)barLine.ControlPoint.TimeSignature == 0; if (barLine.Major)
if (isMajor)
{ {
AddInternal(new EquilateralTriangle AddInternal(new EquilateralTriangle
{ {
@ -65,11 +64,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}); });
} }
if (!isMajor && barLine.BeatIndex % 2 == 1) if (!barLine.Major)
Alpha = 0.2f; Alpha = 0.2f;
} }
protected override void UpdateState(ArmedState state) protected override void UpdateInitialTransforms()
{
}
protected override void UpdateStateTransforms(ArmedState state)
{ {
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
@ -8,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
@ -104,6 +106,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2; bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
} }
protected override void UpdateStateTransforms(ArmedState state)
{
using (BeginDelayedSequence(HitObject.Duration, true))
base.UpdateStateTransforms(state);
}
protected void BeginHold() protected void BeginHold()
{ {
holdStartTime = Time.Current; holdStartTime = Time.Current;
@ -202,6 +210,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected override void CheckForResult(bool userTriggered, double timeOffset) protected override void CheckForResult(bool userTriggered, double timeOffset)
{ {
Debug.Assert(HitObject.HitWindows != null);
// Factor in the release lenience // Factor in the release lenience
timeOffset /= release_window_lenience; timeOffset /= release_window_lenience;

View File

@ -45,6 +45,20 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
} }
protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{
case ArmedState.Miss:
this.FadeOut(150, Easing.In);
break;
case ArmedState.Hit:
this.FadeOut(150, Easing.OutQuint);
break;
}
}
} }
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
@ -57,22 +71,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
HitObject = hitObject; HitObject = hitObject;
} }
protected override bool UseTransformStateManagement => false;
protected override void UpdateState(ArmedState state)
{
// TODO: update to use new state management.
switch (state)
{
case ArmedState.Miss:
this.FadeOut(150, Easing.In).Expire();
break;
case ArmedState.Hit:
this.FadeOut(150, Easing.OutQuint).Expire();
break;
}
}
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -17,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction> public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
{ {
public const float CORNER_RADIUS = NotePiece.NOTE_HEIGHT / 2;
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject) public DrawableNote(Note hitObject)
@ -37,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = colour.NewValue.Lighten(1f).Opacity(0.6f), Colour = colour.NewValue.Lighten(1f).Opacity(0.2f),
Radius = 10, Radius = 10,
}; };
}, true); }, true);
@ -52,6 +55,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected override void CheckForResult(bool userTriggered, double timeOffset) protected override void CheckForResult(bool userTriggered, double timeOffset)
{ {
Debug.Assert(HitObject.HitWindows != null);
if (!userTriggered) if (!userTriggered)
{ {
if (!HitObject.HitWindows.CanBeHit(timeOffset)) if (!HitObject.HitWindows.CanBeHit(timeOffset))

View File

@ -26,14 +26,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public BodyPiece() public BodyPiece()
{ {
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Children = new[] Children = new[]
{ {
Background = new Box { RelativeSizeAxes = Axes.Both }, Background = new Box { RelativeSizeAxes = Axes.Both },
Foreground = new BufferedContainer Foreground = new BufferedContainer
{ {
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
CacheDrawnFrameBuffer = true, CacheDrawnFrameBuffer = true,
Children = new Drawable[] Children = new Drawable[]

View File

@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Name = "Top", Name = "Top",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.5f, Height = 0.5f,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha)) Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha))
}, },
new Box new Box
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.5f, Height = 0.5f,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent) Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent)
} }
}; };

View File

@ -18,8 +18,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary> /// </summary>
internal class NotePiece : Container, IHasAccentColour internal class NotePiece : Container, IHasAccentColour
{ {
public const float NOTE_HEIGHT = 10; public const float NOTE_HEIGHT = 12;
private const float head_colour_height = 6;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
@ -39,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
colouredBox = new Box colouredBox = new Box
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = head_colour_height, Height = NOTE_HEIGHT / 2,
Alpha = 0.2f Alpha = 0.1f
} }
}; };
} }

View File

@ -6,6 +6,7 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects namespace osu.Game.Rulesets.Mania.Objects
{ {
@ -99,5 +100,7 @@ namespace osu.Game.Rulesets.Mania.Objects
} }
public override Judgement CreateJudgement() => new HoldNoteJudgement(); public override Judgement CreateJudgement() => new HoldNoteJudgement();
protected override HitWindows CreateHitWindows() => null;
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects namespace osu.Game.Rulesets.Mania.Objects
{ {
@ -12,5 +13,7 @@ namespace osu.Game.Rulesets.Mania.Objects
public class HoldNoteTick : ManiaHitObject public class HoldNoteTick : ManiaHitObject
{ {
public override Judgement CreateJudgement() => new HoldNoteTickJudgement(); public override Judgement CreateJudgement() => new HoldNoteTickJudgement();
protected override HitWindows CreateHitWindows() => null;
} }
} }

View File

@ -3,7 +3,9 @@
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Game.Rulesets.Mania.Objects.Types; using osu.Game.Rulesets.Mania.Objects.Types;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects namespace osu.Game.Rulesets.Mania.Objects
{ {

View File

@ -1,35 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects
{
public class ManiaHitWindows : HitWindows
{
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
{
{ HitResult.Perfect, (44.8, 38.8, 27.8) },
{ HitResult.Great, (128, 98, 68) },
{ HitResult.Good, (194, 164, 134) },
{ HitResult.Ok, (254, 224, 194) },
{ HitResult.Meh, (302, 272, 242) },
{ HitResult.Miss, (376, 346, 316) },
};
public override bool IsHitResultAllowed(HitResult result) => true;
public override void SetDifficulty(double difficulty)
{
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
Ok = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Ok]);
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
}
}
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Replays; using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays;
@ -77,13 +78,37 @@ namespace osu.Game.Rulesets.Mania.Replays
private IEnumerable<IActionPoint> generateActionPoints() private IEnumerable<IActionPoint> generateActionPoints()
{ {
foreach (var obj in Beatmap.HitObjects) for (int i = 0; i < Beatmap.HitObjects.Count; i++)
{ {
yield return new HitPoint { Time = obj.StartTime, Column = obj.Column }; var currentObject = Beatmap.HitObjects[i];
yield return new ReleasePoint { Time = ((obj as IHasEndTime)?.EndTime ?? obj.StartTime) + RELEASE_DELAY, Column = obj.Column }; var nextObjectInColumn = GetNextObject(i); // Get the next object that requires pressing the same button
double endTime = (currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime;
bool canDelayKeyUp = nextObjectInColumn == null ||
nextObjectInColumn.StartTime > endTime + RELEASE_DELAY;
double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInColumn.StartTime - endTime) * 0.9;
yield return new HitPoint { Time = currentObject.StartTime, Column = currentObject.Column };
yield return new ReleasePoint { Time = endTime + calculatedDelay, Column = currentObject.Column };
} }
} }
protected override HitObject GetNextObject(int currentIndex)
{
int desiredColumn = Beatmap.HitObjects[currentIndex].Column;
for (int i = currentIndex + 1; i < Beatmap.HitObjects.Count; i++)
{
if (Beatmap.HitObjects[i].Column == desiredColumn)
return Beatmap.HitObjects[i];
}
return null;
}
private interface IActionPoint private interface IActionPoint
{ {
double Time { get; set; } double Time { get; set; }

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Replays
Actions.AddRange(actions); Actions.AddRange(actions);
} }
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap) public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
{ {
// We don't need to fully convert, just create the converter // We don't need to fully convert, just create the converter
var converter = new ManiaBeatmapConverter(beatmap); var converter = new ManiaBeatmapConverter(beatmap);

View File

@ -1,9 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Rulesets.Taiko.Objects using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Scoring
{ {
public class BarLine : TaikoHitObject public class ManiaHitWindows : HitWindows
{ {
} }
} }

View File

@ -4,7 +4,6 @@
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq; using System.Linq;
@ -11,6 +11,8 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK; using osuTK;
@ -19,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
{ {
private const float column_width = 45; public const float COLUMN_WIDTH = 80;
private const float special_column_width = 70; private const float special_column_width = 70;
/// <summary> /// <summary>
@ -41,10 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI
Index = index; Index = index;
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Width = column_width; Width = COLUMN_WIDTH;
Masking = true;
CornerRadius = 5;
background = new ColumnBackground { RelativeSizeAxes = Axes.Both }; background = new ColumnBackground { RelativeSizeAxes = Axes.Both };
@ -67,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.UI
explosionContainer = new Container explosionContainer = new Container
{ {
Name = "Hit explosions", Name = "Hit explosions",
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both,
} }
} }
}, },
@ -90,6 +89,12 @@ namespace osu.Game.Rulesets.Mania.UI
Bottom = dir.NewValue == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0, Bottom = dir.NewValue == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0,
}; };
explosionContainer.Padding = new MarginPadding
{
Top = dir.NewValue == ScrollingDirection.Up ? NotePiece.NOTE_HEIGHT / 2 : 0,
Bottom = dir.NewValue == ScrollingDirection.Down ? NotePiece.NOTE_HEIGHT / 2 : 0
};
keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
}, true); }, true);
} }
@ -108,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.UI
isSpecial = value; isSpecial = value;
Width = isSpecial ? special_column_width : column_width; Width = isSpecial ? special_column_width : COLUMN_WIDTH;
} }
} }
@ -163,9 +168,10 @@ namespace osu.Game.Rulesets.Mania.UI
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value) if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
return; return;
explosionContainer.Add(new HitExplosion(judgedObject) explosionContainer.Add(new HitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick)
{ {
Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre,
Origin = Anchor.Centre
}); });
} }

View File

@ -35,14 +35,13 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{ {
Name = "Background", Name = "Background",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.3f
}, },
backgroundOverlay = new Box backgroundOverlay = new Box
{ {
Name = "Background Gradient Overlay", Name = "Background Gradient Overlay",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.5f, Height = 0.5f,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0 Alpha = 0
} }
}; };
@ -82,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
if (!IsLoaded) if (!IsLoaded)
return; return;
background.Colour = AccentColour; background.Colour = AccentColour.Darken(5);
var brightPoint = AccentColour.Opacity(0.6f); var brightPoint = AccentColour.Opacity(0.6f);
var dimPoint = AccentColour.Opacity(0); var dimPoint = AccentColour.Opacity(0);

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK.Graphics; using osuTK.Graphics;
@ -17,7 +18,6 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{ {
public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour
{ {
private const float hit_target_height = 10;
private const float hit_target_bar_height = 2; private const float hit_target_bar_height = 2;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
@ -32,7 +32,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components
hitTargetBar = new Box hitTargetBar = new Box
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = hit_target_height, Height = NotePiece.NOTE_HEIGHT,
Alpha = 0.6f,
Colour = Color4.Black Colour = Color4.Black
}, },
hitTargetLine = new Container hitTargetLine = new Container

View File

@ -2,14 +2,11 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Input.Handlers; using osu.Game.Input.Handlers;
using osu.Game.Replays; using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
@ -19,8 +16,8 @@ using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
@ -36,40 +33,16 @@ namespace osu.Game.Rulesets.Mania.UI
public IEnumerable<BarLine> BarLines; public IEnumerable<BarLine> BarLines;
protected override bool RelativeScaleBeatLengths => true;
protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config;
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>(); private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>();
public DrawableManiaRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) public DrawableManiaRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
// Generate the bar lines BarLines = new BarLineGenerator(Beatmap).BarLines;
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
var timingPoints = Beatmap.ControlPointInfo.TimingPoints;
var barLines = new List<BarLine>();
for (int i = 0; i < timingPoints.Count; i++)
{
TimingControlPoint point = timingPoints[i];
// Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object
double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - point.BeatLength : lastObjectTime + point.BeatLength * (int)point.TimeSignature;
int index = 0;
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
{
barLines.Add(new BarLine
{
StartTime = t,
ControlPoint = point,
BeatIndex = index
});
}
}
BarLines = barLines;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -1,16 +1,14 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
@ -18,51 +16,112 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
public override bool RemoveWhenNotAlive => true; public override bool RemoveWhenNotAlive => true;
private readonly CircularContainer circle; private readonly CircularContainer largeFaint;
private readonly CircularContainer mainGlow1;
public HitExplosion(DrawableHitObject judgedObject) public HitExplosion(Color4 objectColour, bool isSmall = false)
{ {
bool isTick = judgedObject is DrawableHoldNoteTick;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Y = NotePiece.NOTE_HEIGHT / 2;
Height = NotePiece.NOTE_HEIGHT; Height = NotePiece.NOTE_HEIGHT;
// scale roughly in-line with visual appearance of notes // scale roughly in-line with visual appearance of notes
Scale = new Vector2(isTick ? 0.4f : 0.8f); Scale = new Vector2(1f, 0.6f);
InternalChild = circle = new CircularContainer if (isSmall)
Scale *= 0.5f;
const float angle_variangle = 15; // should be less than 45
const float roundness = 80;
const float initial_height = 10;
var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1);
InternalChildren = new Drawable[]
{ {
Anchor = Anchor.Centre, largeFaint = new CircularContainer
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
// we want our size to be very small so the glow dominates it.
Size = new Vector2(0.1f),
EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Anchor = Anchor.Centre,
Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour.Value, Color4.White, 0, 1), Origin = Anchor.Centre,
Radius = 100,
},
Child = new Box
{
Alpha = 0,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
AlwaysPresent = true Masking = true,
// we want our size to be very small so the glow dominates it.
Size = new Vector2(0.8f),
Blending = BlendingParameters.Additive,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
Roundness = 160,
Radius = 200,
},
},
mainGlow1 = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Blending = BlendingParameters.Additive,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
Roundness = 20,
Radius = 50,
},
},
new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Size = new Vector2(0.01f, initial_height),
Blending = BlendingParameters.Additive,
Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = colour,
Roundness = roundness,
Radius = 40,
},
},
new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Size = new Vector2(0.01f, initial_height),
Blending = BlendingParameters.Additive,
Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = colour,
Roundness = roundness,
Radius = 40,
},
} }
}; };
} }
protected override void LoadComplete() protected override void LoadComplete()
{ {
const double duration = 200;
base.LoadComplete(); base.LoadComplete();
circle.ResizeTo(circle.Size * new Vector2(4, 20), 1000, Easing.OutQuint); largeFaint
this.FadeIn(16).Then().FadeOut(500, Easing.OutQuint); .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
.FadeOut(duration * 2);
mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint);
this.FadeOut(duration, Easing.Out);
Expire(true); Expire(true);
} }
} }

View File

@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK; using osuTK;

View File

@ -12,6 +12,7 @@ using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -2,12 +2,12 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.IO; using System.Text.RegularExpressions;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
@ -26,40 +26,56 @@ namespace osu.Game.Rulesets.Osu.Tests
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio, SkinManager skinManager)
{ {
var skins = new SkinManager(LocalStorage, ContextFactory, null, audio); var dllStore = new DllResourceStore("osu.Game.Rulesets.Osu.Tests.dll");
metricsSkin = getSkinFromResources(skins, "metrics_skin"); metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/metrics_skin"), audio, true);
defaultSkin = getSkinFromResources(skins, "default_skin"); defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
specialSkin = getSkinFromResources(skins, "special_skin"); specialSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/special_skin"), audio, true);
} }
public void SetContents(Func<Drawable> creationFunction) public void SetContents(Func<Drawable> creationFunction)
{ {
Cell(0).Child = new LocalSkinOverrideContainer(null) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); Cell(0).Child = createProvider(null, creationFunction);
Cell(1).Child = new LocalSkinOverrideContainer(metricsSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); Cell(1).Child = createProvider(metricsSkin, creationFunction);
Cell(2).Child = new LocalSkinOverrideContainer(defaultSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); Cell(2).Child = createProvider(defaultSkin, creationFunction);
Cell(3).Child = new LocalSkinOverrideContainer(specialSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); Cell(3).Child = createProvider(specialSkin, creationFunction);
} }
private static Skin getSkinFromResources(SkinManager skins, string name) private Drawable createProvider(Skin skin, Func<Drawable> creationFunction)
{ {
using (var storage = new DllResourceStore("osu.Game.Rulesets.Osu.Tests.dll")) var mainProvider = new SkinProvidingContainer(skin);
return mainProvider
.WithChild(new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider))
{
Child = creationFunction()
});
}
private class TestLegacySkin : LegacySkin
{
private readonly bool extrapolateAnimations;
public TestLegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager, bool extrapolateAnimations)
: base(skin, storage, audioManager, "skin.ini")
{ {
var tempName = Path.GetTempFileName(); this.extrapolateAnimations = extrapolateAnimations;
}
File.Delete(tempName); public override Texture GetTexture(string componentName)
Directory.CreateDirectory(tempName); {
// extrapolate frames to test longer animations
if (extrapolateAnimations)
{
var match = Regex.Match(componentName, "-([0-9]*)");
var files = storage.GetAvailableResources().Where(f => f.StartsWith($"Resources/{name}")); if (match.Length > 0 && int.TryParse(match.Groups[1].Value, out var number) && number < 60)
return base.GetTexture(componentName.Replace($"-{number}", $"-{number % 2}"));
}
foreach (var file in files) return base.GetTexture(componentName);
using (var stream = storage.GetStream(file))
using (var newFile = File.Create(Path.Combine(tempName, Path.GetFileName(file))))
stream.CopyTo(newFile);
return skins.GetSkin(skins.Import(tempName).Result);
} }
} }
} }

View File

@ -0,0 +1,128 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Testing.Input;
using osu.Game.Audio;
using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneCursorTrail : OsuTestScene
{
[Test]
public void TestSmoothCursorTrail()
{
Container scalingContainer = null;
createTest(() => scalingContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Child = new CursorTrail()
});
AddStep("set large scale", () => scalingContainer.Scale = new Vector2(10));
}
[Test]
public void TestLegacySmoothCursorTrail()
{
createTest(() => new LegacySkinContainer(false)
{
Child = new LegacyCursorTrail()
});
}
[Test]
public void TestLegacyDisjointCursorTrail()
{
createTest(() => new LegacySkinContainer(true)
{
Child = new LegacyCursorTrail()
});
}
private void createTest(Func<Drawable> createContent) => AddStep("create trail", () =>
{
Clear();
Add(new Container
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f),
Child = new MovingCursorInputManager { Child = createContent?.Invoke() }
});
});
[Cached(typeof(ISkinSource))]
private class LegacySkinContainer : Container, ISkinSource
{
private readonly bool disjoint;
public LegacySkinContainer(bool disjoint)
{
this.disjoint = disjoint;
RelativeSizeAxes = Axes.Both;
}
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException();
public Texture GetTexture(string componentName)
{
switch (componentName)
{
case "cursortrail":
var tex = new Texture(Texture.WhitePixel.TextureGL);
if (disjoint)
tex.ScaleAdjust = 1 / 25f;
return tex;
case "cursormiddle":
return disjoint ? null : Texture.WhitePixel;
}
return null;
}
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
public event Action SourceChanged;
}
private class MovingCursorInputManager : ManualInputManager
{
public MovingCursorInputManager()
{
UseParentInput = false;
}
protected override void Update()
{
base.Update();
const double spin_duration = 1000;
double currentTime = Time.Current;
double angle = (currentTime % spin_duration) / spin_duration * 2 * Math.PI;
Vector2 rPos = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
MoveMouseTo(ToScreenSpace(DrawSize / 2 + DrawSize / 3 * rPos));
}
}
}
}

View File

@ -0,0 +1,35 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneDrawableJudgement : SkinnableTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(DrawableJudgement),
typeof(DrawableOsuJudgement)
};
public TestSceneDrawableJudgement()
{
foreach (HitResult result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Skip(1))
AddStep("Show " + result.GetDescription(), () => SetContents(() =>
new DrawableOsuJudgement(new JudgementResult(new HitObject(), new Judgement()) { Type = result }, null)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}));
}
}
}

View File

@ -6,29 +6,68 @@ using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor; using osu.Framework.Testing.Input;
using osu.Game.Graphics.Cursor;
using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Rulesets.UI; using osuTK;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
{ {
[TestFixture] [TestFixture]
public class TestSceneGameplayCursor : OsuTestScene, IProvideCursor public class TestSceneGameplayCursor : SkinnableTestScene
{ {
private GameplayCursorContainer cursorContainer; public override IReadOnlyList<Type> RequiredTypes => new[]
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(CursorTrail) }; typeof(OsuCursorContainer),
typeof(CursorTrail)
public CursorContainer Cursor => cursorContainer; };
public bool ProvidingUserCursor => true;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Add(cursorContainer = new OsuCursorContainer { RelativeSizeAxes = Axes.Both }); SetContents(() => new MovingCursorInputManager
{
Child = new ClickingCursorContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
}
});
}
private class ClickingCursorContainer : OsuCursorContainer
{
protected override void Update()
{
base.Update();
double currentTime = Time.Current;
if (((int)(currentTime / 1000)) % 2 == 0)
OnPressed(OsuAction.LeftButton);
else
OnReleased(OsuAction.LeftButton);
}
}
private class MovingCursorInputManager : ManualInputManager
{
public MovingCursorInputManager()
{
UseParentInput = false;
}
protected override void Update()
{
base.Update();
const double spin_duration = 5000;
double currentTime = Time.Current;
double angle = (currentTime % spin_duration) / spin_duration * 2 * Math.PI;
Vector2 rPos = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
MoveMouseTo(ToScreenSpace(DrawSize / 2 + DrawSize / 3 * rPos));
}
} }
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -13,8 +14,10 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
var drawableHitObject = base.CreateDrawableHitCircle(circle, auto); var drawableHitObject = base.CreateDrawableHitCircle(circle, auto);
Scheduler.AddDelayed(() => drawableHitObject.TriggerJudgement(), Debug.Assert(drawableHitObject.HitObject.HitWindows != null);
drawableHitObject.HitObject.StartTime - (drawableHitObject.HitObject.HitWindows.HalfWindowFor(HitResult.Miss) + RNG.Next(0, 300)) - Time.Current);
double delay = drawableHitObject.HitObject.StartTime - (drawableHitObject.HitObject.HitWindows.WindowFor(HitResult.Miss) + RNG.Next(0, 300)) - Time.Current;
Scheduler.AddDelayed(() => drawableHitObject.TriggerJudgement(), delay);
return drawableHitObject; return drawableHitObject;
} }

View File

@ -0,0 +1,159 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Timing;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
public class TestSceneSkinFallbacks : PlayerTestScene
{
private readonly TestSource testUserSkin;
private readonly TestSource testBeatmapSkin;
public TestSceneSkinFallbacks()
: base(new OsuRuleset())
{
testUserSkin = new TestSource("user");
testBeatmapSkin = new TestSource("beatmap");
}
[Test]
public void TestBeatmapSkinDefault()
{
AddStep("enable user provider", () => testUserSkin.Enabled = true);
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
checkNextHitObject("beatmap");
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
checkNextHitObject("user");
AddStep("disable user provider", () => testUserSkin.Enabled = false);
checkNextHitObject(null);
}
private void checkNextHitObject(string skin) =>
AddUntilStep($"check skin from {skin}", () =>
{
var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.OfType<DrawableHitCircle>().FirstOrDefault();
if (firstObject == null)
return false;
var skinnable = firstObject.ApproachCircle.Child as SkinnableDrawable;
if (skin == null && skinnable?.Drawable is Sprite)
// check for default skin provider
return true;
var text = skinnable?.Drawable as SpriteText;
return text?.Text == skin;
});
[Resolved]
private AudioManager audio { get; set; }
protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) => new CustomSkinWorkingBeatmap(beatmap, Clock, audio, testBeatmapSkin);
public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
{
private readonly ISkinSource skin;
public CustomSkinWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin)
: base(beatmap, frameBasedClock, audio)
{
this.skin = skin;
}
protected override ISkin GetSkin() => skin;
}
public class SkinProvidingPlayer : TestPlayer
{
private readonly TestSource userSkin;
public SkinProvidingPlayer(TestSource userSkin)
{
this.userSkin = userSkin;
}
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<ISkinSource>(userSkin);
return dependencies;
}
}
public class TestSource : ISkinSource
{
private readonly string identifier;
public TestSource(string identifier)
{
this.identifier = identifier;
}
public Drawable GetDrawableComponent(ISkinComponent component)
{
if (!enabled) return null;
return new SpriteText
{
Text = identifier,
Font = OsuFont.Default.With(size: 30),
};
}
public Texture GetTexture(string componentName) => null;
public SampleChannel GetSample(ISampleInfo sampleInfo) => null;
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => default;
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => null;
public event Action SourceChanged;
private bool enabled = true;
public bool Enabled
{
get => enabled;
set
{
if (value == enabled)
return;
enabled = value;
SourceChanged?.Invoke();
}
}
}
}
}

View File

@ -10,7 +10,6 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -27,83 +26,96 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
{ {
[TestFixture] [TestFixture]
public class TestSceneSlider : OsuTestScene public class TestSceneSlider : SkinnableTestScene
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(Slider),
typeof(SliderTick),
typeof(SliderTailCircle),
typeof(SliderBall), typeof(SliderBall),
typeof(SliderBody), typeof(SliderBody),
typeof(SliderTick), typeof(SnakingSliderBody),
typeof(DrawableSlider), typeof(DrawableSlider),
typeof(DrawableSliderTick), typeof(DrawableSliderTick),
typeof(DrawableSliderTail),
typeof(DrawableSliderHead),
typeof(DrawableRepeatPoint), typeof(DrawableRepeatPoint),
typeof(DrawableOsuHitObject) typeof(DrawableOsuHitObject)
}; };
private readonly Container content; private Container content;
protected override Container<Drawable> Content => content;
protected override Container<Drawable> Content
{
get
{
if (content == null)
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
return content;
}
}
private int depthIndex; private int depthIndex;
public TestSceneSlider() public TestSceneSlider()
{ {
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); AddStep("Big Single", () => SetContents(() => testSimpleBig()));
AddStep("Medium Single", () => SetContents(() => testSimpleMedium()));
AddStep("Small Single", () => SetContents(() => testSimpleSmall()));
AddStep("Big 1 Repeat", () => SetContents(() => testSimpleBig(1)));
AddStep("Medium 1 Repeat", () => SetContents(() => testSimpleMedium(1)));
AddStep("Small 1 Repeat", () => SetContents(() => testSimpleSmall(1)));
AddStep("Big 2 Repeats", () => SetContents(() => testSimpleBig(2)));
AddStep("Medium 2 Repeats", () => SetContents(() => testSimpleMedium(2)));
AddStep("Small 2 Repeats", () => SetContents(() => testSimpleSmall(2)));
AddStep("Big Single", () => testSimpleBig()); AddStep("Slow Slider", () => SetContents(testSlowSpeed)); // slow long sliders take ages already so no repeat steps
AddStep("Medium Single", () => testSimpleMedium()); AddStep("Slow Short Slider", () => SetContents(() => testShortSlowSpeed()));
AddStep("Small Single", () => testSimpleSmall()); AddStep("Slow Short Slider 1 Repeats", () => SetContents(() => testShortSlowSpeed(1)));
AddStep("Big 1 Repeat", () => testSimpleBig(1)); AddStep("Slow Short Slider 2 Repeats", () => SetContents(() => testShortSlowSpeed(2)));
AddStep("Medium 1 Repeat", () => testSimpleMedium(1));
AddStep("Small 1 Repeat", () => testSimpleSmall(1));
AddStep("Big 2 Repeats", () => testSimpleBig(2));
AddStep("Medium 2 Repeats", () => testSimpleMedium(2));
AddStep("Small 2 Repeats", () => testSimpleSmall(2));
AddStep("Slow Slider", testSlowSpeed); // slow long sliders take ages already so no repeat steps AddStep("Fast Slider", () => SetContents(() => testHighSpeed()));
AddStep("Slow Short Slider", () => testShortSlowSpeed()); AddStep("Fast Slider 1 Repeat", () => SetContents(() => testHighSpeed(1)));
AddStep("Slow Short Slider 1 Repeats", () => testShortSlowSpeed(1)); AddStep("Fast Slider 2 Repeats", () => SetContents(() => testHighSpeed(2)));
AddStep("Slow Short Slider 2 Repeats", () => testShortSlowSpeed(2)); AddStep("Fast Short Slider", () => SetContents(() => testShortHighSpeed()));
AddStep("Fast Short Slider 1 Repeat", () => SetContents(() => testShortHighSpeed(1)));
AddStep("Fast Short Slider 2 Repeats", () => SetContents(() => testShortHighSpeed(2)));
AddStep("Fast Short Slider 6 Repeats", () => SetContents(() => testShortHighSpeed(6)));
AddStep("Fast Slider", () => testHighSpeed()); AddStep("Perfect Curve", () => SetContents(() => testPerfect()));
AddStep("Fast Slider 1 Repeat", () => testHighSpeed(1)); AddStep("Perfect Curve 1 Repeat", () => SetContents(() => testPerfect(1)));
AddStep("Fast Slider 2 Repeats", () => testHighSpeed(2)); AddStep("Perfect Curve 2 Repeats", () => SetContents(() => testPerfect(2)));
AddStep("Fast Short Slider", () => testShortHighSpeed());
AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1));
AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2));
AddStep("Fast Short Slider 6 Repeats", () => testShortHighSpeed(6));
AddStep("Perfect Curve", () => testPerfect()); AddStep("Linear Slider", () => SetContents(() => testLinear()));
AddStep("Perfect Curve 1 Repeat", () => testPerfect(1)); AddStep("Linear Slider 1 Repeat", () => SetContents(() => testLinear(1)));
AddStep("Perfect Curve 2 Repeats", () => testPerfect(2)); AddStep("Linear Slider 2 Repeats", () => SetContents(() => testLinear(2)));
AddStep("Linear Slider", () => testLinear()); AddStep("Bezier Slider", () => SetContents(() => testBezier()));
AddStep("Linear Slider 1 Repeat", () => testLinear(1)); AddStep("Bezier Slider 1 Repeat", () => SetContents(() => testBezier(1)));
AddStep("Linear Slider 2 Repeats", () => testLinear(2)); AddStep("Bezier Slider 2 Repeats", () => SetContents(() => testBezier(2)));
AddStep("Bezier Slider", () => testBezier()); AddStep("Linear Overlapping", () => SetContents(() => testLinearOverlapping()));
AddStep("Bezier Slider 1 Repeat", () => testBezier(1)); AddStep("Linear Overlapping 1 Repeat", () => SetContents(() => testLinearOverlapping(1)));
AddStep("Bezier Slider 2 Repeats", () => testBezier(2)); AddStep("Linear Overlapping 2 Repeats", () => SetContents(() => testLinearOverlapping(2)));
AddStep("Linear Overlapping", () => testLinearOverlapping()); AddStep("Catmull Slider", () => SetContents(() => testCatmull()));
AddStep("Linear Overlapping 1 Repeat", () => testLinearOverlapping(1)); AddStep("Catmull Slider 1 Repeat", () => SetContents(() => testCatmull(1)));
AddStep("Linear Overlapping 2 Repeats", () => testLinearOverlapping(2)); AddStep("Catmull Slider 2 Repeats", () => SetContents(() => testCatmull(2)));
AddStep("Catmull Slider", () => testCatmull()); AddStep("Big Single, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset()));
AddStep("Catmull Slider 1 Repeat", () => testCatmull(1)); AddStep("Big 1 Repeat, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset(1)));
AddStep("Catmull Slider 2 Repeats", () => testCatmull(2));
AddStep("Big Single, Large StackOffset", () => testSimpleBigLargeStackOffset()); AddStep("Distance Overflow", () => SetContents(() => testDistanceOverflow()));
AddStep("Big 1 Repeat, Large StackOffset", () => testSimpleBigLargeStackOffset(1)); AddStep("Distance Overflow 1 Repeat", () => SetContents(() => testDistanceOverflow(1)));
AddStep("Distance Overflow", () => testDistanceOverflow());
AddStep("Distance Overflow 1 Repeat", () => testDistanceOverflow(1));
} }
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats); private Drawable testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
private void testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10); private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
private void testDistanceOverflow(int repeats = 0) private Drawable testDistanceOverflow(int repeats = 0)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -120,22 +132,22 @@ namespace osu.Game.Rulesets.Osu.Tests
StackHeight = 10 StackHeight = 10
}; };
addSlider(slider, 2, 2); return createDrawable(slider, 2, 2);
} }
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats); private Drawable testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats); private Drawable testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
private void testSlowSpeed() => createSlider(speedMultiplier: 0.5); private Drawable testSlowSpeed() => createSlider(speedMultiplier: 0.5);
private void testShortSlowSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 0.5); private Drawable testShortSlowSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 0.5);
private void testHighSpeed(int repeats = 0) => createSlider(repeats: repeats, speedMultiplier: 15); private Drawable testHighSpeed(int repeats = 0) => createSlider(repeats: repeats, speedMultiplier: 15);
private void testShortHighSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 15); private Drawable testShortHighSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 15);
private void createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2, int stackHeight = 0) private Drawable createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2, int stackHeight = 0)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -151,10 +163,10 @@ namespace osu.Game.Rulesets.Osu.Tests
StackHeight = stackHeight StackHeight = stackHeight
}; };
addSlider(slider, circleSize, speedMultiplier); return createDrawable(slider, circleSize, speedMultiplier);
} }
private void testPerfect(int repeats = 0) private Drawable testPerfect(int repeats = 0)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -170,12 +182,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testLinear(int repeats = 0) => createLinear(repeats); private Drawable testLinear(int repeats = 0) => createLinear(repeats);
private void createLinear(int repeats) private Drawable createLinear(int repeats)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -194,12 +206,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testBezier(int repeats = 0) => createBezier(repeats); private Drawable testBezier(int repeats = 0) => createBezier(repeats);
private void createBezier(int repeats) private Drawable createBezier(int repeats)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -217,12 +229,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testLinearOverlapping(int repeats = 0) => createOverlapping(repeats); private Drawable testLinearOverlapping(int repeats = 0) => createOverlapping(repeats);
private void createOverlapping(int repeats) private Drawable createOverlapping(int repeats)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -241,12 +253,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testCatmull(int repeats = 0) => createCatmull(repeats); private Drawable testCatmull(int repeats = 0) => createCatmull(repeats);
private void createCatmull(int repeats = 0) private Drawable createCatmull(int repeats = 0)
{ {
var repeatSamples = new List<List<HitSampleInfo>>(); var repeatSamples = new List<List<HitSampleInfo>>();
for (int i = 0; i < repeats; i++) for (int i = 0; i < repeats; i++)
@ -267,7 +279,7 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = repeatSamples NodeSamples = repeatSamples
}; };
addSlider(slider, 3, 1); return createDrawable(slider, 3, 1);
} }
private List<List<HitSampleInfo>> createEmptySamples(int repeats) private List<List<HitSampleInfo>> createEmptySamples(int repeats)
@ -278,7 +290,7 @@ namespace osu.Game.Rulesets.Osu.Tests
return repeatSamples; return repeatSamples;
} }
private void addSlider(Slider slider, float circleSize, double speedMultiplier) private Drawable createDrawable(Slider slider, float circleSize, double speedMultiplier)
{ {
var cpi = new ControlPointInfo(); var cpi = new ControlPointInfo();
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier }); cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
@ -296,7 +308,7 @@ namespace osu.Game.Rulesets.Osu.Tests
drawable.OnNewResult += onNewResult; drawable.OnNewResult += onNewResult;
Add(drawable); return drawable;
} }
private float judgementOffsetDirection = 1; private float judgementOffsetDirection = 1;

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -13,6 +13,8 @@ using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Difficulty.Skills;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Difficulty namespace osu.Game.Rulesets.Osu.Difficulty
{ {
@ -34,8 +36,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
HitWindows hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed 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) / clockRate; double hitWindowGreat = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate;
double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate; double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate;
int maxCombo = beatmap.HitObjects.Count; int maxCombo = beatmap.HitObjects.Count;

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Edit
{ {
public class DrawableOsuEditRuleset : DrawableOsuRuleset public class DrawableOsuEditRuleset : DrawableOsuRuleset
{ {
public DrawableOsuEditRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) public DrawableOsuEditRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
} }

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit
{ {
} }
protected override DrawableRuleset<OsuHitObject> CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList<Mod> mods) protected override DrawableRuleset<OsuHitObject> CreateDrawableRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
=> new DrawableOsuEditRuleset(ruleset, beatmap, mods); => new DrawableOsuEditRuleset(ruleset, beatmap, mods);
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[] protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Osu.Judgements namespace osu.Game.Rulesets.Osu.Judgements
{ {
@ -9,8 +10,8 @@ namespace osu.Game.Rulesets.Osu.Judgements
{ {
public ComboResult ComboType; public ComboResult ComboType;
public OsuJudgementResult(Judgement judgement) public OsuJudgementResult(HitObject hitObject, Judgement judgement)
: base(judgement) : base(hitObject, judgement)
{ {
} }
} }

View File

@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Osu.Mods
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(TextureStore textures) private void load(TextureStore textures)
{ {
Texture = textures.Get("Play/osu/blinds-panel"); Texture = textures.Get("Gameplay/osu/blinds-panel");
} }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
@ -38,7 +39,12 @@ namespace osu.Game.Rulesets.Osu.Mods
if ((osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime) || osuHit.IsHit) if ((osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime) || osuHit.IsHit)
continue; continue;
requiresHit |= osuHit is DrawableHitCircle && osuHit.IsHovered && osuHit.HitObject.HitWindows.CanBeHit(relativetime); if (osuHit is DrawableHitCircle && osuHit.IsHovered)
{
Debug.Assert(osuHit.HitObject.HitWindows != null);
requiresHit |= osuHit.HitObject.HitWindows.CanBeHit(relativetime);
}
requiresHold |= (osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered)) || osuHit is DrawableSpinner; requiresHold |= (osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered)) || osuHit is DrawableSpinner;
} }

View File

@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{ {
Origin = Anchor.Centre; Origin = Anchor.Centre;
Child = new SkinnableDrawable("Play/osu/followpoint", _ => new Container Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.FollowPoint), _ => new Container
{ {
Masking = true, Masking = true,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
Child = new Box Child = new Box
{ {
Size = new Vector2(width), Size = new Vector2(width),
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Alpha = 0.5f, Alpha = 0.5f,

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -9,8 +10,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using osuTK;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osuTK;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
@ -29,6 +30,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly HitArea hitArea; private readonly HitArea hitArea;
private readonly SkinnableDrawable mainContent;
public DrawableHitCircle(HitCircle h) public DrawableHitCircle(HitCircle h)
: base(h) : base(h)
{ {
@ -56,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
return true; return true;
}, },
}, },
new SkinnableDrawable("Play/osu/hitcircle", _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), mainContent = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)),
ApproachCircle = new ApproachCircle ApproachCircle = new ApproachCircle
{ {
Alpha = 0, Alpha = 0,
@ -83,8 +86,30 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue, true); AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue, true);
} }
public override double LifetimeStart
{
get => base.LifetimeStart;
set
{
base.LifetimeStart = value;
ApproachCircle.LifetimeStart = value;
}
}
public override double LifetimeEnd
{
get => base.LifetimeEnd;
set
{
base.LifetimeEnd = value;
ApproachCircle.LifetimeEnd = value;
}
}
protected override void CheckForResult(bool userTriggered, double timeOffset) protected override void CheckForResult(bool userTriggered, double timeOffset)
{ {
Debug.Assert(HitObject.HitWindows != null);
if (!userTriggered) if (!userTriggered)
{ {
if (!HitObject.HitWindows.CanBeHit(timeOffset)) if (!HitObject.HitWindows.CanBeHit(timeOffset))
@ -97,7 +122,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (result == HitResult.None) if (result == HitResult.None)
{ {
Shake(Math.Abs(timeOffset) - HitObject.HitWindows.HalfWindowFor(HitResult.Miss)); Shake(Math.Abs(timeOffset) - HitObject.HitWindows.WindowFor(HitResult.Miss));
return; return;
} }
@ -108,6 +133,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
base.UpdateInitialTransforms(); base.UpdateInitialTransforms();
mainContent.FadeInFromZero(HitObject.TimeFadeIn);
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1f, HitObject.TimePreempt); ApproachCircle.ScaleTo(1f, HitObject.TimePreempt);
ApproachCircle.Expire(true); ApproachCircle.Expire(true);
@ -115,6 +142,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdateStateTransforms(ArmedState state) protected override void UpdateStateTransforms(ArmedState state)
{ {
base.UpdateStateTransforms(state);
Debug.Assert(HitObject.HitWindows != null);
switch (state) switch (state)
{ {
case ArmedState.Idle: case ArmedState.Idle:
@ -123,22 +154,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Expire(true); Expire(true);
hitArea.HitAction = null; hitArea.HitAction = null;
// override lifetime end as FadeIn may have been changed externally, causing out expiration to be too early.
LifetimeEnd = HitObject.StartTime + HitObject.HitWindows.HalfWindowFor(HitResult.Miss);
break; break;
case ArmedState.Miss: case ArmedState.Miss:
ApproachCircle.FadeOut(50); ApproachCircle.FadeOut(50);
this.FadeOut(100); this.FadeOut(100);
Expire();
break; break;
case ArmedState.Hit: case ArmedState.Hit:
ApproachCircle.FadeOut(50); ApproachCircle.FadeOut(50);
// todo: temporary / arbitrary // todo: temporary / arbitrary
this.Delay(800).Expire(); this.Delay(800).FadeOut();
break; break;
} }
} }

View File

@ -36,13 +36,24 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
protected override void UpdateInitialTransforms() => this.FadeIn(HitObject.TimeFadeIn);
private OsuInputManager osuActionInputManager; private OsuInputManager osuActionInputManager;
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager); internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
protected virtual void Shake(double maximumLength) => shakeContainer.Shake(maximumLength); protected virtual void Shake(double maximumLength) => shakeContainer.Shake(maximumLength);
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement); protected override void UpdateStateTransforms(ArmedState state)
{
base.UpdateStateTransforms(state);
switch (state)
{
case ArmedState.Idle:
// Manually set to reduce the number of future alive objects to a bare minimum.
LifetimeStart = HitObject.StartTime - HitObject.TimePreempt;
break;
}
}
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(HitObject, judgement);
} }
} }

View File

@ -9,8 +9,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osuTK;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
@ -32,10 +32,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Origin = Anchor.Centre; Origin = Anchor.Centre;
InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon InternalChild = scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.Solid.ChevronRight, Icon = FontAwesome.Solid.ChevronRight,
@ -74,6 +74,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdateStateTransforms(ArmedState state) protected override void UpdateStateTransforms(ArmedState state)
{ {
base.UpdateStateTransforms(state);
switch (state) switch (state)
{ {
case ArmedState.Idle: case ArmedState.Idle:

View File

@ -12,6 +12,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Configuration;
using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Skinning; using osu.Game.Skinning;
@ -93,6 +94,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
} }
} }
protected override void UpdateInitialTransforms()
{
base.UpdateInitialTransforms();
Body.FadeInFromZero(HitObject.TimeFadeIn);
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -159,12 +167,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
base.SkinChanged(skin, allowFallback); base.SkinChanged(skin, allowFallback);
Body.BorderSize = skin.GetValue<SkinConfiguration, float?>(s => s.SliderBorderSize) ?? SliderBody.DEFAULT_BORDER_SIZE; Body.BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE;
sliderPathRadius = skin.GetValue<SkinConfiguration, float?>(s => s.SliderPathRadius) ?? OsuHitObject.OBJECT_RADIUS; sliderPathRadius = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS;
updatePathRadius(); updatePathRadius();
Body.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : (Color4?)null) ?? AccentColour.Value; Body.AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? AccentColour.Value;
Body.BorderColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : (Color4?)null) ?? Color4.White; Body.BorderColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBorder)?.Value ?? Color4.White;
} }
private void updatePathRadius() => Body.PathRadius = slider.Scale * sliderPathRadius; private void updatePathRadius() => Body.PathRadius = slider.Scale * sliderPathRadius;
@ -194,6 +202,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdateStateTransforms(ArmedState state) protected override void UpdateStateTransforms(ArmedState state)
{ {
base.UpdateStateTransforms(state);
Ball.FadeIn(); Ball.FadeIn();
Ball.ScaleTo(HitObject.Scale); Ball.ScaleTo(HitObject.Scale);
@ -211,10 +221,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
break; break;
} }
this.FadeOut(fade_out_time, Easing.OutQuint).Expire(); this.FadeOut(fade_out_time, Easing.OutQuint);
} }
Expire(true);
} }
public Drawable ProxiedLayer => HeadCircle.ApproachCircle; public Drawable ProxiedLayer => HeadCircle.ApproachCircle;

View File

@ -8,9 +8,9 @@ using osu.Game.Rulesets.Objects.Drawables;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Origin = Anchor.Centre; Origin = Anchor.Centre;
InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new CircularContainer InternalChild = scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer
{ {
Masking = true, Masking = true,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -75,6 +75,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdateStateTransforms(ArmedState state) protected override void UpdateStateTransforms(ArmedState state)
{ {
base.UpdateStateTransforms(state);
switch (state) switch (state)
{ {
case ArmedState.Idle: case ArmedState.Idle:

View File

@ -13,8 +13,8 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Screens.Ranking;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Ranking;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
@ -215,14 +215,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdateStateTransforms(ArmedState state) protected override void UpdateStateTransforms(ArmedState state)
{ {
base.UpdateStateTransforms(state);
var sequence = this.Delay(Spinner.Duration).FadeOut(160); var sequence = this.Delay(Spinner.Duration).FadeOut(160);
switch (state) switch (state)
{ {
case ArmedState.Idle:
Expire(true);
break;
case ArmedState.Hit: case ArmedState.Hit:
sequence.ScaleTo(Scale * 1.2f, 320, Easing.Out); sequence.ScaleTo(Scale * 1.2f, 320, Easing.Out);
break; break;
@ -231,8 +229,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
sequence.ScaleTo(Scale * 0.8f, 320, Easing.In); sequence.ScaleTo(Scale * 0.8f, 320, Easing.In);
break; break;
} }
Expire();
} }
} }
} }

View File

@ -31,13 +31,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private class SkinnableApproachCircle : SkinnableSprite private class SkinnableApproachCircle : SkinnableSprite
{ {
public SkinnableApproachCircle() public SkinnableApproachCircle()
: base("Play/osu/approachcircle") : base("Gameplay/osu/approachcircle")
{ {
} }
protected override Drawable CreateDefault(string name) protected override Drawable CreateDefault(ISkinComponent component)
{ {
var drawable = base.CreateDefault(name); var drawable = base.CreateDefault(component);
// account for the sprite being used for the default approach circle being taken from stable, // account for the sprite being used for the default approach circle being taken from stable,
// when hitcircles have 5px padding on each size. this should be removed if we update the sprite. // when hitcircles have 5px padding on each size. this should be removed if we update the sprite.

View File

@ -31,12 +31,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Texture = textures.Get(@"Play/osu/disc"), Texture = textures.Get(@"Gameplay/osu/disc"),
}, },
new TrianglesPiece new TrianglesPiece
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0.5f, Alpha = 0.5f,
} }
}; };

View File

@ -3,7 +3,6 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Skinning;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
@ -17,15 +16,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Alpha = 0; Alpha = 0;
Child = new SkinnableDrawable("Play/osu/hitcircle-explode", _ => new TrianglesPiece Child = new TrianglesPiece
{ {
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.2f, Alpha = 0.2f,
}, s => s.GetTexture("Play/osu/hitcircle") == null); };
} }
} }
} }

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