Merge branch 'master' of https://github.com/ppy/osu into test-snaking
@ -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.32"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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.327.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.403.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -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);
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
@ -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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,79 @@
|
|||||||
|
// 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 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.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();
|
||||||
|
|
||||||
|
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,13 +6,13 @@ 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;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
{
|
{
|
||||||
public class TestSceneDrawableJudgement : SkinnableTestScene
|
public class TestSceneDrawableJudgement : SkinnableTestScene
|
||||||
{
|
{
|
@ -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 ManiaStage(0, new StageDefinition { Columns = 4 }, ref normalAction, ref specialAction)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,6 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
typeof(Column),
|
typeof(Column),
|
||||||
typeof(ColumnBackground),
|
typeof(ColumnBackground),
|
||||||
typeof(ColumnKeyArea),
|
|
||||||
typeof(ColumnHitObjectArea)
|
typeof(ColumnHitObjectArea)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,7 +47,7 @@ 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> ConvertFromLegacyMods(LegacyMods mods)
|
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
var holdNote = (DrawableHoldNote)drawableObject;
|
||||||
|
|
||||||
updateAccentColour();
|
AccentColour.BindTo(drawableObject.AccentColour);
|
||||||
|
isHitting.BindTo(holdNote.IsHitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4 accentColour;
|
AccentColour.BindValueChanged(onAccentChanged, true);
|
||||||
|
isHitting.BindValueChanged(_ => onAccentChanged(new ValueChangedEvent<Color4>(AccentColour.Value, AccentColour.Value)), true);
|
||||||
|
}
|
||||||
|
|
||||||
public Color4 AccentColour
|
private void onAccentChanged(ValueChangedEvent<Color4> accent)
|
||||||
{
|
{
|
||||||
get => accentColour;
|
Foreground.Colour = accent.NewValue.Opacity(0.5f);
|
||||||
set
|
Background.Colour = accent.NewValue.Opacity(0.7f);
|
||||||
|
|
||||||
|
const float animation_length = 50;
|
||||||
|
|
||||||
|
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
|
||||||
|
|
||||||
|
if (isHitting.Value)
|
||||||
{
|
{
|
||||||
if (accentColour == value)
|
// wait for the next sync point
|
||||||
return;
|
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
|
||||||
|
using (Foreground.BeginDelayedSequence(synchronisedOffset))
|
||||||
accentColour = value;
|
Foreground.FadeColour(accent.NewValue.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
|
||||||
|
|
||||||
updateAccentColour();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Hitting
|
subtractionCache.Invalidate();
|
||||||
{
|
|
||||||
get => hitting;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
hitting = value;
|
|
||||||
updateAccentColour();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
134
osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
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, startAtCurrentTime: true, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
osu.Game.Rulesets.Mania/Skinning/LegacyHitTarget.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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,
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
92
osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
public LegacyNotePiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var scale = DrawWidth / noteSprite.Texture.DisplayWidth;
|
||||||
|
noteSprite.Scale = new Vector2(scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
source.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,109 +33,44 @@ 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)
|
||||||
{
|
{
|
||||||
Index = index;
|
Index = index;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
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 +105,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)
|
||||||
|
@ -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
|
||||||
};
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Depth = -1,
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override void UpdateHitPosition()
|
||||||
private void load(IScrollingInfo scrollingInfo)
|
|
||||||
{
|
{
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
base.UpdateHitPosition();
|
||||||
direction.BindValueChanged(dir =>
|
|
||||||
{
|
|
||||||
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
|
|
||||||
|
|
||||||
hitTarget.Anchor = hitTarget.Origin = anchor;
|
if (Direction.Value == ScrollingDirection.Up)
|
||||||
}, true);
|
hitTarget.Anchor = hitTarget.Origin = Anchor.TopLeft;
|
||||||
}
|
else
|
||||||
|
hitTarget.Anchor = hitTarget.Origin = Anchor.BottomLeft;
|
||||||
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.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()
|
|
||||||
{
|
|
||||||
if (!IsLoaded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hitTargetLine.EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Radius = 5,
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// 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 = ManiaStage.HIT_TARGET_POSITION,
|
||||||
|
Children = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
directionContainer.Anchor = directionContainer.Origin = Anchor.TopLeft;
|
||||||
|
gradient.Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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
|
||||||
|
?? ManiaStage.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,18 @@ 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;
|
||||||
|
|
||||||
|
// 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 +78,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>
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -32,15 +34,18 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
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));
|
||||||
|
|
||||||
@ -66,15 +71,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Name = "Columns mask",
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 5,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
@ -89,9 +85,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
|
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)
|
||||||
{
|
{
|
||||||
barLineContainer.Padding = new MarginPadding
|
currentSkin = skin;
|
||||||
|
skin.SourceChanged += onSkinChanged;
|
||||||
|
|
||||||
|
onSkinChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSkinChanged()
|
||||||
{
|
{
|
||||||
Top = dir.NewValue == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0,
|
foreach (var col in columnFlow)
|
||||||
Bottom = dir.NewValue == ScrollingDirection.Down ? HIT_TARGET_POSITION : 0,
|
{
|
||||||
};
|
if (col.Index > 0)
|
||||||
}, true);
|
{
|
||||||
|
float spacing = currentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
|
||||||
|
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, col.Index - 1))
|
||||||
|
?.Value ?? COLUMN_SPACING;
|
||||||
|
|
||||||
|
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
|
||||||
|
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 |
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;
|
||||||
|
|
||||||
@ -45,5 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
}
|
}
|
||||||
}, confineMode: ConfineMode.NoScaling);
|
}, 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,12 +128,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
|
|
||||||
FollowPoint fp;
|
FollowPoint fp;
|
||||||
|
|
||||||
if (InternalChildren.Count > point)
|
|
||||||
{
|
|
||||||
fp = (FollowPoint)InternalChildren[point];
|
|
||||||
fp.ClearTransforms();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
AddInternal(fp = new FollowPoint());
|
AddInternal(fp = new FollowPoint());
|
||||||
|
|
||||||
fp.Position = pointStartPosition;
|
fp.Position = pointStartPosition;
|
||||||
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -87,8 +87,7 @@ 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,
|
// When the repeat is hit, the arrow should fade out on spot rather than following the slider
|
||||||
// it should no longer follow snaking
|
|
||||||
if (IsHit) return;
|
if (IsHit) return;
|
||||||
|
|
||||||
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
|
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
|
||||||
|
@ -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);
|
||||||
|
@ -73,6 +73,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether currently in the correct time range to allow spinning.
|
||||||
|
/// </summary>
|
||||||
|
private bool isSpinnableTime => spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current;
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
{
|
{
|
||||||
mousePosition = Parent.ToLocalSpace(e.ScreenSpaceMousePosition);
|
mousePosition = Parent.ToLocalSpace(e.ScreenSpaceMousePosition);
|
||||||
@ -93,27 +98,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
|
var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
|
||||||
|
|
||||||
bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current;
|
var delta = thisAngle - lastAngle;
|
||||||
|
|
||||||
if (validAndTracking)
|
if (tracking)
|
||||||
{
|
Rotate(delta);
|
||||||
if (!rotationTransferred)
|
|
||||||
{
|
|
||||||
currentRotation = Rotation * 2;
|
|
||||||
rotationTransferred = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thisAngle - lastAngle > 180)
|
|
||||||
lastAngle += 360;
|
|
||||||
else if (lastAngle - thisAngle > 180)
|
|
||||||
lastAngle -= 360;
|
|
||||||
|
|
||||||
currentRotation += thisAngle - lastAngle;
|
|
||||||
RotationAbsolute += Math.Abs(thisAngle - lastAngle) * Math.Sign(Clock.ElapsedFrameTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastAngle = thisAngle;
|
lastAngle = thisAngle;
|
||||||
|
|
||||||
@ -128,5 +118,38 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
Rotation = (float)Interpolation.Lerp(Rotation, currentRotation / 2, Math.Clamp(Math.Abs(Time.Elapsed) / 40, 0, 1));
|
Rotation = (float)Interpolation.Lerp(Rotation, currentRotation / 2, Math.Clamp(Math.Abs(Time.Elapsed) / 40, 0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotate the disc by the provided angle (in addition to any existing rotation).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Will be a no-op if not a valid time to spin.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="angle">The delta angle.</param>
|
||||||
|
public void Rotate(float angle)
|
||||||
|
{
|
||||||
|
if (!isSpinnableTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!rotationTransferred)
|
||||||
|
{
|
||||||
|
currentRotation = Rotation * 2;
|
||||||
|
rotationTransferred = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (angle > 180)
|
||||||
|
{
|
||||||
|
lastAngle += 360;
|
||||||
|
angle -= 360;
|
||||||
|
}
|
||||||
|
else if (-angle > 180)
|
||||||
|
{
|
||||||
|
lastAngle -= 360;
|
||||||
|
angle += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRotation += angle;
|
||||||
|
RotationAbsolute += Math.Abs(angle) * Math.Sign(Clock.ElapsedFrameTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,6 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new OsuModEasy(),
|
new OsuModEasy(),
|
||||||
new OsuModNoFail(),
|
new OsuModNoFail(),
|
||||||
new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
|
new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
|
||||||
new OsuModSpunOut(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.DifficultyIncrease:
|
case ModType.DifficultyIncrease:
|
||||||
@ -139,6 +138,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new MultiMod(new OsuModAutoplay(), new OsuModCinema()),
|
new MultiMod(new OsuModAutoplay(), new OsuModCinema()),
|
||||||
new OsuModRelax(),
|
new OsuModRelax(),
|
||||||
new OsuModAutopilot(),
|
new OsuModAutopilot(),
|
||||||
|
new OsuModSpunOut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Fun:
|
case ModType.Fun:
|
||||||
@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this);
|
public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this);
|
||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new OsuLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new OsuLegacySkinTransformer(source);
|
||||||
|
|
||||||
public int LegacyID => 0;
|
public int LegacyID => 0;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
ApproachCircle,
|
ApproachCircle,
|
||||||
ReverseArrow,
|
ReverseArrow,
|
||||||
HitCircleText,
|
HitCircleText,
|
||||||
|
SliderHeadHitCircle,
|
||||||
SliderFollowCircle,
|
SliderFollowCircle,
|
||||||
SliderBall,
|
SliderBall,
|
||||||
SliderBody,
|
SliderBody,
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -18,8 +19,12 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
public class LegacyMainCirclePiece : CompositeDrawable
|
public class LegacyMainCirclePiece : CompositeDrawable
|
||||||
{
|
{
|
||||||
public LegacyMainCirclePiece()
|
private readonly string priorityLookup;
|
||||||
|
|
||||||
|
public LegacyMainCirclePiece(string priorityLookup = null)
|
||||||
{
|
{
|
||||||
|
this.priorityLookup = priorityLookup;
|
||||||
|
|
||||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
hitCircleSprite = new Sprite
|
hitCircleSprite = new Sprite
|
||||||
{
|
{
|
||||||
Texture = skin.GetTexture("hitcircle"),
|
Texture = getTextureWithFallback(string.Empty),
|
||||||
Colour = drawableObject.AccentColour.Value,
|
Colour = drawableObject.AccentColour.Value,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -51,12 +56,17 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
}, confineMode: ConfineMode.NoScaling),
|
}, confineMode: ConfineMode.NoScaling),
|
||||||
new Sprite
|
new Sprite
|
||||||
{
|
{
|
||||||
Texture = skin.GetTexture("hitcircleoverlay"),
|
Texture = getTextureWithFallback("overlay"),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool overlayAboveNumber = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.HitCircleOverlayAboveNumber)?.Value ?? true;
|
||||||
|
|
||||||
|
if (!overlayAboveNumber)
|
||||||
|
ChangeInternalChildDepth(hitCircleText, -float.MaxValue);
|
||||||
|
|
||||||
state.BindTo(drawableObject.State);
|
state.BindTo(drawableObject.State);
|
||||||
state.BindValueChanged(updateState, true);
|
state.BindValueChanged(updateState, true);
|
||||||
|
|
||||||
@ -65,6 +75,16 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable);
|
indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable);
|
||||||
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
||||||
|
|
||||||
|
Texture getTextureWithFallback(string name)
|
||||||
|
{
|
||||||
|
Texture tex = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(priorityLookup))
|
||||||
|
tex = skin.GetTexture($"{priorityLookup}{name}");
|
||||||
|
|
||||||
|
return tex ?? skin.GetTexture($"hitcircle{name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateState(ValueChangedEvent<ArmedState> state)
|
private void updateState(ValueChangedEvent<ArmedState> state)
|
||||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
public LegacySliderBall(Drawable animationContent)
|
public LegacySliderBall(Drawable animationContent)
|
||||||
{
|
{
|
||||||
this.animationContent = animationContent;
|
this.animationContent = animationContent;
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -62,17 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
// Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
|
// Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
|
||||||
|
|
||||||
if (sliderBallContent != null)
|
if (sliderBallContent != null)
|
||||||
{
|
return new LegacySliderBall(sliderBallContent);
|
||||||
var size = sliderBallContent.Size;
|
|
||||||
|
|
||||||
sliderBallContent.RelativeSizeAxes = Axes.Both;
|
|
||||||
sliderBallContent.Size = Vector2.One;
|
|
||||||
|
|
||||||
return new LegacySliderBall(sliderBallContent)
|
|
||||||
{
|
|
||||||
Size = size
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -82,6 +72,12 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
case OsuSkinComponents.SliderHeadHitCircle:
|
||||||
|
if (hasHitCircle.Value)
|
||||||
|
return new LegacyMainCirclePiece("sliderstartcircle");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case OsuSkinComponents.HitCircle:
|
case OsuSkinComponents.HitCircle:
|
||||||
if (hasHitCircle.Value)
|
if (hasHitCircle.Value)
|
||||||
return new LegacyMainCirclePiece();
|
return new LegacyMainCirclePiece();
|
||||||
|
@ -11,6 +11,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
SliderPathRadius,
|
SliderPathRadius,
|
||||||
AllowSliderBallTint,
|
AllowSliderBallTint,
|
||||||
CursorExpand,
|
CursorExpand,
|
||||||
CursorRotate
|
CursorRotate,
|
||||||
|
HitCircleOverlayAboveNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 7.6 KiB |
@ -4,31 +4,28 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Audio;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Taiko.Audio;
|
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Tests
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneInputDrum : OsuTestScene
|
public class TestSceneInputDrum : SkinnableTestScene
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
typeof(InputDrum),
|
typeof(InputDrum),
|
||||||
typeof(DrumSampleMapping),
|
|
||||||
typeof(HitSampleInfo),
|
|
||||||
typeof(SampleControlPoint)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public TestSceneInputDrum()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
Add(new TaikoInputManager(new RulesetInfo { ID = 1 })
|
SetContents(() => new TaikoInputManager(new RulesetInfo { ID = 1 })
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = new Container
|
Child = new Container
|
||||||
|
144
osu.Game.Rulesets.Taiko/Skinning/LegacyInputDrum.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.Taiko.Audio;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A component of the playfield that captures input and displays input as a drum.
|
||||||
|
/// </summary>
|
||||||
|
internal class LegacyInputDrum : Container
|
||||||
|
{
|
||||||
|
public LegacyInputDrum()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin)
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Texture = skin.GetTexture("taiko-bar-left")
|
||||||
|
},
|
||||||
|
new LegacyHalfDrum(false)
|
||||||
|
{
|
||||||
|
Name = "Left Half",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
RimAction = TaikoAction.LeftRim,
|
||||||
|
CentreAction = TaikoAction.LeftCentre
|
||||||
|
},
|
||||||
|
new LegacyHalfDrum(true)
|
||||||
|
{
|
||||||
|
Name = "Right Half",
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Scale = new Vector2(-1, 1),
|
||||||
|
RimAction = TaikoAction.RightRim,
|
||||||
|
CentreAction = TaikoAction.RightCentre
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A half-drum. Contains one centre and one rim hit.
|
||||||
|
/// </summary>
|
||||||
|
private class LegacyHalfDrum : Container, IKeyBindingHandler<TaikoAction>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The key to be used for the rim of the half-drum.
|
||||||
|
/// </summary>
|
||||||
|
public TaikoAction RimAction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key to be used for the centre of the half-drum.
|
||||||
|
/// </summary>
|
||||||
|
public TaikoAction CentreAction;
|
||||||
|
|
||||||
|
private readonly Sprite rimHit;
|
||||||
|
private readonly Sprite centreHit;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private DrumSampleMapping sampleMappings { get; set; }
|
||||||
|
|
||||||
|
public LegacyHalfDrum(bool flipped)
|
||||||
|
{
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rimHit = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = flipped ? Anchor.CentreRight : Anchor.CentreLeft,
|
||||||
|
Origin = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Scale = new Vector2(-1, 1),
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
centreHit = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = flipped ? Anchor.CentreRight : Anchor.CentreLeft,
|
||||||
|
Origin = flipped ? Anchor.CentreRight : Anchor.CentreLeft,
|
||||||
|
Alpha = 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin)
|
||||||
|
{
|
||||||
|
rimHit.Texture = skin.GetTexture(@"taiko-drum-outer");
|
||||||
|
centreHit.Texture = skin.GetTexture(@"taiko-drum-inner");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(TaikoAction action)
|
||||||
|
{
|
||||||
|
Drawable target = null;
|
||||||
|
var drumSample = sampleMappings.SampleAt(Time.Current);
|
||||||
|
|
||||||
|
if (action == CentreAction)
|
||||||
|
{
|
||||||
|
target = centreHit;
|
||||||
|
drumSample.Centre?.Play();
|
||||||
|
}
|
||||||
|
else if (action == RimAction)
|
||||||
|
{
|
||||||
|
target = rimHit;
|
||||||
|
drumSample.Rim?.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
const float alpha_amount = 1;
|
||||||
|
|
||||||
|
const float down_time = 80;
|
||||||
|
const float up_time = 50;
|
||||||
|
|
||||||
|
target.Animate(
|
||||||
|
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time)
|
||||||
|
).Then(
|
||||||
|
t => t.FadeOut(up_time)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(TaikoAction action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,22 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable GetDrawableComponent(ISkinComponent component) => source.GetDrawableComponent(component);
|
public Drawable GetDrawableComponent(ISkinComponent component)
|
||||||
|
{
|
||||||
|
if (!(component is TaikoSkinComponent taikoComponent))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (taikoComponent.Component)
|
||||||
|
{
|
||||||
|
case TaikoSkinComponents.InputDrum:
|
||||||
|
if (GetTexture("taiko-bar-left") != null)
|
||||||
|
return new LegacyInputDrum();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.GetDrawableComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
public Texture GetTexture(string componentName) => source.GetTexture(componentName);
|
public Texture GetTexture(string componentName) => source.GetTexture(componentName);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new TaikoLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new TaikoLegacySkinTransformer(source);
|
||||||
|
|
||||||
public const string SHORT_NAME = "taiko";
|
public const string SHORT_NAME = "taiko";
|
||||||
|
|
||||||
|
@ -5,5 +5,6 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
{
|
{
|
||||||
public enum TaikoSkinComponents
|
public enum TaikoSkinComponents
|
||||||
{
|
{
|
||||||
|
InputDrum,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Input.Bindings;
|
|||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Taiko.Audio;
|
using osu.Game.Rulesets.Taiko.Audio;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.UI
|
namespace osu.Game.Rulesets.Taiko.UI
|
||||||
{
|
{
|
||||||
@ -22,11 +23,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
private const float middle_split = 0.025f;
|
private const float middle_split = 0.025f;
|
||||||
|
|
||||||
private readonly ControlPointInfo controlPoints;
|
[Cached]
|
||||||
|
private DrumSampleMapping sampleMapping;
|
||||||
|
|
||||||
public InputDrum(ControlPointInfo controlPoints)
|
public InputDrum(ControlPointInfo controlPoints)
|
||||||
{
|
{
|
||||||
this.controlPoints = controlPoints;
|
sampleMapping = new DrumSampleMapping(controlPoints);
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
@ -35,11 +37,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
var sampleMappings = new DrumSampleMapping(controlPoints);
|
Child = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.InputDrum), _ => new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new TaikoHalfDrum(false, sampleMappings)
|
new TaikoHalfDrum(false)
|
||||||
{
|
{
|
||||||
Name = "Left Half",
|
Name = "Left Half",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -50,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
RimAction = TaikoAction.LeftRim,
|
RimAction = TaikoAction.LeftRim,
|
||||||
CentreAction = TaikoAction.LeftCentre
|
CentreAction = TaikoAction.LeftCentre
|
||||||
},
|
},
|
||||||
new TaikoHalfDrum(true, sampleMappings)
|
new TaikoHalfDrum(true)
|
||||||
{
|
{
|
||||||
Name = "Right Half",
|
Name = "Right Half",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -61,9 +64,10 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
RimAction = TaikoAction.RightRim,
|
RimAction = TaikoAction.RightRim,
|
||||||
CentreAction = TaikoAction.RightCentre
|
CentreAction = TaikoAction.RightCentre
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
AddRangeInternal(sampleMappings.Sounds);
|
AddRangeInternal(sampleMapping.Sounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -86,12 +90,11 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
private readonly Sprite centre;
|
private readonly Sprite centre;
|
||||||
private readonly Sprite centreHit;
|
private readonly Sprite centreHit;
|
||||||
|
|
||||||
private readonly DrumSampleMapping sampleMappings;
|
[Resolved]
|
||||||
|
private DrumSampleMapping sampleMappings { get; set; }
|
||||||
|
|
||||||
public TaikoHalfDrum(bool flipped, DrumSampleMapping sampleMappings)
|
public TaikoHalfDrum(bool flipped)
|
||||||
{
|
{
|
||||||
this.sampleMappings = sampleMappings;
|
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -127,6 +127,31 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
.Assert();
|
.Assert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGetJsonDecoder()
|
||||||
|
{
|
||||||
|
Decoder<Beatmap> decoder;
|
||||||
|
|
||||||
|
using (var stream = TestResources.OpenResource(normal))
|
||||||
|
using (var sr = new LineBufferedReader(stream))
|
||||||
|
{
|
||||||
|
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
|
||||||
|
|
||||||
|
using (var memStream = new MemoryStream())
|
||||||
|
using (var memWriter = new StreamWriter(memStream))
|
||||||
|
using (var memReader = new LineBufferedReader(memStream))
|
||||||
|
{
|
||||||
|
memWriter.Write(legacyDecoded.Serialize());
|
||||||
|
memWriter.Flush();
|
||||||
|
|
||||||
|
memStream.Position = 0;
|
||||||
|
decoder = Decoder.GetDecoder<Beatmap>(memReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsInstanceOf(typeof(JsonBeatmapDecoder), decoder);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a .osu file first with a <see cref="LegacyBeatmapDecoder"/>, serializes the resulting <see cref="Beatmap"/> to JSON
|
/// Reads a .osu file first with a <see cref="LegacyBeatmapDecoder"/>, serializes the resulting <see cref="Beatmap"/> to JSON
|
||||||
/// and then deserializes the result back into a <see cref="Beatmap"/> through an <see cref="JsonBeatmapDecoder"/>.
|
/// and then deserializes the result back into a <see cref="Beatmap"/> through an <see cref="JsonBeatmapDecoder"/>.
|
||||||
|
3
osu.Game.Tests/Resources/mania-skin-colours.ini
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[Mania]
|
||||||
|
Keys: 4
|
||||||
|
ColourBarline: 50,50,50,50
|
9
osu.Game.Tests/Resources/mania-skin-duplicate.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Mania]
|
||||||
|
Keys: 4
|
||||||
|
ColumnWidth: 10,10,10,10
|
||||||
|
HitPosition: 470
|
||||||
|
|
||||||
|
[Mania]
|
||||||
|
Keys: 4
|
||||||
|
ColumnWidth: 20,20,20,20
|
||||||
|
HitPosition: 460
|
4
osu.Game.Tests/Resources/mania-skin-extra-data.ini
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[Mania]
|
||||||
|
Keys: 4
|
||||||
|
ColumnWidth: 10,10,10,10,10,10,10
|
||||||
|
HitPosition: 470
|
9
osu.Game.Tests/Resources/mania-skin-multiple.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Mania]
|
||||||
|
Keys: 4
|
||||||
|
ColumnWidth: 10,10,10,10
|
||||||
|
HitPosition: 470
|
||||||
|
|
||||||
|
[Mania]
|
||||||
|
Keys: 2
|
||||||
|
ColumnWidth: 20,20
|
||||||
|
HitPosition: 460
|
4
osu.Game.Tests/Resources/mania-skin-single.ini
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[Mania]
|
||||||
|
Keys: 4
|
||||||
|
ColumnWidth: 10,10,10,10
|
||||||
|
HitPosition: 470
|