Merge branch 'master' into update-overlay-headers
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="RiderProjectSettingsUpdater">
|
<component name="RiderProjectSettingsUpdater">
|
||||||
<option name="vcsConfiguration" value="1" />
|
<option name="vcsConfiguration" value="2" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -5,6 +5,6 @@
|
|||||||
"version": "3.1.100"
|
"version": "3.1.100"
|
||||||
},
|
},
|
||||||
"msbuild-sdks": {
|
"msbuild-sdks": {
|
||||||
"Microsoft.Build.Traversal": "2.0.24"
|
"Microsoft.Build.Traversal": "2.0.34"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.403.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.319.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.407.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
21
osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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 osu.Game.Rulesets.Catch.Skinning;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
public abstract class CatchSkinnableTestScene : SkinnableTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(CatchRuleset),
|
||||||
|
typeof(CatchLegacySkinTransformer),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override Ruleset CreateRulesetForSkinProvider() => new CatchRuleset();
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -4,21 +4,21 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneCatcher : SkinnableTestScene
|
public class TestSceneCatcher : CatchSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||||
{
|
{
|
||||||
typeof(CatcherArea),
|
typeof(CatcherArea),
|
||||||
typeof(CatcherSprite)
|
typeof(CatcherSprite)
|
||||||
};
|
}).ToList();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -17,12 +17,11 @@ using osu.Game.Rulesets.Catch.UI;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneCatcherArea : SkinnableTestScene
|
public class TestSceneCatcherArea : CatchSkinnableTestScene
|
||||||
{
|
{
|
||||||
private RulesetInfo catchRuleset;
|
private RulesetInfo catchRuleset;
|
||||||
|
|
||||||
|
@ -3,20 +3,20 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneFruitObjects : SkinnableTestScene
|
public class TestSceneFruitObjects : CatchSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||||
{
|
{
|
||||||
typeof(CatchHitObject),
|
typeof(CatchHitObject),
|
||||||
typeof(Fruit),
|
typeof(Fruit),
|
||||||
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
typeof(DrawableBanana),
|
typeof(DrawableBanana),
|
||||||
typeof(DrawableBananaShower),
|
typeof(DrawableBananaShower),
|
||||||
typeof(Pulp),
|
typeof(Pulp),
|
||||||
};
|
}).ToList();
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
new KeyBinding(InputKey.Shift, CatchAction.Dash),
|
new KeyBinding(InputKey.Shift, CatchAction.Dash),
|
||||||
};
|
};
|
||||||
|
|
||||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||||
{
|
{
|
||||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||||
yield return new CatchModNightcore();
|
yield return new CatchModNightcore();
|
||||||
@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new CatchLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
|
@ -72,10 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
protected override Skill[] CreateSkills(IBeatmap beatmap)
|
protected override Skill[] CreateSkills(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
using (var catcher = new Catcher(beatmap.BeatmapInfo.BaseDifficulty))
|
using (var catcher = new Catcher(beatmap.BeatmapInfo.BaseDifficulty))
|
||||||
{
|
|
||||||
halfCatcherWidth = catcher.CatchWidth * 0.5f;
|
halfCatcherWidth = catcher.CatchWidth * 0.5f;
|
||||||
halfCatcherWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay.
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Skill[]
|
return new Skill[]
|
||||||
{
|
{
|
||||||
|
@ -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.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -30,6 +31,22 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
Value = 5,
|
Value = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public override string SettingDescription
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string circleSize = CircleSize.IsDefault ? string.Empty : $"CS {CircleSize.Value:N1}";
|
||||||
|
string approachRate = ApproachRate.IsDefault ? string.Empty : $"AR {ApproachRate.Value:N1}";
|
||||||
|
|
||||||
|
return string.Join(", ", new[]
|
||||||
|
{
|
||||||
|
circleSize,
|
||||||
|
base.SettingDescription,
|
||||||
|
approachRate
|
||||||
|
}.Where(s => !string.IsNullOrEmpty(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void TransferSettings(BeatmapDifficulty difficulty)
|
protected override void TransferSettings(BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.TransferSettings(difficulty);
|
base.TransferSettings(difficulty);
|
||||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||||
{
|
{
|
||||||
Position = currentFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
Position = currentFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
||||||
Dashing = currentFrame.ButtonState == ReplayButtonState.Left1;
|
Dashing = currentFrame.ButtonState == ReplayButtonState.Left1;
|
||||||
@ -56,5 +56,14 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
Actions.Add(CatchAction.MoveLeft);
|
Actions.Add(CatchAction.MoveLeft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
ReplayButtonState state = ReplayButtonState.None;
|
||||||
|
|
||||||
|
if (Actions.Contains(CatchAction.Dash)) state |= ReplayButtonState.Left1;
|
||||||
|
|
||||||
|
return new LegacyReplayFrame(Time, Position * CatchPlayfield.BASE_WIDTH, null, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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.Replays;
|
||||||
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
|
{
|
||||||
|
public class CatchReplayRecorder : ReplayRecorder<CatchAction>
|
||||||
|
{
|
||||||
|
private readonly CatchPlayfield playfield;
|
||||||
|
|
||||||
|
public CatchReplayRecorder(Replay target, CatchPlayfield playfield)
|
||||||
|
: base(target)
|
||||||
|
{
|
||||||
|
this.playfield = playfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<CatchAction> actions, ReplayFrame previousFrame)
|
||||||
|
=> new CatchReplayFrame(Time.Current, playfield.CatcherArea.MovableCatcher.X, actions.Contains(CatchAction.Dash), previousFrame as CatchReplayFrame);
|
||||||
|
}
|
||||||
|
}
|
@ -37,10 +37,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public CatcherAnimationState CurrentState { get; private set; }
|
public CatcherAnimationState CurrentState { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The width of the catcher which can receive fruit. Equivalent to "catchMargin" in osu-stable.
|
||||||
|
/// </summary>
|
||||||
|
private const float allowed_catch_range = 0.8f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the area that can be used to attempt catches during gameplay.
|
/// Width of the area that can be used to attempt catches during gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal float CatchWidth => CatcherArea.CATCHER_SIZE * Math.Abs(Scale.X);
|
internal float CatchWidth => CatcherArea.CATCHER_SIZE * Math.Abs(Scale.X) * allowed_catch_range;
|
||||||
|
|
||||||
protected bool Dashing
|
protected bool Dashing
|
||||||
{
|
{
|
||||||
@ -141,14 +146,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
var ourRadius = fruit.DisplayRadius;
|
var ourRadius = fruit.DisplayRadius;
|
||||||
float theirRadius = 0;
|
float theirRadius = 0;
|
||||||
|
|
||||||
const float allowance = 6;
|
const float allowance = 10;
|
||||||
|
|
||||||
while (caughtFruit.Any(f =>
|
while (caughtFruit.Any(f =>
|
||||||
f.LifetimeEnd == double.MaxValue &&
|
f.LifetimeEnd == double.MaxValue &&
|
||||||
Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2)))
|
Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2)))
|
||||||
{
|
{
|
||||||
var diff = (ourRadius + theirRadius) / allowance;
|
var diff = (ourRadius + theirRadius) / allowance;
|
||||||
fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff;
|
fruit.X += (RNG.NextSingle() - 0.5f) * diff * 2;
|
||||||
fruit.Y -= RNG.NextSingle() * diff;
|
fruit.Y -= RNG.NextSingle() * diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +384,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentCatcher.Show();
|
currentCatcher.Show();
|
||||||
(currentCatcher.Drawable as IAnimation)?.GotoFrame(0);
|
(currentCatcher.Drawable as IFramedAnimation)?.GotoFrame(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beginTrail()
|
private void beginTrail()
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public CatcherSprite(CatcherAnimationState state)
|
public CatcherSprite(CatcherAnimationState state)
|
||||||
: base(new CatchSkinComponent(componentFromState(state)), _ =>
|
: base(new CatchSkinComponent(componentFromState(state)), _ =>
|
||||||
new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleDownToFit)
|
new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleToFit)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.None;
|
RelativeSizeAxes = Axes.None;
|
||||||
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
||||||
|
@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
|
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new CatchReplayRecorder(replay, (CatchPlayfield)Playfield);
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
||||||
|
|
||||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();
|
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();
|
||||||
|
50
osu.Game.Rulesets.Mania.Tests/ManiaColumnTypeTest.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// 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.Rulesets.Mania.Beatmaps;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ManiaColumnTypeTest
|
||||||
|
{
|
||||||
|
[TestCase(new[]
|
||||||
|
{
|
||||||
|
ColumnType.Special
|
||||||
|
}, 1)]
|
||||||
|
[TestCase(new[]
|
||||||
|
{
|
||||||
|
ColumnType.Odd,
|
||||||
|
ColumnType.Even,
|
||||||
|
ColumnType.Even,
|
||||||
|
ColumnType.Odd
|
||||||
|
}, 4)]
|
||||||
|
[TestCase(new[]
|
||||||
|
{
|
||||||
|
ColumnType.Odd,
|
||||||
|
ColumnType.Even,
|
||||||
|
ColumnType.Odd,
|
||||||
|
ColumnType.Special,
|
||||||
|
ColumnType.Odd,
|
||||||
|
ColumnType.Even,
|
||||||
|
ColumnType.Odd
|
||||||
|
}, 7)]
|
||||||
|
public void Test(IEnumerable<ColumnType> expected, int columns)
|
||||||
|
{
|
||||||
|
var definition = new StageDefinition
|
||||||
|
{
|
||||||
|
Columns = columns
|
||||||
|
};
|
||||||
|
var results = getResults(definition);
|
||||||
|
Assert.AreEqual(expected, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<ColumnType> getResults(StageDefinition definition)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < definition.Columns; i++)
|
||||||
|
yield return definition.GetTypeOfColumn(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
protected override KeyBindingContainer<ManiaAction> CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||||
=> new LocalKeyBindingContainer(ruleset, variant, unique);
|
=> new LocalKeyBindingContainer(ruleset, variant, unique);
|
||||||
|
|
||||||
private class LocalKeyBindingContainer : RulesetKeyBindingContainer
|
private class LocalKeyBindingContainer : RulesetKeyBindingContainer
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A container to be used in a <see cref="ManiaSkinnableTestScene"/> to provide a resolvable <see cref="Column"/> dependency.
|
||||||
|
/// </summary>
|
||||||
|
public class ColumnTestContainer : Container
|
||||||
|
{
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private readonly Column column;
|
||||||
|
|
||||||
|
public ColumnTestContainer(int column, ManiaAction action)
|
||||||
|
{
|
||||||
|
this.column = new Column(column)
|
||||||
|
{
|
||||||
|
Action = { Value = action },
|
||||||
|
AccentColour = Color4.Orange,
|
||||||
|
ColumnType = column % 2 == 0 ? ColumnType.Even : ColumnType.Odd
|
||||||
|
};
|
||||||
|
|
||||||
|
InternalChild = content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A test scene for a mania hitobject.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ManiaHitObjectTestScene : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
SetContents(() => new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Height = 0.7f,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 80,
|
||||||
|
Child = new ScrollingHitObjectContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}.With(c =>
|
||||||
|
{
|
||||||
|
c.Add(CreateHitObject().With(h =>
|
||||||
|
{
|
||||||
|
h.HitObject.StartTime = START_TIME;
|
||||||
|
h.AccentColour.Value = Color4.Orange;
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
},
|
||||||
|
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 80,
|
||||||
|
Child = new ScrollingHitObjectContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}.With(c =>
|
||||||
|
{
|
||||||
|
c.Add(CreateHitObject().With(h =>
|
||||||
|
{
|
||||||
|
h.HitObject.StartTime = START_TIME;
|
||||||
|
h.AccentColour.Value = Color4.Orange;
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract DrawableManiaHitObject CreateHitObject();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A test scene for skinnable mania components.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ManiaSkinnableTestScene : SkinnableTestScene
|
||||||
|
{
|
||||||
|
protected const double START_TIME = 1000000000;
|
||||||
|
|
||||||
|
[Cached(Type = typeof(IScrollingInfo))]
|
||||||
|
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
|
||||||
|
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(ManiaRuleset),
|
||||||
|
typeof(ManiaLegacySkinTransformer),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override Ruleset CreateRulesetForSkinProvider() => new ManiaRuleset();
|
||||||
|
|
||||||
|
protected ManiaSkinnableTestScene()
|
||||||
|
{
|
||||||
|
scrollingInfo.Direction.Value = ScrollingDirection.Down;
|
||||||
|
|
||||||
|
Add(new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.SlateGray.Opacity(0.2f),
|
||||||
|
Depth = 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScrollingDown()
|
||||||
|
{
|
||||||
|
AddStep("change direction to down", () => scrollingInfo.Direction.Value = ScrollingDirection.Down);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScrollingUp()
|
||||||
|
{
|
||||||
|
AddStep("change direction to up", () => scrollingInfo.Direction.Value = ScrollingDirection.Up);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestScrollingInfo : IScrollingInfo
|
||||||
|
{
|
||||||
|
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||||
|
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(1000);
|
||||||
|
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ZeroScrollAlgorithm();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ZeroScrollAlgorithm : IScrollAlgorithm
|
||||||
|
{
|
||||||
|
public double GetDisplayStartTime(double originTime, float offset, double timeRange, float scrollLength)
|
||||||
|
=> double.MinValue;
|
||||||
|
|
||||||
|
public float GetLength(double startTime, double endTime, double timeRange, float scrollLength)
|
||||||
|
=> scrollLength;
|
||||||
|
|
||||||
|
public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
|
||||||
|
=> (float)((time - START_TIME) / timeRange) * scrollLength;
|
||||||
|
|
||||||
|
public double TimeAt(float position, double currentTime, double timeRange, float scrollLength)
|
||||||
|
=> 0;
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneColumnBackground : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
SetContents(() => new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Size = new Vector2(0.8f),
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 0), _ => new DefaultColumnBackground())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 0), _ => new DefaultColumnBackground())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneColumnHitObjectArea : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
SetContents(() => new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Size = new Vector2(0.8f),
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new ColumnHitObjectArea(0, new HitObjectContainer())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new ColumnHitObjectArea(1, new HitObjectContainer())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,15 +6,14 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
{
|
{
|
||||||
public class TestSceneDrawableJudgement : SkinnableTestScene
|
public class TestSceneDrawableJudgement : ManiaSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
@ -0,0 +1,66 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneHitExplosion : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(DrawableNote),
|
||||||
|
typeof(DrawableManiaHitObject),
|
||||||
|
};
|
||||||
|
|
||||||
|
public TestSceneHitExplosion()
|
||||||
|
{
|
||||||
|
int runcount = 0;
|
||||||
|
|
||||||
|
AddRepeatStep("explode", () =>
|
||||||
|
{
|
||||||
|
runcount++;
|
||||||
|
|
||||||
|
if (runcount % 15 > 12)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CreatedDrawables.OfType<Container>().ForEach(c =>
|
||||||
|
{
|
||||||
|
c.Add(new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, 0),
|
||||||
|
_ => new DefaultHitExplosion((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);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
SetContents(() => new ColumnTestContainer(0, ManiaAction.Key1)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativePositionAxes = Axes.Y,
|
||||||
|
Y = -0.25f,
|
||||||
|
Size = new Vector2(Column.COLUMN_WIDTH, DefaultNotePiece.NOTE_HEIGHT),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHoldNote.cs
Normal 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.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneHoldNote : ManiaHitObjectTestScene
|
||||||
|
{
|
||||||
|
public TestSceneHoldNote()
|
||||||
|
{
|
||||||
|
AddToggleStep("toggle hitting", v =>
|
||||||
|
{
|
||||||
|
foreach (var holdNote in CreatedDrawables.SelectMany(d => d.ChildrenOfType<DrawableHoldNote>()))
|
||||||
|
{
|
||||||
|
((Bindable<bool>)holdNote.IsHitting).Value = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DrawableManiaHitObject CreateHitObject()
|
||||||
|
{
|
||||||
|
var note = new HoldNote { Duration = 1000 };
|
||||||
|
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
return new DrawableHoldNote(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning;
|
||||||
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneKeyArea : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(DefaultKeyArea),
|
||||||
|
typeof(LegacyKeyArea)
|
||||||
|
};
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
SetContents(() => new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Size = new Vector2(0.8f),
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, 0), _ => new DefaultKeyArea())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, 1), _ => new DefaultKeyArea())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneNote.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneNote : ManiaHitObjectTestScene
|
||||||
|
{
|
||||||
|
protected override DrawableManiaHitObject CreateHitObject()
|
||||||
|
{
|
||||||
|
var note = new Note();
|
||||||
|
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
return new DrawableNote(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestScenePlayfield : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
private List<StageDefinition> stageDefinitions = new List<StageDefinition>();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleStage()
|
||||||
|
{
|
||||||
|
AddStep("create stage", () =>
|
||||||
|
{
|
||||||
|
stageDefinitions = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = 2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
SetContents(() => new ManiaPlayfield(stageDefinitions));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDualStages()
|
||||||
|
{
|
||||||
|
AddStep("create stage", () =>
|
||||||
|
{
|
||||||
|
stageDefinitions = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = 2 },
|
||||||
|
new StageDefinition { Columns = 2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
SetContents(() => new ManiaPlayfield(stageDefinitions));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmapForSkinProvider()
|
||||||
|
{
|
||||||
|
var maniaBeatmap = (ManiaBeatmap)base.CreateBeatmapForSkinProvider();
|
||||||
|
maniaBeatmap.Stages = stageDefinitions;
|
||||||
|
return maniaBeatmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneStage : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
SetContents(() =>
|
||||||
|
{
|
||||||
|
ManiaAction normalAction = ManiaAction.Key1;
|
||||||
|
ManiaAction specialAction = ManiaAction.Special1;
|
||||||
|
|
||||||
|
return new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
|
||||||
|
{
|
||||||
|
Child = new Stage(0, new StageDefinition { Columns = 4 }, ref normalAction, ref specialAction)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,8 +28,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
typeof(Column),
|
typeof(Column),
|
||||||
typeof(ColumnBackground),
|
typeof(ColumnBackground),
|
||||||
typeof(ColumnKeyArea),
|
typeof(ColumnHitObjectArea),
|
||||||
typeof(ColumnHitObjectArea)
|
typeof(DefaultKeyArea),
|
||||||
|
typeof(DefaultHitTarget)
|
||||||
};
|
};
|
||||||
|
|
||||||
[Cached(typeof(IReadOnlyList<Mod>))]
|
[Cached(typeof(IReadOnlyList<Mod>))]
|
||||||
|
@ -1,62 +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;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
[Cached(typeof(IReadOnlyList<Mod>))]
|
[Cached(typeof(IReadOnlyList<Mod>))]
|
||||||
private IReadOnlyList<Mod> mods { get; set; } = Array.Empty<Mod>();
|
private IReadOnlyList<Mod> mods { get; set; } = Array.Empty<Mod>();
|
||||||
|
|
||||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
private readonly List<Stage> stages = new List<Stage>();
|
||||||
|
|
||||||
private FillFlowContainer<ScrollingTestContainer> fill;
|
private FillFlowContainer<ScrollingTestContainer> fill;
|
||||||
|
|
||||||
@ -81,9 +81,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.TopCentre));
|
AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.TopCentre));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
|
private bool notesInStageAreAnchored(Stage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
|
||||||
|
|
||||||
private bool barsInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor);
|
private bool barsInStageAreAnchored(Stage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor);
|
||||||
|
|
||||||
private void createNote()
|
private void createNote()
|
||||||
{
|
{
|
||||||
@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
var specialAction = ManiaAction.Special1;
|
var specialAction = ManiaAction.Special1;
|
||||||
|
|
||||||
var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction);
|
var stage = new Stage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction);
|
||||||
stages.Add(stage);
|
stages.Add(stage);
|
||||||
|
|
||||||
return new ScrollingTestContainer(direction)
|
return new ScrollingTestContainer(direction)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
// 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.Mania
|
namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||||
{
|
{
|
||||||
public enum ManiaSkinComponents
|
public enum ColumnType
|
||||||
{
|
{
|
||||||
|
Even,
|
||||||
|
Odd,
|
||||||
|
Special
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Beatmaps
|
namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||||
@ -21,5 +22,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <param name="column">The 0-based column index.</param>
|
/// <param name="column">The 0-based column index.</param>
|
||||||
/// <returns>Whether the column is a special column.</returns>
|
/// <returns>Whether the column is a special column.</returns>
|
||||||
public bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2;
|
public bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the type of column given a column index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column">The 0-based column index.</param>
|
||||||
|
/// <returns>The type of the column.</returns>
|
||||||
|
public ColumnType GetTypeOfColumn(int column)
|
||||||
|
{
|
||||||
|
if (IsSpecialColumn(column))
|
||||||
|
return ColumnType.Special;
|
||||||
|
|
||||||
|
int distanceToEdge = Math.Min(column, (Columns - 1) - column);
|
||||||
|
return distanceToEdge % 2 == 0 ? ColumnType.Odd : ColumnType.Even;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Configuration;
|
using osu.Game.Rulesets.Configuration;
|
||||||
@ -19,13 +20,14 @@ namespace osu.Game.Rulesets.Mania.Configuration
|
|||||||
{
|
{
|
||||||
base.InitialiseDefaults();
|
base.InitialiseDefaults();
|
||||||
|
|
||||||
Set(ManiaRulesetSetting.ScrollTime, 1500.0, 50.0, 5000.0, 50.0);
|
Set(ManiaRulesetSetting.ScrollTime, 1500.0, DrawableManiaRuleset.MIN_TIME_RANGE, DrawableManiaRuleset.MAX_TIME_RANGE, 1);
|
||||||
Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
|
Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||||
{
|
{
|
||||||
new TrackedSetting<double>(ManiaRulesetSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms"))
|
new TrackedSetting<double>(ManiaRulesetSetting.ScrollTime,
|
||||||
|
v => new SettingDescription(v, "Scroll Speed", $"{(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / v)} ({v}ms)"))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,12 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||||
{
|
{
|
||||||
public class EditBodyPiece : BodyPiece
|
public class EditBodyPiece : DefaultBodyPiece
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
AccentColour = colours.Yellow;
|
AccentColour.Value = colours.Yellow;
|
||||||
|
|
||||||
Background.Alpha = 0.5f;
|
Background.Alpha = 0.5f;
|
||||||
Foreground.Alpha = 0;
|
Foreground.Alpha = 0;
|
||||||
|
@ -12,12 +12,12 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
|||||||
{
|
{
|
||||||
public EditNotePiece()
|
public EditNotePiece()
|
||||||
{
|
{
|
||||||
Height = NotePiece.NOTE_HEIGHT;
|
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||||
|
|
||||||
CornerRadius = 5;
|
CornerRadius = 5;
|
||||||
Masking = true;
|
Masking = true;
|
||||||
|
|
||||||
InternalChild = new NotePiece();
|
InternalChild = new DefaultNotePiece();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||||
{
|
{
|
||||||
@ -42,11 +42,18 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
{
|
{
|
||||||
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.Start),
|
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.Start),
|
||||||
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.End),
|
new HoldNoteNoteSelectionBlueprint(DrawableObject, HoldNotePosition.End),
|
||||||
new BodyPiece
|
new Container
|
||||||
{
|
{
|
||||||
AccentColour = Color4.Transparent,
|
RelativeSizeAxes = Axes.Both,
|
||||||
BorderColour = colours.Yellow
|
BorderThickness = 1,
|
||||||
},
|
BorderColour = colours.Yellow,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,11 +122,11 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
switch (scrollingInfo.Direction.Value)
|
switch (scrollingInfo.Direction.Value)
|
||||||
{
|
{
|
||||||
case ScrollingDirection.Up:
|
case ScrollingDirection.Up:
|
||||||
mousePosition.Y -= NotePiece.NOTE_HEIGHT / 2;
|
mousePosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ScrollingDirection.Down:
|
case ScrollingDirection.Down:
|
||||||
mousePosition.Y += NotePiece.NOTE_HEIGHT / 2;
|
mousePosition.Y += DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,11 +143,11 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
switch (scrollingInfo.Direction.Value)
|
switch (scrollingInfo.Direction.Value)
|
||||||
{
|
{
|
||||||
case ScrollingDirection.Up:
|
case ScrollingDirection.Up:
|
||||||
hitObjectPosition.Y += NotePiece.NOTE_HEIGHT / 2;
|
hitObjectPosition.Y += DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ScrollingDirection.Down:
|
case ScrollingDirection.Down:
|
||||||
hitObjectPosition.Y -= NotePiece.NOTE_HEIGHT / 2;
|
hitObjectPosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +47,9 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
|
||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new ManiaLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new ManiaLegacySkinTransformer(source, beatmap);
|
||||||
|
|
||||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||||
{
|
{
|
||||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||||
yield return new ManiaModNightcore();
|
yield return new ManiaModNightcore();
|
||||||
@ -118,6 +118,59 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
yield return new ManiaModRandom();
|
yield return new ManiaModRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override LegacyMods ConvertToLegacyMods(Mod[] mods)
|
||||||
|
{
|
||||||
|
var value = base.ConvertToLegacyMods(mods);
|
||||||
|
|
||||||
|
foreach (var mod in mods)
|
||||||
|
{
|
||||||
|
switch (mod)
|
||||||
|
{
|
||||||
|
case ManiaModKey1 _:
|
||||||
|
value |= LegacyMods.Key1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey2 _:
|
||||||
|
value |= LegacyMods.Key2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey3 _:
|
||||||
|
value |= LegacyMods.Key3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey4 _:
|
||||||
|
value |= LegacyMods.Key4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey5 _:
|
||||||
|
value |= LegacyMods.Key5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey6 _:
|
||||||
|
value |= LegacyMods.Key6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey7 _:
|
||||||
|
value |= LegacyMods.Key7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey8 _:
|
||||||
|
value |= LegacyMods.Key8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModKey9 _:
|
||||||
|
value |= LegacyMods.Key9;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaModFadeIn _:
|
||||||
|
value |= LegacyMods.FadeIn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -1,19 +1,44 @@
|
|||||||
// 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.Mania.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents>
|
public class ManiaSkinComponent : GameplaySkinComponent<ManiaSkinComponents>
|
||||||
{
|
{
|
||||||
public ManiaSkinComponent(ManiaSkinComponents component)
|
/// <summary>
|
||||||
|
/// The intended <see cref="Column"/> index for this component.
|
||||||
|
/// May be null if the component does not exist in a <see cref="Column"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int? TargetColumn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ManiaSkinComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="component">The component.</param>
|
||||||
|
/// <param name="targetColumn">The intended <see cref="Column"/> index for this component. May be null if the component does not exist in a <see cref="Column"/>.</param>
|
||||||
|
public ManiaSkinComponent(ManiaSkinComponents component, int? targetColumn = null)
|
||||||
: base(component)
|
: base(component)
|
||||||
{
|
{
|
||||||
|
TargetColumn = targetColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME;
|
protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME;
|
||||||
|
|
||||||
protected override string ComponentName => Component.ToString().ToLower();
|
protected override string ComponentName => Component.ToString().ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ManiaSkinComponents
|
||||||
|
{
|
||||||
|
ColumnBackground,
|
||||||
|
HitTarget,
|
||||||
|
KeyArea,
|
||||||
|
Note,
|
||||||
|
HoldNoteHead,
|
||||||
|
HoldNoteTail,
|
||||||
|
HoldNoteBody,
|
||||||
|
HitExplosion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,17 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
|
||||||
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.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
{
|
{
|
||||||
public class ManiaModRandom : Mod, IApplicableToBeatmap
|
public class ManiaModRandom : ModRandom, IApplicableToBeatmap
|
||||||
{
|
{
|
||||||
public override string Name => "Random";
|
|
||||||
public override string Acronym => "RD";
|
|
||||||
public override ModType Type => ModType.Conversion;
|
|
||||||
public override IconUsage? Icon => OsuIcon.Dice;
|
|
||||||
public override string Description => @"Shuffle around the keys!";
|
public override string Description => @"Shuffle around the keys!";
|
||||||
public override double ScoreMultiplier => 1;
|
|
||||||
|
|
||||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
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;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -20,6 +21,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public override bool DisplayResult => false;
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
|
public IBindable<bool> IsHitting => isHitting;
|
||||||
|
|
||||||
|
private readonly Bindable<bool> isHitting = new Bindable<bool>();
|
||||||
|
|
||||||
public DrawableHoldNoteHead Head => headContainer.Child;
|
public DrawableHoldNoteHead Head => headContainer.Child;
|
||||||
public DrawableHoldNoteTail Tail => tailContainer.Child;
|
public DrawableHoldNoteTail Tail => tailContainer.Child;
|
||||||
|
|
||||||
@ -27,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
private readonly Container<DrawableHoldNoteTail> tailContainer;
|
private readonly Container<DrawableHoldNoteTail> tailContainer;
|
||||||
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
||||||
|
|
||||||
private readonly BodyPiece bodyPiece;
|
private readonly Drawable bodyPiece;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
|
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
|
||||||
@ -44,18 +49,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new[]
|
||||||
{
|
{
|
||||||
bodyPiece = new BodyPiece { RelativeSizeAxes = Axes.X },
|
bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody, hitObject.Column), _ => new DefaultBodyPiece())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X
|
||||||
|
},
|
||||||
tickContainer = new Container<DrawableHoldNoteTick> { RelativeSizeAxes = Axes.Both },
|
tickContainer = new Container<DrawableHoldNoteTick> { RelativeSizeAxes = Axes.Both },
|
||||||
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both },
|
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both },
|
||||||
tailContainer = new Container<DrawableHoldNoteTail> { RelativeSizeAxes = Axes.Both },
|
tailContainer = new Container<DrawableHoldNoteTail> { RelativeSizeAxes = Axes.Both },
|
||||||
});
|
});
|
||||||
|
|
||||||
AccentColour.BindValueChanged(colour =>
|
|
||||||
{
|
|
||||||
bodyPiece.AccentColour = colour.NewValue;
|
|
||||||
}, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||||
@ -168,7 +171,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
HoldStartTime = Time.Current;
|
HoldStartTime = Time.Current;
|
||||||
bodyPiece.Hitting = true;
|
isHitting.Value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(ManiaAction action)
|
||||||
@ -194,7 +197,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
private void endHold()
|
private void endHold()
|
||||||
{
|
{
|
||||||
HoldStartTime = null;
|
HoldStartTime = null;
|
||||||
bodyPiece.Hitting = false;
|
isHitting.Value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableHoldNoteHead : DrawableNote
|
public class DrawableHoldNoteHead : DrawableNote
|
||||||
{
|
{
|
||||||
|
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteHead;
|
||||||
|
|
||||||
public DrawableHoldNoteHead(DrawableHoldNote holdNote)
|
public DrawableHoldNoteHead(DrawableHoldNote holdNote)
|
||||||
: base(holdNote.HitObject.Head)
|
: base(holdNote.HitObject.Head)
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const double release_window_lenience = 1.5;
|
private const double release_window_lenience = 1.5;
|
||||||
|
|
||||||
|
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteTail;
|
||||||
|
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableHoldNoteTail(DrawableHoldNote holdNote)
|
public DrawableHoldNoteTail(DrawableHoldNote holdNote)
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -18,7 +17,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
|
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
protected virtual ManiaSkinComponents Component => ManiaSkinComponents.Note;
|
||||||
|
|
||||||
|
private readonly Drawable headPiece;
|
||||||
|
|
||||||
public DrawableNote(Note hitObject)
|
public DrawableNote(Note hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
@ -26,22 +27,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
CornerRadius = 5;
|
AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinComponent(Component, hitObject.Column), _ => new DefaultNotePiece())
|
||||||
Masking = true;
|
|
||||||
|
|
||||||
AddInternal(headPiece = new NotePiece());
|
|
||||||
|
|
||||||
AccentColour.BindValueChanged(colour =>
|
|
||||||
{
|
{
|
||||||
headPiece.AccentColour = colour.NewValue;
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y
|
||||||
EdgeEffect = new EdgeEffectParameters
|
});
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Colour = colour.NewValue.Lighten(1f).Opacity(0.2f),
|
|
||||||
Radius = 10,
|
|
||||||
};
|
|
||||||
}, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
// 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 JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -9,26 +12,38 @@ 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.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents length-wise portion of a hold note.
|
/// Represents length-wise portion of a hold note.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BodyPiece : Container, IHasAccentColour
|
public class DefaultBodyPiece : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Container subtractionLayer;
|
protected readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
protected readonly Drawable Background;
|
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
|
||||||
protected readonly BufferedContainer Foreground;
|
private readonly IBindable<bool> isHitting = new Bindable<bool>();
|
||||||
private readonly BufferedContainer subtractionContainer;
|
|
||||||
|
|
||||||
public BodyPiece()
|
protected Drawable Background { get; private set; }
|
||||||
|
protected BufferedContainer Foreground { get; private set; }
|
||||||
|
|
||||||
|
private BufferedContainer subtractionContainer;
|
||||||
|
private Container subtractionLayer;
|
||||||
|
|
||||||
|
public DefaultBodyPiece()
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
Blending = BlendingParameters.Additive;
|
Blending = BlendingParameters.Additive;
|
||||||
|
|
||||||
Children = new[]
|
AddLayout(subtractionCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load([CanBeNull] DrawableHitObject drawableObject)
|
||||||
|
{
|
||||||
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
Background = new Box { RelativeSizeAxes = Axes.Both },
|
Background = new Box { RelativeSizeAxes = Axes.Both },
|
||||||
Foreground = new BufferedContainer
|
Foreground = new BufferedContainer
|
||||||
@ -66,43 +81,37 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddLayout(subtractionCache);
|
if (drawableObject != null)
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
updateAccentColour();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
{
|
||||||
if (accentColour == value)
|
var holdNote = (DrawableHoldNote)drawableObject;
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
AccentColour.BindTo(drawableObject.AccentColour);
|
||||||
|
isHitting.BindTo(holdNote.IsHitting);
|
||||||
updateAccentColour();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccentColour.BindValueChanged(onAccentChanged, true);
|
||||||
|
isHitting.BindValueChanged(_ => onAccentChanged(new ValueChangedEvent<Color4>(AccentColour.Value, AccentColour.Value)), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Hitting
|
private void onAccentChanged(ValueChangedEvent<Color4> accent)
|
||||||
{
|
{
|
||||||
get => hitting;
|
Foreground.Colour = accent.NewValue.Opacity(0.5f);
|
||||||
set
|
Background.Colour = accent.NewValue.Opacity(0.7f);
|
||||||
{
|
|
||||||
hitting = value;
|
|
||||||
updateAccentColour();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
|
const float animation_length = 50;
|
||||||
|
|
||||||
|
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
|
||||||
|
|
||||||
|
if (isHitting.Value)
|
||||||
|
{
|
||||||
|
// wait for the next sync point
|
||||||
|
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
|
||||||
|
using (Foreground.BeginDelayedSequence(synchronisedOffset))
|
||||||
|
Foreground.FadeColour(accent.NewValue.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
subtractionCache.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
@ -125,30 +134,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
|||||||
subtractionCache.Validate();
|
subtractionCache.Validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool hitting;
|
|
||||||
|
|
||||||
private void updateAccentColour()
|
|
||||||
{
|
|
||||||
if (!IsLoaded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Foreground.Colour = AccentColour.Opacity(0.5f);
|
|
||||||
Background.Colour = AccentColour.Opacity(0.7f);
|
|
||||||
|
|
||||||
const float animation_length = 50;
|
|
||||||
|
|
||||||
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
|
|
||||||
|
|
||||||
if (hitting)
|
|
||||||
{
|
|
||||||
// wait for the next sync point
|
|
||||||
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
|
|
||||||
using (Foreground.BeginDelayedSequence(synchronisedOffset))
|
|
||||||
Foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
subtractionCache.Invalidate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
// 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 JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the static hit markers of notes.
|
||||||
|
/// </summary>
|
||||||
|
internal class DefaultNotePiece : CompositeDrawable
|
||||||
|
{
|
||||||
|
public const float NOTE_HEIGHT = 12;
|
||||||
|
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
|
private readonly Box colouredBox;
|
||||||
|
|
||||||
|
public DefaultNotePiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = NOTE_HEIGHT;
|
||||||
|
|
||||||
|
CornerRadius = 5;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
colouredBox = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = NOTE_HEIGHT / 2,
|
||||||
|
Alpha = 0.1f
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load([NotNull] IScrollingInfo scrollingInfo, [CanBeNull] DrawableHitObject drawableObject)
|
||||||
|
{
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
|
||||||
|
if (drawableObject != null)
|
||||||
|
{
|
||||||
|
accentColour.BindTo(drawableObject.AccentColour);
|
||||||
|
accentColour.BindValueChanged(onAccentChanged, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
colouredBox.Anchor = colouredBox.Origin = direction.NewValue == ScrollingDirection.Up
|
||||||
|
? Anchor.TopCentre
|
||||||
|
: Anchor.BottomCentre;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAccentChanged(ValueChangedEvent<Color4> accent)
|
||||||
|
{
|
||||||
|
colouredBox.Colour = accent.NewValue.Lighten(0.9f);
|
||||||
|
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = accent.NewValue.Lighten(1f).Opacity(0.2f),
|
||||||
|
Radius = 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +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.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the static hit markers of notes.
|
|
||||||
/// </summary>
|
|
||||||
internal class NotePiece : Container, IHasAccentColour
|
|
||||||
{
|
|
||||||
public const float NOTE_HEIGHT = 12;
|
|
||||||
|
|
||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
|
||||||
|
|
||||||
private readonly Box colouredBox;
|
|
||||||
|
|
||||||
public NotePiece()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = NOTE_HEIGHT;
|
|
||||||
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
},
|
|
||||||
colouredBox = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = NOTE_HEIGHT / 2,
|
|
||||||
Alpha = 0.1f
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
|
||||||
{
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
|
||||||
direction.BindValueChanged(dir =>
|
|
||||||
{
|
|
||||||
colouredBox.Anchor = colouredBox.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
|
|
||||||
colouredBox.Colour = AccentColour.Lighten(0.9f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Replays.Legacy;
|
using osu.Game.Replays.Legacy;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
@ -24,15 +25,9 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
Actions.AddRange(actions);
|
Actions.AddRange(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
public void FromLegacy(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||||
{
|
{
|
||||||
// We don't need to fully convert, just create the converter
|
var maniaBeatmap = (ManiaBeatmap)beatmap;
|
||||||
var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
|
|
||||||
|
|
||||||
// NB: Via co-op mod, osu-stable can have two stages with floor(col/2) and ceil(col/2) columns. This will need special handling
|
|
||||||
// elsewhere in the game if we do choose to support the old co-op mod anyway. For now, assume that there is only one stage.
|
|
||||||
|
|
||||||
var stage = new StageDefinition { Columns = converter.TargetColumns };
|
|
||||||
|
|
||||||
var normalAction = ManiaAction.Key1;
|
var normalAction = ManiaAction.Key1;
|
||||||
var specialAction = ManiaAction.Special1;
|
var specialAction = ManiaAction.Special1;
|
||||||
@ -42,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
|
|
||||||
while (activeColumns > 0)
|
while (activeColumns > 0)
|
||||||
{
|
{
|
||||||
var isSpecial = stage.IsSpecialColumn(counter);
|
var isSpecial = maniaBeatmap.Stages.First().IsSpecialColumn(counter);
|
||||||
|
|
||||||
if ((activeColumns & 1) > 0)
|
if ((activeColumns & 1) > 0)
|
||||||
Actions.Add(isSpecial ? specialAction : normalAction);
|
Actions.Add(isSpecial ? specialAction : normalAction);
|
||||||
@ -56,5 +51,40 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
activeColumns >>= 1;
|
activeColumns >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
var maniaBeatmap = (ManiaBeatmap)beatmap;
|
||||||
|
|
||||||
|
int keys = 0;
|
||||||
|
|
||||||
|
var specialColumns = new List<int>();
|
||||||
|
|
||||||
|
for (int i = 0; i < maniaBeatmap.TotalColumns; i++)
|
||||||
|
{
|
||||||
|
if (maniaBeatmap.Stages.First().IsSpecialColumn(i))
|
||||||
|
specialColumns.Add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var action in Actions)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case ManiaAction.Special1:
|
||||||
|
keys |= 1 << specialColumns[0];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ManiaAction.Special2:
|
||||||
|
keys |= 1 << specialColumns[1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
keys |= 1 << (action - ManiaAction.Key1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LegacyReplayFrame(Time, keys, null, ReplayButtonState.None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
86
osu.Game.Rulesets.Mania/Skinning/LegacyBodyPiece.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Animations;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyBodyPiece : LegacyManiaColumnElement
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
private readonly IBindable<bool> isHitting = new Bindable<bool>();
|
||||||
|
|
||||||
|
private Drawable sprite;
|
||||||
|
|
||||||
|
public LegacyBodyPiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo, DrawableHitObject drawableObject)
|
||||||
|
{
|
||||||
|
string imageName = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage)?.Value
|
||||||
|
?? $"mania-note{FallbackColumnIndex}L";
|
||||||
|
|
||||||
|
sprite = skin.GetAnimation(imageName, true, true).With(d =>
|
||||||
|
{
|
||||||
|
if (d == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (d is TextureAnimation animation)
|
||||||
|
animation.IsPlaying = false;
|
||||||
|
|
||||||
|
d.Anchor = Anchor.TopCentre;
|
||||||
|
d.RelativeSizeAxes = Axes.Both;
|
||||||
|
d.Size = Vector2.One;
|
||||||
|
d.FillMode = FillMode.Stretch;
|
||||||
|
// Todo: Wrap
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sprite != null)
|
||||||
|
InternalChild = sprite;
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
|
||||||
|
var holdNote = (DrawableHoldNote)drawableObject;
|
||||||
|
isHitting.BindTo(holdNote.IsHitting);
|
||||||
|
isHitting.BindValueChanged(onIsHittingChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onIsHittingChanged(ValueChangedEvent<bool> isHitting)
|
||||||
|
{
|
||||||
|
if (!(sprite is TextureAnimation animation))
|
||||||
|
return;
|
||||||
|
|
||||||
|
animation.GotoFrame(0);
|
||||||
|
animation.IsPlaying = isHitting.NewValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (sprite == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
sprite.Origin = Anchor.BottomCentre;
|
||||||
|
sprite.Scale = new Vector2(1, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprite.Origin = Anchor.TopCentre;
|
||||||
|
sprite.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
141
osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
private readonly bool isLastColumn;
|
||||||
|
|
||||||
|
private Container lightContainer;
|
||||||
|
private Sprite light;
|
||||||
|
|
||||||
|
public LegacyColumnBackground(bool isLastColumn)
|
||||||
|
{
|
||||||
|
this.isLastColumn = isLastColumn;
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
string lightImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.LightImage, 0)?.Value
|
||||||
|
?? "mania-stage-light";
|
||||||
|
|
||||||
|
float leftLineWidth = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.LeftLineWidth)
|
||||||
|
?.Value ?? 1;
|
||||||
|
float rightLineWidth = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.RightLineWidth)
|
||||||
|
?.Value ?? 1;
|
||||||
|
|
||||||
|
bool hasLeftLine = leftLineWidth > 0;
|
||||||
|
bool hasRightLine = rightLineWidth > 0 && skin.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value >= 2.4m
|
||||||
|
|| isLastColumn;
|
||||||
|
|
||||||
|
float lightPosition = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.LightPosition)?.Value
|
||||||
|
?? 0;
|
||||||
|
|
||||||
|
Color4 lineColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnLineColour)?.Value
|
||||||
|
?? Color4.White;
|
||||||
|
|
||||||
|
Color4 backgroundColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour)?.Value
|
||||||
|
?? Color4.Black;
|
||||||
|
|
||||||
|
Color4 lightColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnLightColour)?.Value
|
||||||
|
?? Color4.White;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = backgroundColour
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = leftLineWidth,
|
||||||
|
Colour = lineColour,
|
||||||
|
Alpha = hasLeftLine ? 1 : 0
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = rightLineWidth,
|
||||||
|
Colour = lineColour,
|
||||||
|
Alpha = hasRightLine ? 1 : 0
|
||||||
|
},
|
||||||
|
lightContainer = new Container
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Bottom = lightPosition },
|
||||||
|
Child = light = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
Colour = lightColour,
|
||||||
|
Texture = skin.GetTexture(lightImage),
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 1,
|
||||||
|
Alpha = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
lightContainer.Anchor = Anchor.TopCentre;
|
||||||
|
lightContainer.Scale = new Vector2(1, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lightContainer.Anchor = Anchor.BottomCentre;
|
||||||
|
lightContainer.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == Column.Action.Value)
|
||||||
|
{
|
||||||
|
light.FadeIn();
|
||||||
|
light.ScaleTo(Vector2.One);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(ManiaAction action)
|
||||||
|
{
|
||||||
|
// Todo: Should be 400 * 100 / CurrentBPM
|
||||||
|
const double animation_length = 250;
|
||||||
|
|
||||||
|
if (action == Column.Action.Value)
|
||||||
|
{
|
||||||
|
light.FadeTo(0, animation_length);
|
||||||
|
light.ScaleTo(new Vector2(1, 0), animation_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Animations;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyHitExplosion : LegacyManiaColumnElement
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Drawable explosion;
|
||||||
|
|
||||||
|
public LegacyHitExplosion()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
string imageName = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.ExplosionImage)?.Value
|
||||||
|
?? "lightingN";
|
||||||
|
|
||||||
|
float explosionScale = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.ExplosionScale)?.Value
|
||||||
|
?? 1;
|
||||||
|
|
||||||
|
// Create a temporary animation to retrieve the number of frames, in an effort to calculate the intended frame length.
|
||||||
|
// This animation is discarded and re-queried with the appropriate frame length afterwards.
|
||||||
|
var tmp = skin.GetAnimation(imageName, true, false);
|
||||||
|
double frameLength = 0;
|
||||||
|
if (tmp is IFramedAnimation tmpAnimation && tmpAnimation.FrameCount > 0)
|
||||||
|
frameLength = Math.Max(1000 / 60.0, 170.0 / tmpAnimation.FrameCount);
|
||||||
|
|
||||||
|
explosion = skin.GetAnimation(imageName, true, false, frameLength: frameLength).With(d =>
|
||||||
|
{
|
||||||
|
if (d == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d.Origin = Anchor.Centre;
|
||||||
|
d.Blending = BlendingParameters.Additive;
|
||||||
|
d.Scale = new Vector2(explosionScale);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (explosion != null)
|
||||||
|
InternalChild = explosion;
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (explosion != null)
|
||||||
|
explosion.Anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
explosion?.FadeInFromZero(80)
|
||||||
|
.Then().FadeOut(120);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
osu.Game.Rulesets.Mania/Skinning/LegacyHitTarget.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyHitTarget : LegacyManiaElement
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Container directionContainer;
|
||||||
|
|
||||||
|
public LegacyHitTarget()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
string targetImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.HitTargetImage)?.Value
|
||||||
|
?? "mania-stage-hint";
|
||||||
|
|
||||||
|
bool showJudgementLine = GetManiaSkinConfig<bool>(skin, LegacyManiaSkinConfigurationLookups.ShowJudgementLine)?.Value
|
||||||
|
?? true;
|
||||||
|
|
||||||
|
Color4 lineColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.JudgementLineColour)?.Value
|
||||||
|
?? Color4.White;
|
||||||
|
|
||||||
|
InternalChild = directionContainer = new Container
|
||||||
|
{
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Texture = skin.GetTexture(targetImage),
|
||||||
|
Scale = new Vector2(1, 0.9f * 1.6025f),
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 1
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 1,
|
||||||
|
Colour = lineColour,
|
||||||
|
Alpha = showJudgementLine ? 0.9f : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = Anchor.TopLeft;
|
||||||
|
directionContainer.Scale = new Vector2(1, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = Anchor.BottomLeft;
|
||||||
|
directionContainer.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteHeadPiece.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
||||||
|
{
|
||||||
|
protected override Texture GetTexture(ISkinSource skin)
|
||||||
|
{
|
||||||
|
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||||
|
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||||
|
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteTailPiece.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyHoldNoteTailPiece : LegacyNotePiece
|
||||||
|
{
|
||||||
|
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
// Invert the direction
|
||||||
|
base.OnDirectionChanged(direction.NewValue == ScrollingDirection.Up
|
||||||
|
? new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Down, ScrollingDirection.Down)
|
||||||
|
: new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Up, ScrollingDirection.Up));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Texture GetTexture(ISkinSource skin)
|
||||||
|
{
|
||||||
|
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||||
|
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage)
|
||||||
|
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||||
|
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
osu.Game.Rulesets.Mania/Skinning/LegacyKeyArea.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Container directionContainer;
|
||||||
|
private Sprite upSprite;
|
||||||
|
private Sprite downSprite;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Column column { get; set; }
|
||||||
|
|
||||||
|
public LegacyKeyArea()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
string upImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.KeyImage)?.Value
|
||||||
|
?? $"mania-key{FallbackColumnIndex}";
|
||||||
|
|
||||||
|
string downImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.KeyImageDown)?.Value
|
||||||
|
?? $"mania-key{FallbackColumnIndex}D";
|
||||||
|
|
||||||
|
InternalChild = directionContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
upSprite = new Sprite
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
Texture = skin.GetTexture(upImage),
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 1
|
||||||
|
},
|
||||||
|
downSprite = new Sprite
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
Texture = skin.GetTexture(downImage),
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 1,
|
||||||
|
Alpha = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = directionContainer.Origin = Anchor.TopCentre;
|
||||||
|
upSprite.Anchor = downSprite.Anchor = Anchor.TopCentre;
|
||||||
|
upSprite.Scale = downSprite.Scale = new Vector2(1, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = directionContainer.Origin = Anchor.BottomCentre;
|
||||||
|
upSprite.Anchor = downSprite.Anchor = Anchor.BottomCentre;
|
||||||
|
upSprite.Scale = downSprite.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == column.Action.Value)
|
||||||
|
{
|
||||||
|
upSprite.FadeTo(0);
|
||||||
|
downSprite.FadeTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == column.Action.Value)
|
||||||
|
{
|
||||||
|
upSprite.FadeTo(1);
|
||||||
|
downSprite.FadeTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
osu.Game.Rulesets.Mania/Skinning/LegacyManiaColumnElement.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="CompositeDrawable"/> which is placed somewhere within a <see cref="Column"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class LegacyManiaColumnElement : LegacyManiaElement
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
protected Column Column { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The column type identifier to use for texture lookups, in the case of no user-provided configuration.
|
||||||
|
/// </summary>
|
||||||
|
protected string FallbackColumnIndex { get; private set; }
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
switch (Column.ColumnType)
|
||||||
|
{
|
||||||
|
case ColumnType.Special:
|
||||||
|
FallbackColumnIndex = "S";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ColumnType.Odd:
|
||||||
|
FallbackColumnIndex = "1";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ColumnType.Even:
|
||||||
|
FallbackColumnIndex = "2";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IBindable<T> GetManiaSkinConfig<T>(ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? index = null)
|
||||||
|
=> base.GetManiaSkinConfig<T>(skin, lookup, index ?? Column.Index);
|
||||||
|
}
|
||||||
|
}
|
25
osu.Game.Rulesets.Mania/Skinning/LegacyManiaElement.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A mania legacy skin element.
|
||||||
|
/// </summary>
|
||||||
|
public class LegacyManiaElement : CompositeDrawable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve a per-column-count skin configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="skin">The skin from which configuration is retrieved.</param>
|
||||||
|
/// <param name="lookup">The value to retrieve.</param>
|
||||||
|
/// <param name="index">If not null, denotes the index of the column to which the entry applies.</param>
|
||||||
|
protected virtual IBindable<T> GetManiaSkinConfig<T>(ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? index = null)
|
||||||
|
=> skin.GetConfig<ManiaSkinConfigurationLookup, T>(
|
||||||
|
new ManiaSkinConfigurationLookup(lookup, index));
|
||||||
|
}
|
||||||
|
}
|
98
osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyNotePiece : LegacyManiaColumnElement
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Container directionContainer;
|
||||||
|
private Sprite noteSprite;
|
||||||
|
|
||||||
|
private float? minimumColumnWidth;
|
||||||
|
|
||||||
|
public LegacyNotePiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
minimumColumnWidth = skin.GetConfig<ManiaSkinConfigurationLookup, float>(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth))?.Value;
|
||||||
|
|
||||||
|
InternalChild = directionContainer = new Container
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Child = noteSprite = new Sprite { Texture = GetTexture(skin) }
|
||||||
|
};
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(OnDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (noteSprite.Texture != null)
|
||||||
|
{
|
||||||
|
// The height is scaled to the minimum column width, if provided.
|
||||||
|
float minimumWidth = minimumColumnWidth ?? DrawWidth;
|
||||||
|
|
||||||
|
noteSprite.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), noteSprite.Texture.DisplayWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = Anchor.TopCentre;
|
||||||
|
directionContainer.Scale = new Vector2(1, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = Anchor.BottomCentre;
|
||||||
|
directionContainer.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Texture GetTexture(ISkinSource skin) => GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
|
|
||||||
|
protected Texture GetTextureFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup)
|
||||||
|
{
|
||||||
|
string suffix = string.Empty;
|
||||||
|
|
||||||
|
switch (lookup)
|
||||||
|
{
|
||||||
|
case LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage:
|
||||||
|
suffix = "H";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LegacyManiaSkinConfigurationLookups.HoldNoteTailImage:
|
||||||
|
suffix = "T";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string noteImage = GetManiaSkinConfig<string>(skin, lookup)?.Value
|
||||||
|
?? $"mania-note{FallbackColumnIndex}{suffix}";
|
||||||
|
|
||||||
|
return skin.GetTexture(noteImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
// 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 osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
@ -14,10 +17,32 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
public class ManiaLegacySkinTransformer : ISkin
|
public class ManiaLegacySkinTransformer : ISkin
|
||||||
{
|
{
|
||||||
private readonly ISkin source;
|
private readonly ISkin source;
|
||||||
|
private readonly ManiaBeatmap beatmap;
|
||||||
|
|
||||||
public ManiaLegacySkinTransformer(ISkin source)
|
private Lazy<bool> isLegacySkin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether texture for the keys exists.
|
||||||
|
/// Used to determine if the mania ruleset is skinned.
|
||||||
|
/// </summary>
|
||||||
|
private Lazy<bool> hasKeyTexture;
|
||||||
|
|
||||||
|
public ManiaLegacySkinTransformer(ISkinSource source, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
this.beatmap = (ManiaBeatmap)beatmap;
|
||||||
|
|
||||||
|
source.SourceChanged += sourceChanged;
|
||||||
|
sourceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sourceChanged()
|
||||||
|
{
|
||||||
|
isLegacySkin = new Lazy<bool>(() => source.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version) != null);
|
||||||
|
hasKeyTexture = new Lazy<bool>(() => source.GetAnimation(
|
||||||
|
GetConfig<ManiaSkinConfigurationLookup, string>(
|
||||||
|
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.KeyImage, 0))?.Value
|
||||||
|
?? "mania-key1", true, true) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable GetDrawableComponent(ISkinComponent component)
|
public Drawable GetDrawableComponent(ISkinComponent component)
|
||||||
@ -26,6 +51,39 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
{
|
{
|
||||||
case GameplaySkinComponent<HitResult> resultComponent:
|
case GameplaySkinComponent<HitResult> resultComponent:
|
||||||
return getResult(resultComponent);
|
return getResult(resultComponent);
|
||||||
|
|
||||||
|
case ManiaSkinComponent maniaComponent:
|
||||||
|
if (!isLegacySkin.Value || !hasKeyTexture.Value)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (maniaComponent.Component)
|
||||||
|
{
|
||||||
|
case ManiaSkinComponents.ColumnBackground:
|
||||||
|
return new LegacyColumnBackground(maniaComponent.TargetColumn == beatmap.TotalColumns - 1);
|
||||||
|
|
||||||
|
case ManiaSkinComponents.HitTarget:
|
||||||
|
return new LegacyHitTarget();
|
||||||
|
|
||||||
|
case ManiaSkinComponents.KeyArea:
|
||||||
|
return new LegacyKeyArea();
|
||||||
|
|
||||||
|
case ManiaSkinComponents.Note:
|
||||||
|
return new LegacyNotePiece();
|
||||||
|
|
||||||
|
case ManiaSkinComponents.HoldNoteHead:
|
||||||
|
return new LegacyHoldNoteHeadPiece();
|
||||||
|
|
||||||
|
case ManiaSkinComponents.HoldNoteTail:
|
||||||
|
return new LegacyHoldNoteTailPiece();
|
||||||
|
|
||||||
|
case ManiaSkinComponents.HoldNoteBody:
|
||||||
|
return new LegacyBodyPiece();
|
||||||
|
|
||||||
|
case ManiaSkinComponents.HitExplosion:
|
||||||
|
return new LegacyHitExplosion();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -61,7 +119,12 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
|
|
||||||
public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
|
public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
|
||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) =>
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||||
source.GetConfig<TLookup, TValue>(lookup);
|
{
|
||||||
|
if (lookup is ManiaSkinConfigurationLookup maniaLookup)
|
||||||
|
return source.GetConfig<LegacyManiaSkinConfigurationLookup, TValue>(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.TargetColumn));
|
||||||
|
|
||||||
|
return source.GetConfig<TLookup, TValue>(lookup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
// 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.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning
|
||||||
|
{
|
||||||
|
public class ManiaSkinConfigurationLookup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration lookup value.
|
||||||
|
/// </summary>
|
||||||
|
public readonly LegacyManiaSkinConfigurationLookups Lookup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The intended <see cref="Column"/> index for the configuration.
|
||||||
|
/// May be null if the configuration does not apply to a <see cref="Column"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int? TargetColumn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ManiaSkinConfigurationLookup"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lookup">The lookup value.</param>
|
||||||
|
/// <param name="targetColumn">The intended <see cref="Column"/> index for the configuration. May be null if the configuration does not apply to a <see cref="Column"/>.</param>
|
||||||
|
public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null)
|
||||||
|
{
|
||||||
|
Lookup = lookup;
|
||||||
|
TargetColumn = targetColumn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,17 +12,19 @@ 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;
|
||||||
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 osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||||
{
|
{
|
||||||
public const float COLUMN_WIDTH = 80;
|
public const float COLUMN_WIDTH = 80;
|
||||||
private const float special_column_width = 70;
|
public const float SPECIAL_COLUMN_WIDTH = 70;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The index of this column as part of the whole playfield.
|
/// The index of this column as part of the whole playfield.
|
||||||
@ -31,12 +33,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||||
|
|
||||||
private readonly ColumnBackground background;
|
|
||||||
private readonly ColumnKeyArea keyArea;
|
|
||||||
private readonly ColumnHitObjectArea hitObjectArea;
|
private readonly ColumnHitObjectArea hitObjectArea;
|
||||||
|
|
||||||
internal readonly Container TopLevelContainer;
|
internal readonly Container TopLevelContainer;
|
||||||
private readonly Container explosionContainer;
|
|
||||||
|
|
||||||
public Column(int index)
|
public Column(int index)
|
||||||
{
|
{
|
||||||
@ -45,95 +44,34 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
Width = COLUMN_WIDTH;
|
Width = COLUMN_WIDTH;
|
||||||
|
|
||||||
background = new ColumnBackground { RelativeSizeAxes = Axes.Both };
|
Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, Index), _ => new DefaultColumnBackground())
|
||||||
|
{
|
||||||
Container hitTargetContainer;
|
RelativeSizeAxes = Axes.Both
|
||||||
|
};
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
||||||
background.CreateProxy(),
|
background.CreateProxy(),
|
||||||
hitTargetContainer = new Container
|
hitObjectArea = new ColumnHitObjectArea(Index, HitObjectContainer) { RelativeSizeAxes = Axes.Both },
|
||||||
|
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, Index), _ => new DefaultKeyArea())
|
||||||
{
|
{
|
||||||
Name = "Hit target + hit objects",
|
RelativeSizeAxes = Axes.Both
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
hitObjectArea = new ColumnHitObjectArea(HitObjectContainer)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
explosionContainer = new Container
|
|
||||||
{
|
|
||||||
Name = "Hit explosions",
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
keyArea = new ColumnKeyArea
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = ManiaStage.HIT_TARGET_POSITION,
|
|
||||||
},
|
},
|
||||||
background,
|
background,
|
||||||
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||||
};
|
};
|
||||||
|
|
||||||
TopLevelContainer.Add(explosionContainer.CreateProxy());
|
TopLevelContainer.Add(hitObjectArea.Explosions.CreateProxy());
|
||||||
|
|
||||||
Direction.BindValueChanged(dir =>
|
|
||||||
{
|
|
||||||
hitTargetContainer.Padding = new MarginPadding
|
|
||||||
{
|
|
||||||
Top = dir.NewValue == ScrollingDirection.Up ? 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;
|
|
||||||
}, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Axes RelativeSizeAxes => Axes.Y;
|
public override Axes RelativeSizeAxes => Axes.Y;
|
||||||
|
|
||||||
private bool isSpecial;
|
public ColumnType ColumnType { get; set; }
|
||||||
|
|
||||||
public bool IsSpecial
|
public bool IsSpecial => ColumnType == ColumnType.Special;
|
||||||
{
|
|
||||||
get => isSpecial;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (isSpecial == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
isSpecial = value;
|
public Color4 AccentColour { get; set; }
|
||||||
|
|
||||||
Width = isSpecial ? special_column_width : COLUMN_WIDTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
|
|
||||||
background.AccentColour = value;
|
|
||||||
keyArea.AccentColour = value;
|
|
||||||
hitObjectArea.AccentColour = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
{
|
{
|
||||||
@ -168,11 +106,15 @@ 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.AccentColour.Value, judgedObject is DrawableHoldNoteTick)
|
var explosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, Index), _ =>
|
||||||
|
new DefaultHitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick))
|
||||||
{
|
{
|
||||||
Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre,
|
RelativeSizeAxes = Axes.Both
|
||||||
Origin = Anchor.Centre
|
};
|
||||||
});
|
|
||||||
|
hitObjectArea.Explosions.Add(explosion);
|
||||||
|
|
||||||
|
explosion.Delay(200).Expire(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(ManiaAction action)
|
||||||
@ -197,6 +139,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
|
||||||
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
|
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
|
||||||
=> DrawRectangle.Inflate(new Vector2(ManiaStage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
|
=> DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,145 +1,45 @@
|
|||||||
// 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.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
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.Shapes;
|
|
||||||
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 osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||||
{
|
{
|
||||||
public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour
|
public class ColumnHitObjectArea : HitObjectArea
|
||||||
{
|
{
|
||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
public readonly Container Explosions;
|
||||||
|
|
||||||
private readonly Drawable hitTarget;
|
private readonly Drawable hitTarget;
|
||||||
|
|
||||||
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
|
public ColumnHitObjectArea(int columnIndex, HitObjectContainer hitObjectContainer)
|
||||||
|
: base(hitObjectContainer)
|
||||||
{
|
{
|
||||||
InternalChildren = new[]
|
AddRangeInternal(new[]
|
||||||
{
|
{
|
||||||
hitTarget = new DefaultHitTarget
|
hitTarget = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitTarget, columnIndex), _ => new DefaultHitTarget())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Depth = 1
|
||||||
},
|
},
|
||||||
hitObjectContainer
|
Explosions = new Container
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
|
||||||
{
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
|
||||||
direction.BindValueChanged(dir =>
|
|
||||||
{
|
|
||||||
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
|
|
||||||
|
|
||||||
hitTarget.Anchor = hitTarget.Origin = anchor;
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
|
|
||||||
if (hitTarget is IHasAccentColour colouredHitTarget)
|
|
||||||
colouredHitTarget.AccentColour = accentColour;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DefaultHitTarget : CompositeDrawable, IHasAccentColour
|
|
||||||
{
|
|
||||||
private const float hit_target_bar_height = 2;
|
|
||||||
|
|
||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
|
||||||
|
|
||||||
private readonly Container hitTargetLine;
|
|
||||||
private readonly Drawable hitTargetBar;
|
|
||||||
|
|
||||||
public DefaultHitTarget()
|
|
||||||
{
|
|
||||||
InternalChildren = new[]
|
|
||||||
{
|
{
|
||||||
hitTargetBar = new Box
|
RelativeSizeAxes = Axes.Both,
|
||||||
{
|
Depth = -1,
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = NotePiece.NOTE_HEIGHT,
|
|
||||||
Alpha = 0.6f,
|
|
||||||
Colour = Color4.Black
|
|
||||||
},
|
|
||||||
hitTargetLine = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = hit_target_bar_height,
|
|
||||||
Masking = true,
|
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
|
||||||
{
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
|
||||||
direction.BindValueChanged(dir =>
|
|
||||||
{
|
|
||||||
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
|
|
||||||
|
|
||||||
hitTargetBar.Anchor = hitTargetBar.Origin = anchor;
|
|
||||||
hitTargetLine.Anchor = hitTargetLine.Origin = anchor;
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
updateColours();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
|
|
||||||
updateColours();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void updateColours()
|
protected override void UpdateHitPosition()
|
||||||
{
|
{
|
||||||
if (!IsLoaded)
|
base.UpdateHitPosition();
|
||||||
return;
|
|
||||||
|
|
||||||
hitTargetLine.EdgeEffect = new EdgeEffectParameters
|
if (Direction.Value == ScrollingDirection.Up)
|
||||||
{
|
hitTarget.Anchor = hitTarget.Origin = Anchor.TopLeft;
|
||||||
Type = EdgeEffectType.Glow,
|
else
|
||||||
Radius = 5,
|
hitTarget.Anchor = hitTarget.Origin = Anchor.BottomLeft;
|
||||||
Colour = accentColour.Opacity(0.5f),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,124 +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.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Colour;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
|
||||||
{
|
|
||||||
public class ColumnKeyArea : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
|
||||||
{
|
|
||||||
private const float key_icon_size = 10;
|
|
||||||
private const float key_icon_corner_radius = 3;
|
|
||||||
|
|
||||||
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
|
|
||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
|
||||||
|
|
||||||
private Container keyIcon;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
|
|
||||||
{
|
|
||||||
this.action.BindTo(action);
|
|
||||||
|
|
||||||
Drawable gradient;
|
|
||||||
|
|
||||||
InternalChildren = new[]
|
|
||||||
{
|
|
||||||
gradient = new Box
|
|
||||||
{
|
|
||||||
Name = "Key gradient",
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0.5f
|
|
||||||
},
|
|
||||||
keyIcon = new Container
|
|
||||||
{
|
|
||||||
Name = "Key icon",
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(key_icon_size),
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = key_icon_corner_radius,
|
|
||||||
BorderThickness = 2,
|
|
||||||
BorderColour = Color4.White, // Not true
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0,
|
|
||||||
AlwaysPresent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
|
||||||
direction.BindValueChanged(dir =>
|
|
||||||
{
|
|
||||||
gradient.Colour = ColourInfo.GradientVertical(
|
|
||||||
dir.NewValue == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0),
|
|
||||||
dir.NewValue == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black);
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
updateColours();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
|
|
||||||
updateColours();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateColours()
|
|
||||||
{
|
|
||||||
if (!IsLoaded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
keyIcon.EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Radius = 5,
|
|
||||||
Colour = accentColour.Opacity(0.5f),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
|
||||||
{
|
|
||||||
if (action == this.action.Value)
|
|
||||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
|
||||||
{
|
|
||||||
if (action == this.action.Value)
|
|
||||||
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,90 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||||
|
{
|
||||||
|
public class DefaultColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>
|
||||||
|
{
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Color4 brightColour;
|
||||||
|
private Color4 dimColour;
|
||||||
|
|
||||||
|
private Box background;
|
||||||
|
private Box backgroundOverlay;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Column column { get; set; }
|
||||||
|
|
||||||
|
public DefaultColumnBackground()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
InternalChildren = new[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
Name = "Background",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
backgroundOverlay = new Box
|
||||||
|
{
|
||||||
|
Name = "Background Gradient Overlay",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Height = 0.5f,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Alpha = 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
background.Colour = column.AccentColour.Darken(5);
|
||||||
|
brightColour = column.AccentColour.Opacity(0.6f);
|
||||||
|
dimColour = column.AccentColour.Opacity(0);
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
backgroundOverlay.Anchor = backgroundOverlay.Origin = Anchor.TopLeft;
|
||||||
|
backgroundOverlay.Colour = ColourInfo.GradientVertical(brightColour, dimColour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backgroundOverlay.Anchor = backgroundOverlay.Origin = Anchor.BottomLeft;
|
||||||
|
backgroundOverlay.Colour = ColourInfo.GradientVertical(dimColour, brightColour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == column.Action.Value)
|
||||||
|
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == column.Action.Value)
|
||||||
|
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
80
osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||||
|
{
|
||||||
|
public class DefaultHitTarget : CompositeDrawable
|
||||||
|
{
|
||||||
|
private const float hit_target_bar_height = 2;
|
||||||
|
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Container hitTargetLine;
|
||||||
|
private Drawable hitTargetBar;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Column column { get; set; }
|
||||||
|
|
||||||
|
public DefaultHitTarget()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
InternalChildren = new[]
|
||||||
|
{
|
||||||
|
hitTargetBar = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = DefaultNotePiece.NOTE_HEIGHT,
|
||||||
|
Alpha = 0.6f,
|
||||||
|
Colour = Color4.Black
|
||||||
|
},
|
||||||
|
hitTargetLine = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = hit_target_bar_height,
|
||||||
|
Masking = true,
|
||||||
|
Child = new Box { RelativeSizeAxes = Axes.Both }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
hitTargetLine.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Radius = 5,
|
||||||
|
Colour = column.AccentColour.Opacity(0.5f),
|
||||||
|
};
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
hitTargetBar.Anchor = hitTargetBar.Origin = Anchor.TopLeft;
|
||||||
|
hitTargetLine.Anchor = hitTargetLine.Origin = Anchor.TopLeft;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hitTargetBar.Anchor = hitTargetBar.Origin = Anchor.BottomLeft;
|
||||||
|
hitTargetLine.Anchor = hitTargetLine.Origin = Anchor.BottomLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||||
|
{
|
||||||
|
public class DefaultKeyArea : CompositeDrawable, IKeyBindingHandler<ManiaAction>
|
||||||
|
{
|
||||||
|
private const float key_icon_size = 10;
|
||||||
|
private const float key_icon_corner_radius = 3;
|
||||||
|
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
private Container directionContainer;
|
||||||
|
private Container keyIcon;
|
||||||
|
private Drawable gradient;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Column column { get; set; }
|
||||||
|
|
||||||
|
public DefaultKeyArea()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
InternalChild = directionContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = Stage.HIT_TARGET_POSITION,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
gradient = new Box
|
||||||
|
{
|
||||||
|
Name = "Key gradient",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0.5f
|
||||||
|
},
|
||||||
|
keyIcon = new Container
|
||||||
|
{
|
||||||
|
Name = "Key icon",
|
||||||
|
Size = new Vector2(key_icon_size),
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = key_icon_corner_radius,
|
||||||
|
BorderThickness = 2,
|
||||||
|
BorderColour = Color4.White, // Not true
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
keyIcon.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Radius = 5,
|
||||||
|
Colour = column.AccentColour.Opacity(0.5f),
|
||||||
|
};
|
||||||
|
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
keyIcon.Anchor = Anchor.BottomCentre;
|
||||||
|
keyIcon.Y = -20;
|
||||||
|
directionContainer.Anchor = directionContainer.Origin = Anchor.TopLeft;
|
||||||
|
gradient.Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keyIcon.Anchor = Anchor.TopCentre;
|
||||||
|
keyIcon.Y = 20;
|
||||||
|
directionContainer.Anchor = directionContainer.Origin = Anchor.BottomLeft;
|
||||||
|
gradient.Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == column.Action.Value)
|
||||||
|
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(ManiaAction action)
|
||||||
|
{
|
||||||
|
if (action == column.Action.Value)
|
||||||
|
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||||
|
{
|
||||||
|
public class HitObjectArea : SkinReloadableDrawable
|
||||||
|
{
|
||||||
|
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
|
public HitObjectArea(HitObjectContainer hitObjectContainer)
|
||||||
|
{
|
||||||
|
InternalChildren = new[]
|
||||||
|
{
|
||||||
|
hitObjectContainer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
Direction.BindTo(scrollingInfo.Direction);
|
||||||
|
Direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||||
|
{
|
||||||
|
base.SkinChanged(skin, allowFallback);
|
||||||
|
UpdateHitPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
UpdateHitPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateHitPosition()
|
||||||
|
{
|
||||||
|
float hitPosition = CurrentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
|
||||||
|
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition))?.Value
|
||||||
|
?? Stage.HIT_TARGET_POSITION;
|
||||||
|
|
||||||
|
Padding = Direction.Value == ScrollingDirection.Up
|
||||||
|
? new MarginPadding { Top = hitPosition }
|
||||||
|
: new MarginPadding { Bottom = hitPosition };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,35 @@
|
|||||||
// 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.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
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.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
internal class HitExplosion : CompositeDrawable
|
public class DefaultHitExplosion : CompositeDrawable
|
||||||
{
|
{
|
||||||
public override bool RemoveWhenNotAlive => true;
|
public override bool RemoveWhenNotAlive => true;
|
||||||
|
|
||||||
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
private readonly CircularContainer largeFaint;
|
private readonly CircularContainer largeFaint;
|
||||||
private readonly CircularContainer mainGlow1;
|
private readonly CircularContainer mainGlow1;
|
||||||
|
|
||||||
public HitExplosion(Color4 objectColour, bool isSmall = false)
|
public DefaultHitExplosion(Color4 objectColour, bool isSmall = false)
|
||||||
{
|
{
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = NotePiece.NOTE_HEIGHT;
|
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||||
|
|
||||||
// scale roughly in-line with visual appearance of notes
|
// scale roughly in-line with visual appearance of notes
|
||||||
Scale = new Vector2(1f, 0.6f);
|
Scale = new Vector2(1f, 0.6f);
|
||||||
@ -109,6 +116,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
|
direction.BindValueChanged(onDirectionChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
const double duration = 200;
|
const double duration = 200;
|
||||||
@ -122,7 +136,20 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint);
|
mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint);
|
||||||
|
|
||||||
this.FadeOut(duration, Easing.Out);
|
this.FadeOut(duration, Easing.Out);
|
||||||
Expire(true);
|
}
|
||||||
|
|
||||||
|
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||||
|
{
|
||||||
|
if (direction.NewValue == ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre;
|
||||||
|
Y = DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre;
|
||||||
|
Y = -DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,8 +5,10 @@ using System.Collections.Generic;
|
|||||||
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.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
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;
|
||||||
@ -25,6 +27,16 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
public class DrawableManiaRuleset : DrawableScrollingRuleset<ManiaHitObject>
|
public class DrawableManiaRuleset : DrawableScrollingRuleset<ManiaHitObject>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum time range. This occurs at a <see cref="relativeTimeRange"/> of 40.
|
||||||
|
/// </summary>
|
||||||
|
public const double MIN_TIME_RANGE = 150;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum time range. This occurs at a <see cref="relativeTimeRange"/> of 1.
|
||||||
|
/// </summary>
|
||||||
|
public const double MAX_TIME_RANGE = 6000;
|
||||||
|
|
||||||
protected new ManiaPlayfield Playfield => (ManiaPlayfield)base.Playfield;
|
protected new ManiaPlayfield Playfield => (ManiaPlayfield)base.Playfield;
|
||||||
|
|
||||||
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
|
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
|
||||||
@ -46,6 +58,19 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
bool isForCurrentRuleset = Beatmap.BeatmapInfo.Ruleset.Equals(Ruleset.RulesetInfo);
|
||||||
|
|
||||||
|
foreach (var p in ControlPoints)
|
||||||
|
{
|
||||||
|
// Mania doesn't care about global velocity
|
||||||
|
p.Velocity = 1;
|
||||||
|
p.BaseBeatLength *= Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier;
|
||||||
|
|
||||||
|
// For non-mania beatmap, speed changes should only happen through timing points
|
||||||
|
if (!isForCurrentRuleset)
|
||||||
|
p.DifficultyPoint = new DifficultyControlPoint();
|
||||||
|
}
|
||||||
|
|
||||||
BarLines.ForEach(Playfield.Add);
|
BarLines.ForEach(Playfield.Add);
|
||||||
|
|
||||||
Config.BindWith(ManiaRulesetSetting.ScrollDirection, configDirection);
|
Config.BindWith(ManiaRulesetSetting.ScrollDirection, configDirection);
|
||||||
@ -54,6 +79,17 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
Config.BindWith(ManiaRulesetSetting.ScrollTime, TimeRange);
|
Config.BindWith(ManiaRulesetSetting.ScrollTime, TimeRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void AdjustScrollSpeed(int amount)
|
||||||
|
{
|
||||||
|
this.TransformTo(nameof(relativeTimeRange), relativeTimeRange + amount, 200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double relativeTimeRange
|
||||||
|
{
|
||||||
|
get => MAX_TIME_RANGE / TimeRange.Value;
|
||||||
|
set => TimeRange.Value = MAX_TIME_RANGE / value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the column that intersects a screen-space position.
|
/// Retrieves the column that intersects a screen-space position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -85,5 +121,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
|
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new ManiaReplayRecorder(replay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
public class ManiaPlayfield : ScrollingPlayfield
|
public class ManiaPlayfield : ScrollingPlayfield
|
||||||
{
|
{
|
||||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
private readonly List<Stage> stages = new List<Stage>();
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => stages.Any(s => s.ReceivePositionalInputAt(screenSpacePos));
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => stages.Any(s => s.ReceivePositionalInputAt(screenSpacePos));
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
for (int i = 0; i < stageDefinitions.Count; i++)
|
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||||
{
|
{
|
||||||
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
var newStage = new Stage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||||
|
|
||||||
playfieldGrid.Content[0][i] = newStage;
|
playfieldGrid.Content[0][i] = newStage;
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int TotalColumns => stages.Sum(s => s.Columns.Count);
|
public int TotalColumns => stages.Sum(s => s.Columns.Count);
|
||||||
|
|
||||||
private ManiaStage getStageByColumn(int column)
|
private Stage getStageByColumn(int column)
|
||||||
{
|
{
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
@ -13,8 +12,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Size = new Vector2(1, 0.8f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 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.Replays;
|
||||||
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
|
{
|
||||||
|
public class ManiaReplayRecorder : ReplayRecorder<ManiaAction>
|
||||||
|
{
|
||||||
|
public ManiaReplayRecorder(Replay replay)
|
||||||
|
: base(replay)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<ManiaAction> actions, ReplayFrame previousFrame)
|
||||||
|
=> new ManiaReplayFrame(Time.Current, actions.ToArray());
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -12,9 +11,12 @@ 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.Mania.Skinning;
|
||||||
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
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;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -23,30 +25,33 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of <see cref="Column"/>s.
|
/// A collection of <see cref="Column"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ManiaStage : ScrollingPlayfield
|
public class Stage : ScrollingPlayfield
|
||||||
{
|
{
|
||||||
public const float COLUMN_SPACING = 1;
|
public const float COLUMN_SPACING = 1;
|
||||||
|
|
||||||
public const float HIT_TARGET_POSITION = 50;
|
public const float HIT_TARGET_POSITION = 110;
|
||||||
|
|
||||||
public IReadOnlyList<Column> Columns => columnFlow.Children;
|
public IReadOnlyList<Column> Columns => columnFlow.Children;
|
||||||
private readonly FillFlowContainer<Column> columnFlow;
|
private readonly FillFlowContainer<Column> columnFlow;
|
||||||
|
|
||||||
private readonly Container barLineContainer;
|
|
||||||
|
|
||||||
public Container<DrawableManiaJudgement> Judgements => judgements;
|
public Container<DrawableManiaJudgement> Judgements => judgements;
|
||||||
private readonly JudgementContainer<DrawableManiaJudgement> judgements;
|
private readonly JudgementContainer<DrawableManiaJudgement> judgements;
|
||||||
|
|
||||||
|
private readonly Drawable barLineContainer;
|
||||||
private readonly Container topLevelContainer;
|
private readonly Container topLevelContainer;
|
||||||
|
|
||||||
private List<Color4> normalColumnColours = new List<Color4>();
|
private readonly Dictionary<ColumnType, Color4> columnColours = new Dictionary<ColumnType, Color4>
|
||||||
private Color4 specialColumnColour;
|
{
|
||||||
|
{ ColumnType.Even, new Color4(6, 84, 0, 255) },
|
||||||
|
{ ColumnType.Odd, new Color4(94, 0, 57, 255) },
|
||||||
|
{ ColumnType.Special, new Color4(0, 48, 63, 255) }
|
||||||
|
};
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos));
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos));
|
||||||
|
|
||||||
private readonly int firstColumnIndex;
|
private readonly int firstColumnIndex;
|
||||||
|
|
||||||
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
public Stage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||||
{
|
{
|
||||||
this.firstColumnIndex = firstColumnIndex;
|
this.firstColumnIndex = firstColumnIndex;
|
||||||
|
|
||||||
@ -67,31 +72,19 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Columns mask",
|
Name = "Background",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black
|
||||||
|
},
|
||||||
|
columnFlow = new FillFlowContainer<Column>
|
||||||
|
{
|
||||||
|
Name = "Columns",
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Masking = true,
|
Direction = FillDirection.Horizontal,
|
||||||
CornerRadius = 5,
|
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Name = "Background",
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4.Black
|
|
||||||
},
|
|
||||||
columnFlow = new FillFlowContainer<Column>
|
|
||||||
{
|
|
||||||
Name = "Columns",
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
|
|
||||||
Spacing = new Vector2(COLUMN_SPACING, 0)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
@ -102,13 +95,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
Width = 1366, // Bar lines should only be masked on the vertical axis
|
Width = 1366, // Bar lines should only be masked on the vertical axis
|
||||||
BypassAutoSizeAxes = Axes.Both,
|
BypassAutoSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Child = barLineContainer = new Container
|
Child = barLineContainer = new HitObjectArea(HitObjectContainer)
|
||||||
{
|
{
|
||||||
Name = "Bar lines",
|
Name = "Bar lines",
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Child = HitObjectContainer
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
judgements = new JudgementContainer<DrawableManiaJudgement>
|
judgements = new JudgementContainer<DrawableManiaJudgement>
|
||||||
@ -125,24 +117,52 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
for (int i = 0; i < definition.Columns; i++)
|
for (int i = 0; i < definition.Columns; i++)
|
||||||
{
|
{
|
||||||
var isSpecial = definition.IsSpecialColumn(i);
|
var columnType = definition.GetTypeOfColumn(i);
|
||||||
var column = new Column(firstColumnIndex + i)
|
var column = new Column(firstColumnIndex + i)
|
||||||
{
|
{
|
||||||
IsSpecial = isSpecial,
|
ColumnType = columnType,
|
||||||
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
|
AccentColour = columnColours[columnType],
|
||||||
|
Action = { Value = columnType == ColumnType.Special ? specialColumnStartAction++ : normalColumnStartAction++ }
|
||||||
};
|
};
|
||||||
|
|
||||||
AddColumn(column);
|
AddColumn(column);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Direction.BindValueChanged(dir =>
|
private ISkin currentSkin;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin)
|
||||||
|
{
|
||||||
|
currentSkin = skin;
|
||||||
|
skin.SourceChanged += onSkinChanged;
|
||||||
|
|
||||||
|
onSkinChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSkinChanged()
|
||||||
|
{
|
||||||
|
foreach (var col in columnFlow)
|
||||||
{
|
{
|
||||||
barLineContainer.Padding = new MarginPadding
|
if (col.Index > 0)
|
||||||
{
|
{
|
||||||
Top = dir.NewValue == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0,
|
float spacing = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
|
||||||
Bottom = dir.NewValue == ScrollingDirection.Down ? HIT_TARGET_POSITION : 0,
|
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, col.Index - 1))
|
||||||
};
|
?.Value ?? COLUMN_SPACING;
|
||||||
}, true);
|
|
||||||
|
col.Margin = new MarginPadding { Left = spacing };
|
||||||
|
}
|
||||||
|
|
||||||
|
float? width = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
|
||||||
|
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, col.Index))
|
||||||
|
?.Value;
|
||||||
|
|
||||||
|
if (width == null)
|
||||||
|
// only used by default skin (legacy skins get defaults set in LegacyManiaSkinConfiguration)
|
||||||
|
col.Width = col.IsSpecial ? Column.SPECIAL_COLUMN_WIDTH : Column.COLUMN_WIDTH;
|
||||||
|
else
|
||||||
|
col.Width = width.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddColumn(Column c)
|
public void AddColumn(Column c)
|
||||||
@ -195,38 +215,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
normalColumnColours = new List<Color4>
|
|
||||||
{
|
|
||||||
new Color4(94, 0, 57, 255),
|
|
||||||
new Color4(6, 84, 0, 255)
|
|
||||||
};
|
|
||||||
|
|
||||||
specialColumnColour = new Color4(0, 48, 63, 255);
|
|
||||||
|
|
||||||
// Set the special column + colour + key
|
|
||||||
foreach (var column in Columns)
|
|
||||||
{
|
|
||||||
if (!column.IsSpecial)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
column.AccentColour = specialColumnColour;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList();
|
|
||||||
|
|
||||||
// We'll set the colours of the non-special columns in a separate loop, because the non-special
|
|
||||||
// column colours are mirrored across their centre and special styles mess with this
|
|
||||||
for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++)
|
|
||||||
{
|
|
||||||
Color4 colour = normalColumnColours[i % normalColumnColours.Count];
|
|
||||||
nonSpecialColumns[i].AccentColour = colour;
|
|
||||||
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
// Due to masking differences, it is not possible to get the width of the columns container automatically
|
// Due to masking differences, it is not possible to get the width of the columns container automatically
|
21
osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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 osu.Game.Rulesets.Osu.Skinning;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
public abstract class OsuSkinnableTestScene : SkinnableTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(OsuRuleset),
|
||||||
|
typeof(OsuLegacySkinTransformer),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 49 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/special-skin/sliderb0.png
Normal file
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 23 KiB |
@ -10,17 +10,16 @@ using osu.Game.Rulesets.Judgements;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
public class TestSceneDrawableJudgement : SkinnableTestScene
|
public class TestSceneDrawableJudgement : OsuSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||||
{
|
{
|
||||||
typeof(DrawableJudgement),
|
typeof(DrawableJudgement),
|
||||||
typeof(DrawableOsuJudgement)
|
typeof(DrawableOsuJudgement)
|
||||||
};
|
}).ToList();
|
||||||
|
|
||||||
public TestSceneDrawableJudgement()
|
public TestSceneDrawableJudgement()
|
||||||
{
|
{
|
||||||
|
@ -3,26 +3,32 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
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.Testing.Input;
|
using osu.Framework.Testing.Input;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Osu.Skinning;
|
||||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneGameplayCursor : SkinnableTestScene
|
public class TestSceneGameplayCursor : OsuSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||||
{
|
{
|
||||||
|
typeof(GameplayCursorContainer),
|
||||||
typeof(OsuCursorContainer),
|
typeof(OsuCursorContainer),
|
||||||
|
typeof(OsuCursor),
|
||||||
|
typeof(LegacyCursor),
|
||||||
|
typeof(LegacyCursorTrail),
|
||||||
typeof(CursorTrail)
|
typeof(CursorTrail)
|
||||||
};
|
}).ToList();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private GameplayBeatmap gameplayBeatmap;
|
private GameplayBeatmap gameplayBeatmap;
|
||||||
|
@ -14,12 +14,11 @@ using osu.Game.Rulesets.Mods;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneHitCircle : SkinnableTestScene
|
public class TestSceneHitCircle : OsuSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
|
@ -22,12 +22,11 @@ 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.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneSlider : SkinnableTestScene
|
public class TestSceneSlider : OsuSkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
|
253
osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.Osu.Configuration;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
|
using osu.Game.Storyboards;
|
||||||
|
using osuTK;
|
||||||
|
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneSliderSnaking : TestSceneOsuPlayer
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private AudioManager audioManager { get; set; }
|
||||||
|
|
||||||
|
private TrackVirtualManual track;
|
||||||
|
|
||||||
|
protected override bool Autoplay => autoplay;
|
||||||
|
private bool autoplay;
|
||||||
|
|
||||||
|
private readonly BindableBool snakingIn = new BindableBool();
|
||||||
|
private readonly BindableBool snakingOut = new BindableBool();
|
||||||
|
|
||||||
|
private const double duration_of_span = 3605;
|
||||||
|
private const double fade_in_modifier = -1200;
|
||||||
|
|
||||||
|
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||||
|
{
|
||||||
|
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||||
|
track = (TrackVirtualManual)working.Track;
|
||||||
|
return working;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(RulesetConfigCache configCache)
|
||||||
|
{
|
||||||
|
var config = (OsuRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
||||||
|
config.BindWith(OsuRulesetSetting.SnakingInSliders, snakingIn);
|
||||||
|
config.BindWith(OsuRulesetSetting.SnakingOutSliders, snakingOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrawableSlider slider;
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public override void SetUpSteps() { }
|
||||||
|
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
[TestCase(2)]
|
||||||
|
public void TestSnakingEnabled(int sliderIndex)
|
||||||
|
{
|
||||||
|
AddStep("enable autoplay", () => autoplay = true);
|
||||||
|
base.SetUpSteps();
|
||||||
|
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||||
|
|
||||||
|
double startTime = hitObjects[sliderIndex].StartTime;
|
||||||
|
retrieveDrawableSlider(sliderIndex);
|
||||||
|
setSnaking(true);
|
||||||
|
|
||||||
|
ensureSnakingIn(startTime + fade_in_modifier);
|
||||||
|
|
||||||
|
for (int i = 0; i < sliderIndex; i++)
|
||||||
|
{
|
||||||
|
// non-final repeats should not snake out
|
||||||
|
ensureNoSnakingOut(startTime, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// final repeat should snake out
|
||||||
|
ensureSnakingOut(startTime, sliderIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
[TestCase(2)]
|
||||||
|
public void TestSnakingDisabled(int sliderIndex)
|
||||||
|
{
|
||||||
|
AddStep("have autoplay", () => autoplay = true);
|
||||||
|
base.SetUpSteps();
|
||||||
|
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||||
|
|
||||||
|
double startTime = hitObjects[sliderIndex].StartTime;
|
||||||
|
retrieveDrawableSlider(sliderIndex);
|
||||||
|
setSnaking(false);
|
||||||
|
|
||||||
|
ensureNoSnakingIn(startTime + fade_in_modifier);
|
||||||
|
|
||||||
|
for (int i = 0; i <= sliderIndex; i++)
|
||||||
|
{
|
||||||
|
// no snaking out ever, including final repeat
|
||||||
|
ensureNoSnakingOut(startTime, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRepeatArrowDoesNotMoveWhenHit()
|
||||||
|
{
|
||||||
|
AddStep("enable autoplay", () => autoplay = true);
|
||||||
|
setSnaking(true);
|
||||||
|
base.SetUpSteps();
|
||||||
|
|
||||||
|
// repeat might have a chance to update its position depending on where in the frame its hit,
|
||||||
|
// so some leniency is allowed here instead of checking strict equality
|
||||||
|
checkPositionChange(16600, sliderRepeat, positionAlmostSame);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRepeatArrowMovesWhenNotHit()
|
||||||
|
{
|
||||||
|
AddStep("disable autoplay", () => autoplay = false);
|
||||||
|
setSnaking(true);
|
||||||
|
base.SetUpSteps();
|
||||||
|
|
||||||
|
checkPositionChange(16600, sliderRepeat, positionDecreased);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retrieveDrawableSlider(int index) => AddStep($"retrieve {(index + 1).ToOrdinalWords()} slider", () =>
|
||||||
|
{
|
||||||
|
slider = (DrawableSlider)Player.DrawableRuleset.Playfield.AllHitObjects.ElementAt(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void ensureSnakingIn(double startTime) => checkPositionChange(startTime, sliderEnd, positionIncreased);
|
||||||
|
private void ensureNoSnakingIn(double startTime) => checkPositionChange(startTime, sliderEnd, positionRemainsSame);
|
||||||
|
|
||||||
|
private void ensureSnakingOut(double startTime, int repeatIndex)
|
||||||
|
{
|
||||||
|
var repeatTime = timeAtRepeat(startTime, repeatIndex);
|
||||||
|
|
||||||
|
if (repeatIndex % 2 == 0)
|
||||||
|
checkPositionChange(repeatTime, sliderStart, positionIncreased);
|
||||||
|
else
|
||||||
|
checkPositionChange(repeatTime, sliderEnd, positionDecreased);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureNoSnakingOut(double startTime, int repeatIndex) =>
|
||||||
|
checkPositionChange(timeAtRepeat(startTime, repeatIndex), positionAtRepeat(repeatIndex), positionRemainsSame);
|
||||||
|
|
||||||
|
private double timeAtRepeat(double startTime, int repeatIndex) => startTime + 100 + duration_of_span * repeatIndex;
|
||||||
|
private Func<Vector2> positionAtRepeat(int repeatIndex) => repeatIndex % 2 == 0 ? (Func<Vector2>)sliderStart : sliderEnd;
|
||||||
|
|
||||||
|
private List<Vector2> sliderCurve => ((PlaySliderBody)slider.Body.Drawable).CurrentCurve;
|
||||||
|
private Vector2 sliderStart() => sliderCurve.First();
|
||||||
|
private Vector2 sliderEnd() => sliderCurve.Last();
|
||||||
|
|
||||||
|
private Vector2 sliderRepeat()
|
||||||
|
{
|
||||||
|
var drawable = Player.DrawableRuleset.Playfield.AllHitObjects.ElementAt(1);
|
||||||
|
var repeat = drawable.ChildrenOfType<Container<DrawableSliderRepeat>>().First().Children.First();
|
||||||
|
return repeat.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool positionRemainsSame(Vector2 previous, Vector2 current) => previous == current;
|
||||||
|
private bool positionIncreased(Vector2 previous, Vector2 current) => current.X > previous.X && current.Y > previous.Y;
|
||||||
|
private bool positionDecreased(Vector2 previous, Vector2 current) => current.X < previous.X && current.Y < previous.Y;
|
||||||
|
private bool positionAlmostSame(Vector2 previous, Vector2 current) => Precision.AlmostEquals(previous, current, 1);
|
||||||
|
|
||||||
|
private void checkPositionChange(double startTime, Func<Vector2> positionToCheck, Func<Vector2, Vector2, bool> positionAssertion)
|
||||||
|
{
|
||||||
|
Vector2 previousPosition = Vector2.Zero;
|
||||||
|
|
||||||
|
string positionDescription = positionToCheck.Method.Name.Humanize(LetterCasing.LowerCase);
|
||||||
|
string assertionDescription = positionAssertion.Method.Name.Humanize(LetterCasing.LowerCase);
|
||||||
|
|
||||||
|
addSeekStep(startTime);
|
||||||
|
AddStep($"save {positionDescription} position", () => previousPosition = positionToCheck.Invoke());
|
||||||
|
addSeekStep(startTime + 100);
|
||||||
|
AddAssert($"{positionDescription} {assertionDescription}", () =>
|
||||||
|
{
|
||||||
|
var currentPosition = positionToCheck.Invoke();
|
||||||
|
return positionAssertion.Invoke(previousPosition, currentPosition);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSnaking(bool value)
|
||||||
|
{
|
||||||
|
AddStep($"{(value ? "enable" : "disable")} snaking", () =>
|
||||||
|
{
|
||||||
|
snakingIn.Value = value;
|
||||||
|
snakingOut.Value = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSeekStep(double time)
|
||||||
|
{
|
||||||
|
AddStep($"seek to {time}", () => track.Seek(time));
|
||||||
|
|
||||||
|
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = hitObjects
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly List<HitObject> hitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new Slider
|
||||||
|
{
|
||||||
|
StartTime = 3000,
|
||||||
|
Position = new Vector2(100, 100),
|
||||||
|
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(300, 200)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
new Slider
|
||||||
|
{
|
||||||
|
StartTime = 13000,
|
||||||
|
Position = new Vector2(100, 100),
|
||||||
|
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(300, 200)
|
||||||
|
}),
|
||||||
|
RepeatCount = 1,
|
||||||
|
},
|
||||||
|
new Slider
|
||||||
|
{
|
||||||
|
StartTime = 23000,
|
||||||
|
Position = new Vector2(100, 100),
|
||||||
|
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(300, 200)
|
||||||
|
}),
|
||||||
|
RepeatCount = 2,
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 199999,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
70
osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneSpinnerSpunOut : OsuTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(SpinnerDisc),
|
||||||
|
typeof(DrawableSpinner),
|
||||||
|
typeof(DrawableOsuHitObject),
|
||||||
|
typeof(OsuModSpunOut)
|
||||||
|
};
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
|
{
|
||||||
|
SelectedMods.Value = new[] { new OsuModSpunOut() };
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSpunOut()
|
||||||
|
{
|
||||||
|
DrawableSpinner spinner = null;
|
||||||
|
|
||||||
|
AddStep("create spinner", () => spinner = createSpinner());
|
||||||
|
|
||||||
|
AddUntilStep("wait for end", () => Time.Current > spinner.LifetimeEnd);
|
||||||
|
|
||||||
|
AddAssert("spinner is completed", () => spinner.Progress >= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrawableSpinner createSpinner()
|
||||||
|
{
|
||||||
|
var spinner = new Spinner
|
||||||
|
{
|
||||||
|
StartTime = Time.Current + 500,
|
||||||
|
EndTime = Time.Current + 2500
|
||||||
|
};
|
||||||
|
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
var drawableSpinner = new DrawableSpinner(spinner)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
||||||
|
mod.ApplyToDrawableHitObjects(new[] { drawableSpinner });
|
||||||
|
|
||||||
|
Add(drawableSpinner);
|
||||||
|
return drawableSpinner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -30,6 +31,22 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
Value = 5,
|
Value = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public override string SettingDescription
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string circleSize = CircleSize.IsDefault ? string.Empty : $"CS {CircleSize.Value:N1}";
|
||||||
|
string approachRate = ApproachRate.IsDefault ? string.Empty : $"AR {ApproachRate.Value:N1}";
|
||||||
|
|
||||||
|
return string.Join(", ", new[]
|
||||||
|
{
|
||||||
|
circleSize,
|
||||||
|
base.SettingDescription,
|
||||||
|
approachRate
|
||||||
|
}.Where(s => !string.IsNullOrEmpty(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void TransferSettings(BeatmapDifficulty difficulty)
|
protected override void TransferSettings(BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.TransferSettings(difficulty);
|
base.TransferSettings(difficulty);
|
||||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
void handleHitCircle(DrawableHitCircle circle)
|
void handleHitCircle(DrawableHitCircle circle)
|
||||||
{
|
{
|
||||||
if (!circle.IsHovered)
|
if (!circle.HitArea.IsHovered)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Assert(circle.HitObject.HitWindows != null);
|
Debug.Assert(circle.HitObject.HitWindows != null);
|
||||||
|
@ -2,21 +2,46 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
public class OsuModSpunOut : Mod
|
public class OsuModSpunOut : Mod, IApplicableToDrawableHitObjects
|
||||||
{
|
{
|
||||||
public override string Name => "Spun Out";
|
public override string Name => "Spun Out";
|
||||||
public override string Acronym => "SO";
|
public override string Acronym => "SO";
|
||||||
public override IconUsage? Icon => OsuIcon.ModSpunout;
|
public override IconUsage? Icon => OsuIcon.ModSpunout;
|
||||||
public override ModType Type => ModType.DifficultyReduction;
|
public override ModType Type => ModType.Automation;
|
||||||
public override string Description => @"Spinners will be automatically completed.";
|
public override string Description => @"Spinners will be automatically completed.";
|
||||||
public override double ScoreMultiplier => 0.9;
|
public override double ScoreMultiplier => 0.9;
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) };
|
||||||
|
|
||||||
|
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||||
|
{
|
||||||
|
foreach (var hitObject in drawables)
|
||||||
|
{
|
||||||
|
if (hitObject is DrawableSpinner spinner)
|
||||||
|
{
|
||||||
|
spinner.HandleUserInput = false;
|
||||||
|
spinner.OnUpdate += onSpinnerUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSpinnerUpdate(Drawable drawable)
|
||||||
|
{
|
||||||
|
var spinner = (DrawableSpinner)drawable;
|
||||||
|
|
||||||
|
spinner.Disc.Tracking = true;
|
||||||
|
spinner.Disc.Rotate(MathUtils.RadiansToDegrees((float)spinner.Clock.ElapsedFrameTime * 0.03f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A single follow point positioned between two adjacent <see cref="DrawableOsuHitObject"/>s.
|
/// A single follow point positioned between two adjacent <see cref="DrawableOsuHitObject"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FollowPoint : Container
|
public class FollowPoint : Container, IAnimationTimeReference
|
||||||
{
|
{
|
||||||
private const float width = 8;
|
private const float width = 8;
|
||||||
|
|
||||||
@ -43,7 +43,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
}
|
}
|
||||||
}, confineMode: ConfineMode.NoScaling);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double AnimationStartTime { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
|
|
||||||
int point = 0;
|
int point = 0;
|
||||||
|
|
||||||
|
ClearInternal();
|
||||||
|
|
||||||
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
|
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
|
||||||
{
|
{
|
||||||
float fraction = (float)d / distance;
|
float fraction = (float)d / distance;
|
||||||
@ -126,13 +128,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
|
|
||||||
FollowPoint fp;
|
FollowPoint fp;
|
||||||
|
|
||||||
if (InternalChildren.Count > point)
|
AddInternal(fp = new FollowPoint());
|
||||||
{
|
|
||||||
fp = (FollowPoint)InternalChildren[point];
|
|
||||||
fp.ClearTransforms();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
AddInternal(fp = new FollowPoint());
|
|
||||||
|
|
||||||
fp.Position = pointStartPosition;
|
fp.Position = pointStartPosition;
|
||||||
fp.Rotation = rotation;
|
fp.Rotation = rotation;
|
||||||
@ -142,6 +138,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
if (firstTransformStartTime == null)
|
if (firstTransformStartTime == null)
|
||||||
firstTransformStartTime = fadeInTime;
|
firstTransformStartTime = fadeInTime;
|
||||||
|
|
||||||
|
fp.AnimationStartTime = fadeInTime;
|
||||||
|
|
||||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||||
{
|
{
|
||||||
fp.FadeIn(osuEnd.TimeFadeIn);
|
fp.FadeIn(osuEnd.TimeFadeIn);
|
||||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public readonly SkinnableDrawable CirclePiece;
|
public readonly SkinnableDrawable CirclePiece;
|
||||||
private readonly Container scaleContainer;
|
private readonly Container scaleContainer;
|
||||||
|
|
||||||
|
protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle;
|
||||||
|
|
||||||
public DrawableHitCircle(HitCircle h)
|
public DrawableHitCircle(HitCircle h)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
@ -57,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece()),
|
CirclePiece = new SkinnableDrawable(new OsuSkinComponent(CirclePieceComponent), _ => new MainCirclePiece()),
|
||||||
ApproachCircle = new ApproachCircle
|
ApproachCircle = new ApproachCircle
|
||||||
{
|
{
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
|
@ -11,6 +11,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.Skinning;
|
using osu.Game.Rulesets.Osu.Skinning;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
base.ApplySkin(skin, allowFallback);
|
base.ApplySkin(skin, allowFallback);
|
||||||
|
|
||||||
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
||||||
Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White;
|
Ball.AccentColour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
@ -196,6 +197,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void PlaySamples()
|
||||||
|
{
|
||||||
|
// rather than doing it this way, we should probably attach the sample to the tail circle.
|
||||||
|
// this can only be done after we stop using LegacyLastTick.
|
||||||
|
if (TailCircle.Result.Type != HitResult.Miss)
|
||||||
|
base.PlaySamples();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateStateTransforms(ArmedState state)
|
protected override void UpdateStateTransforms(ArmedState state)
|
||||||
{
|
{
|
||||||
base.UpdateStateTransforms(state);
|
base.UpdateStateTransforms(state);
|
||||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
||||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||||
|
|
||||||
|
protected override OsuSkinComponents CirclePieceComponent => OsuSkinComponents.SliderHeadHitCircle;
|
||||||
|
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
|
|
||||||
public DrawableSliderHead(Slider slider, HitCircle h)
|
public DrawableSliderHead(Slider slider, HitCircle h)
|
||||||
|
@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||||
|
|
||||||
Blending = BlendingParameters.Additive;
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
InternalChild = scaleContainer = new ReverseArrowPiece();
|
InternalChild = scaleContainer = new ReverseArrowPiece();
|
||||||
@ -87,6 +86,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||||
{
|
{
|
||||||
|
// When the repeat is hit, the arrow should fade out on spot rather than following the slider
|
||||||
|
if (IsHit) return;
|
||||||
|
|
||||||
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
|
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
|
||||||
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
|
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
|
||||||
|
|
||||||
|
@ -176,17 +176,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false;
|
|
||||||
if (!SpmCounter.IsPresent && Disc.Tracking)
|
|
||||||
SpmCounter.FadeIn(HitObject.TimeFadeIn);
|
|
||||||
|
|
||||||
base.Update();
|
base.Update();
|
||||||
|
if (HandleUserInput)
|
||||||
|
Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
|
if (!SpmCounter.IsPresent && Disc.Tracking)
|
||||||
|
SpmCounter.FadeIn(HitObject.TimeFadeIn);
|
||||||
|
|
||||||
circle.Rotation = Disc.Rotation;
|
circle.Rotation = Disc.Rotation;
|
||||||
Ticks.Rotation = Disc.Rotation;
|
Ticks.Rotation = Disc.Rotation;
|
||||||
SpmCounter.SetRotation(Disc.RotationAbsolute);
|
SpmCounter.SetRotation(Disc.RotationAbsolute);
|
||||||
|
@ -8,11 +8,16 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
{
|
{
|
||||||
public class ReverseArrowPiece : BeatSyncedContainer
|
public class ReverseArrowPiece : BeatSyncedContainer
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private DrawableHitObject drawableRepeat { get; set; }
|
||||||
|
|
||||||
public ReverseArrowPiece()
|
public ReverseArrowPiece()
|
||||||
{
|
{
|
||||||
Divisor = 2;
|
Divisor = 2;
|
||||||
@ -21,13 +26,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Blending = BlendingParameters.Additive;
|
|
||||||
|
|
||||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||||
|
|
||||||
Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon
|
Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
Icon = FontAwesome.Solid.ChevronRight,
|
Icon = FontAwesome.Solid.ChevronRight,
|
||||||
Size = new Vector2(0.35f)
|
Size = new Vector2(0.35f)
|
||||||
})
|
})
|
||||||
@ -37,7 +41,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) =>
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||||
Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out);
|
{
|
||||||
|
if (!drawableRepeat.IsHit)
|
||||||
|
Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
this.drawableSlider = drawableSlider;
|
this.drawableSlider = drawableSlider;
|
||||||
this.slider = slider;
|
this.slider = slider;
|
||||||
|
|
||||||
Blending = BlendingParameters.Additive;
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||||
@ -241,6 +240,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
Scale = new Vector2(radius / OsuHitObject.OBJECT_RADIUS),
|
Scale = new Vector2(radius / OsuHitObject.OBJECT_RADIUS),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
BorderThickness = 10,
|
BorderThickness = 10,
|
||||||
BorderColour = Color4.White,
|
BorderColour = Color4.White,
|
||||||
Alpha = 1,
|
Alpha = 1,
|
||||||
|