Merge branch 'master' into add-notelock
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="1" />
|
||||
<option name="vcsConfiguration" value="2" />
|
||||
</component>
|
||||
</project>
|
@ -5,6 +5,6 @@
|
||||
"version": "3.1.100"
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.Build.Traversal": "2.0.24"
|
||||
"Microsoft.Build.Traversal": "2.0.34"
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.327.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.403.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.407.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
21
osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public abstract class CatchSkinnableTestScene : SkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CatchRuleset),
|
||||
typeof(CatchLegacySkinTransformer),
|
||||
};
|
||||
|
||||
protected override Ruleset CreateRulesetForSkinProvider() => new CatchRuleset();
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -4,21 +4,21 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCatcher : SkinnableTestScene
|
||||
public class TestSceneCatcher : CatchSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||
{
|
||||
typeof(CatcherArea),
|
||||
typeof(CatcherSprite)
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
|
@ -17,12 +17,11 @@ using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCatcherArea : SkinnableTestScene
|
||||
public class TestSceneCatcherArea : CatchSkinnableTestScene
|
||||
{
|
||||
private RulesetInfo catchRuleset;
|
||||
|
||||
|
@ -3,20 +3,20 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneFruitObjects : SkinnableTestScene
|
||||
public class TestSceneFruitObjects : CatchSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||
{
|
||||
typeof(CatchHitObject),
|
||||
typeof(Fruit),
|
||||
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
typeof(DrawableBanana),
|
||||
typeof(DrawableBananaShower),
|
||||
typeof(Pulp),
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
|
||||
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);
|
||||
|
||||
|
@ -72,10 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
protected override Skill[] CreateSkills(IBeatmap beatmap)
|
||||
{
|
||||
using (var catcher = new Catcher(beatmap.BeatmapInfo.BaseDifficulty))
|
||||
{
|
||||
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[]
|
||||
{
|
||||
|
@ -37,10 +37,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
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>
|
||||
/// Width of the area that can be used to attempt catches during gameplay.
|
||||
/// </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
|
||||
{
|
||||
@ -379,7 +384,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
|
||||
currentCatcher.Show();
|
||||
(currentCatcher.Drawable as IAnimation)?.GotoFrame(0);
|
||||
(currentCatcher.Drawable as IFramedAnimation)?.GotoFrame(0);
|
||||
}
|
||||
|
||||
private void beginTrail()
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public CatcherSprite(CatcherAnimationState state)
|
||||
: base(new CatchSkinComponent(componentFromState(state)), _ =>
|
||||
new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleDownToFit)
|
||||
new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleToFit)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 1.9 KiB |
@ -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,91 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Mania.Skinning;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A test scene for skinnable mania components.
|
||||
/// </summary>
|
||||
public abstract class ManiaSkinnableTestScene : SkinnableTestScene
|
||||
{
|
||||
protected const double START_TIME = 1000000000;
|
||||
|
||||
[Cached(Type = typeof(IScrollingInfo))]
|
||||
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ManiaRuleset),
|
||||
typeof(ManiaLegacySkinTransformer),
|
||||
typeof(ManiaSettingsSubsection)
|
||||
};
|
||||
|
||||
protected override Ruleset CreateRulesetForSkinProvider() => new ManiaRuleset();
|
||||
|
||||
protected ManiaSkinnableTestScene()
|
||||
{
|
||||
scrollingInfo.Direction.Value = ScrollingDirection.Down;
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.SlateGray.Opacity(0.2f),
|
||||
Depth = 1
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScrollingDown()
|
||||
{
|
||||
AddStep("change direction to down", () => scrollingInfo.Direction.Value = ScrollingDirection.Down);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScrollingUp()
|
||||
{
|
||||
AddStep("change direction to up", () => scrollingInfo.Direction.Value = ScrollingDirection.Up);
|
||||
}
|
||||
|
||||
private class TestScrollingInfo : IScrollingInfo
|
||||
{
|
||||
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(1000);
|
||||
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ZeroScrollAlgorithm();
|
||||
}
|
||||
|
||||
private class ZeroScrollAlgorithm : IScrollAlgorithm
|
||||
{
|
||||
public double GetDisplayStartTime(double originTime, float offset, double timeRange, float scrollLength)
|
||||
=> double.MinValue;
|
||||
|
||||
public float GetLength(double startTime, double endTime, double timeRange, float scrollLength)
|
||||
=> scrollLength;
|
||||
|
||||
public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
|
||||
=> (float)((time - START_TIME) / timeRange) * scrollLength;
|
||||
|
||||
public double TimeAt(float position, double currentTime, double timeRange, float scrollLength)
|
||||
=> 0;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.UI.Components;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneColumnBackground : ManiaSkinnableTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.8f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 0), _ => new DefaultColumnBackground())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
},
|
||||
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 0), _ => new DefaultColumnBackground())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.UI.Components;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneColumnHitObjectArea : ManiaSkinnableTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.8f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
Child = new ColumnHitObjectArea(0, new HitObjectContainer())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
},
|
||||
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
Child = new ColumnHitObjectArea(1, new HitObjectContainer())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -6,15 +6,14 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneDrawableJudgement : SkinnableTestScene
|
||||
public class TestSceneDrawableJudgement : ManiaSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
@ -0,0 +1,66 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneHitExplosion : ManiaSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableNote),
|
||||
typeof(DrawableManiaHitObject),
|
||||
};
|
||||
|
||||
public TestSceneHitExplosion()
|
||||
{
|
||||
int runcount = 0;
|
||||
|
||||
AddRepeatStep("explode", () =>
|
||||
{
|
||||
runcount++;
|
||||
|
||||
if (runcount % 15 > 12)
|
||||
return;
|
||||
|
||||
CreatedDrawables.OfType<Container>().ForEach(c =>
|
||||
{
|
||||
c.Add(new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, 0),
|
||||
_ => new DefaultHitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}));
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new ColumnTestContainer(0, ManiaAction.Key1)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Y = -0.25f,
|
||||
Size = new Vector2(Column.COLUMN_WIDTH, DefaultNotePiece.NOTE_HEIGHT),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
35
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHoldNote.cs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneHoldNote : ManiaHitObjectTestScene
|
||||
{
|
||||
public TestSceneHoldNote()
|
||||
{
|
||||
AddToggleStep("toggle hitting", v =>
|
||||
{
|
||||
foreach (var holdNote in CreatedDrawables.SelectMany(d => d.ChildrenOfType<DrawableHoldNote>()))
|
||||
{
|
||||
((Bindable<bool>)holdNote.IsHitting).Value = v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override DrawableManiaHitObject CreateHitObject()
|
||||
{
|
||||
var note = new HoldNote { Duration = 1000 };
|
||||
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
return new DrawableHoldNote(note);
|
||||
}
|
||||
}
|
||||
}
|
58
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Skinning;
|
||||
using osu.Game.Rulesets.Mania.UI.Components;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneKeyArea : ManiaSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DefaultKeyArea),
|
||||
typeof(LegacyKeyArea)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.8f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ColumnTestContainer(0, ManiaAction.Key1)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, 0), _ => new DefaultKeyArea())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
},
|
||||
new ColumnTestContainer(1, ManiaAction.Key2)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea, 1), _ => new DefaultKeyArea())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
21
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneNote.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneNote : ManiaHitObjectTestScene
|
||||
{
|
||||
protected override DrawableManiaHitObject CreateHitObject()
|
||||
{
|
||||
var note = new Note();
|
||||
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
return new DrawableNote(note);
|
||||
}
|
||||
}
|
||||
}
|
52
osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestScenePlayfield : ManiaSkinnableTestScene
|
||||
{
|
||||
private List<StageDefinition> stageDefinitions = new List<StageDefinition>();
|
||||
|
||||
[Test]
|
||||
public void TestSingleStage()
|
||||
{
|
||||
AddStep("create stage", () =>
|
||||
{
|
||||
stageDefinitions = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 2 }
|
||||
};
|
||||
|
||||
SetContents(() => new ManiaPlayfield(stageDefinitions));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDualStages()
|
||||
{
|
||||
AddStep("create stage", () =>
|
||||
{
|
||||
stageDefinitions = new List<StageDefinition>
|
||||
{
|
||||
new StageDefinition { Columns = 2 },
|
||||
new StageDefinition { Columns = 2 }
|
||||
};
|
||||
|
||||
SetContents(() => new ManiaPlayfield(stageDefinitions));
|
||||
});
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmapForSkinProvider()
|
||||
{
|
||||
var maniaBeatmap = (ManiaBeatmap)base.CreateBeatmapForSkinProvider();
|
||||
maniaBeatmap.Stages = stageDefinitions;
|
||||
return maniaBeatmap;
|
||||
}
|
||||
}
|
||||
}
|
27
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneStage : ManiaSkinnableTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() =>
|
||||
{
|
||||
ManiaAction normalAction = ManiaAction.Key1;
|
||||
ManiaAction specialAction = ManiaAction.Special1;
|
||||
|
||||
return new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4)
|
||||
{
|
||||
Child = new Stage(0, new StageDefinition { Columns = 4 }, ref normalAction, ref specialAction)
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Skinning;
|
||||
using osu.Game.Rulesets.Mania.UI.Components;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneStageBackground : ManiaSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||
{
|
||||
typeof(DefaultStageBackground),
|
||||
typeof(LegacyStageBackground),
|
||||
}).ToList();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Skinning;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
public class TestSceneStageForeground : ManiaSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||
{
|
||||
typeof(LegacyStageForeground),
|
||||
}).ToList();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.5f,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -28,8 +28,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
typeof(Column),
|
||||
typeof(ColumnBackground),
|
||||
typeof(ColumnKeyArea),
|
||||
typeof(ColumnHitObjectArea)
|
||||
typeof(ColumnHitObjectArea),
|
||||
typeof(DefaultKeyArea),
|
||||
typeof(DefaultHitTarget)
|
||||
};
|
||||
|
||||
[Cached(typeof(IReadOnlyList<Mod>))]
|
||||
|
@ -1,62 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneHitExplosion : OsuTestScene
|
||||
{
|
||||
private ScrollingTestContainer scrolling;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableNote),
|
||||
typeof(DrawableManiaHitObject),
|
||||
};
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Child = scrolling = new ScrollingTestContainer(ScrollingDirection.Down)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Y = -0.25f,
|
||||
Size = new Vector2(Column.COLUMN_WIDTH, NotePiece.NOTE_HEIGHT),
|
||||
};
|
||||
|
||||
int runcount = 0;
|
||||
|
||||
AddRepeatStep("explode", () =>
|
||||
{
|
||||
runcount++;
|
||||
|
||||
if (runcount % 15 > 12)
|
||||
return;
|
||||
|
||||
scrolling.AddRange(new Drawable[]
|
||||
{
|
||||
new HitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
[Cached(typeof(IReadOnlyList<Mod>))]
|
||||
private IReadOnlyList<Mod> mods { get; set; } = Array.Empty<Mod>();
|
||||
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
private readonly List<Stage> stages = new List<Stage>();
|
||||
|
||||
private FillFlowContainer<ScrollingTestContainer> fill;
|
||||
|
||||
@ -81,9 +81,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.TopCentre));
|
||||
}
|
||||
|
||||
private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
|
||||
private bool notesInStageAreAnchored(Stage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
|
||||
|
||||
private bool barsInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor);
|
||||
private bool barsInStageAreAnchored(Stage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor);
|
||||
|
||||
private void createNote()
|
||||
{
|
||||
@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
var specialAction = ManiaAction.Special1;
|
||||
|
||||
var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction);
|
||||
var stage = new Stage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction);
|
||||
stages.Add(stage);
|
||||
|
||||
return new ScrollingTestContainer(direction)
|
||||
|
@ -1,9 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Game.Rulesets.Mania
|
||||
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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
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>
|
||||
/// <returns>Whether the column is a special column.</returns>
|
||||
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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
@ -19,13 +20,14 @@ namespace osu.Game.Rulesets.Mania.Configuration
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
public class EditBodyPiece : BodyPiece
|
||||
public class EditBodyPiece : DefaultBodyPiece
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
AccentColour = colours.Yellow;
|
||||
AccentColour.Value = colours.Yellow;
|
||||
|
||||
Background.Alpha = 0.5f;
|
||||
Foreground.Alpha = 0;
|
||||
|
@ -12,12 +12,12 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||
{
|
||||
public EditNotePiece()
|
||||
{
|
||||
Height = NotePiece.NOTE_HEIGHT;
|
||||
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
InternalChild = new NotePiece();
|
||||
InternalChild = new DefaultNotePiece();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -4,13 +4,13 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
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.End),
|
||||
new BodyPiece
|
||||
new Container
|
||||
{
|
||||
AccentColour = Color4.Transparent,
|
||||
BorderColour = colours.Yellow
|
||||
},
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
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)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
mousePosition.Y -= NotePiece.NOTE_HEIGHT / 2;
|
||||
mousePosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Down:
|
||||
mousePosition.Y += NotePiece.NOTE_HEIGHT / 2;
|
||||
mousePosition.Y += DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -143,11 +143,11 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
hitObjectPosition.Y += NotePiece.NOTE_HEIGHT / 2;
|
||||
hitObjectPosition.Y += DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Down:
|
||||
hitObjectPosition.Y -= NotePiece.NOTE_HEIGHT / 2;
|
||||
hitObjectPosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -1,19 +1,46 @@
|
||||
// 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
|
||||
{
|
||||
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)
|
||||
{
|
||||
TargetColumn = targetColumn;
|
||||
}
|
||||
|
||||
protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME;
|
||||
|
||||
protected override string ComponentName => Component.ToString().ToLower();
|
||||
}
|
||||
|
||||
public enum ManiaSkinComponents
|
||||
{
|
||||
ColumnBackground,
|
||||
HitTarget,
|
||||
KeyArea,
|
||||
Note,
|
||||
HoldNoteHead,
|
||||
HoldNoteTail,
|
||||
HoldNoteBody,
|
||||
HitExplosion,
|
||||
StageBackground,
|
||||
StageForeground,
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
@ -20,6 +21,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
public IBindable<bool> IsHitting => isHitting;
|
||||
|
||||
private readonly Bindable<bool> isHitting = new Bindable<bool>();
|
||||
|
||||
public DrawableHoldNoteHead Head => headContainer.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<DrawableHoldNoteTick> tickContainer;
|
||||
|
||||
private readonly BodyPiece bodyPiece;
|
||||
private readonly Drawable bodyPiece;
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
|
||||
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 },
|
||||
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both },
|
||||
tailContainer = new Container<DrawableHoldNoteTail> { RelativeSizeAxes = Axes.Both },
|
||||
});
|
||||
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
bodyPiece.AccentColour = colour.NewValue;
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||
@ -168,7 +171,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
return;
|
||||
|
||||
HoldStartTime = Time.Current;
|
||||
bodyPiece.Hitting = true;
|
||||
isHitting.Value = true;
|
||||
}
|
||||
|
||||
public void OnReleased(ManiaAction action)
|
||||
@ -194,7 +197,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
private void endHold()
|
||||
{
|
||||
HoldStartTime = null;
|
||||
bodyPiece.Hitting = false;
|
||||
isHitting.Value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
public class DrawableHoldNoteHead : DrawableNote
|
||||
{
|
||||
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteHead;
|
||||
|
||||
public DrawableHoldNoteHead(DrawableHoldNote holdNote)
|
||||
: base(holdNote.HitObject.Head)
|
||||
{
|
||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
private const double release_window_lenience = 1.5;
|
||||
|
||||
protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteTail;
|
||||
|
||||
private readonly DrawableHoldNote holdNote;
|
||||
|
||||
public DrawableHoldNoteTail(DrawableHoldNote holdNote)
|
||||
|
@ -3,13 +3,12 @@
|
||||
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
@ -18,7 +17,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
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)
|
||||
: base(hitObject)
|
||||
@ -26,22 +27,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
AddInternal(headPiece = new NotePiece());
|
||||
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinComponent(Component, hitObject.Column), _ => new DefaultNotePiece())
|
||||
{
|
||||
headPiece.AccentColour = colour.NewValue;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = colour.NewValue.Lighten(1f).Opacity(0.2f),
|
||||
Radius = 10,
|
||||
};
|
||||
}, true);
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
||||
|
@ -2,6 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -9,26 +12,38 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents length-wise portion of a hold note.
|
||||
/// </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;
|
||||
protected readonly BufferedContainer Foreground;
|
||||
private readonly BufferedContainer subtractionContainer;
|
||||
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
|
||||
private readonly IBindable<bool> isHitting = new Bindable<bool>();
|
||||
|
||||
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;
|
||||
|
||||
Children = new[]
|
||||
AddLayout(subtractionCache);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load([CanBeNull] DrawableHitObject drawableObject)
|
||||
{
|
||||
InternalChildren = new[]
|
||||
{
|
||||
Background = new Box { RelativeSizeAxes = Axes.Both },
|
||||
Foreground = new BufferedContainer
|
||||
@ -66,43 +81,37 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
}
|
||||
};
|
||||
|
||||
AddLayout(subtractionCache);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
updateAccentColour();
|
||||
}
|
||||
|
||||
private Color4 accentColour;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
if (drawableObject != null)
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
var holdNote = (DrawableHoldNote)drawableObject;
|
||||
|
||||
accentColour = value;
|
||||
|
||||
updateAccentColour();
|
||||
AccentColour.BindTo(drawableObject.AccentColour);
|
||||
isHitting.BindTo(holdNote.IsHitting);
|
||||
}
|
||||
|
||||
AccentColour.BindValueChanged(onAccentChanged, true);
|
||||
isHitting.BindValueChanged(_ => onAccentChanged(new ValueChangedEvent<Color4>(AccentColour.Value, AccentColour.Value)), true);
|
||||
}
|
||||
|
||||
public bool Hitting
|
||||
private void onAccentChanged(ValueChangedEvent<Color4> accent)
|
||||
{
|
||||
get => hitting;
|
||||
set
|
||||
{
|
||||
hitting = value;
|
||||
updateAccentColour();
|
||||
}
|
||||
}
|
||||
Foreground.Colour = accent.NewValue.Opacity(0.5f);
|
||||
Background.Colour = accent.NewValue.Opacity(0.7f);
|
||||
|
||||
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
|
||||
const float animation_length = 50;
|
||||
|
||||
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
|
||||
|
||||
if (isHitting.Value)
|
||||
{
|
||||
// wait for the next sync point
|
||||
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
|
||||
using (Foreground.BeginDelayedSequence(synchronisedOffset))
|
||||
Foreground.FadeColour(accent.NewValue.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
|
||||
}
|
||||
|
||||
subtractionCache.Invalidate();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
@ -125,30 +134,5 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
141
osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
private readonly bool isLastColumn;
|
||||
|
||||
private Container lightContainer;
|
||||
private Sprite light;
|
||||
|
||||
public LegacyColumnBackground(bool isLastColumn)
|
||||
{
|
||||
this.isLastColumn = isLastColumn;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
string lightImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.LightImage, 0)?.Value
|
||||
?? "mania-stage-light";
|
||||
|
||||
float leftLineWidth = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.LeftLineWidth)
|
||||
?.Value ?? 1;
|
||||
float rightLineWidth = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.RightLineWidth)
|
||||
?.Value ?? 1;
|
||||
|
||||
bool hasLeftLine = leftLineWidth > 0;
|
||||
bool hasRightLine = rightLineWidth > 0 && skin.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value >= 2.4m
|
||||
|| isLastColumn;
|
||||
|
||||
float lightPosition = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.LightPosition)?.Value
|
||||
?? 0;
|
||||
|
||||
Color4 lineColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnLineColour)?.Value
|
||||
?? Color4.White;
|
||||
|
||||
Color4 backgroundColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour)?.Value
|
||||
?? Color4.Black;
|
||||
|
||||
Color4 lightColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.ColumnLightColour)?.Value
|
||||
?? Color4.White;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = backgroundColour
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = leftLineWidth,
|
||||
Colour = lineColour,
|
||||
Alpha = hasLeftLine ? 1 : 0
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = rightLineWidth,
|
||||
Colour = lineColour,
|
||||
Alpha = hasRightLine ? 1 : 0
|
||||
},
|
||||
lightContainer = new Container
|
||||
{
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Bottom = lightPosition },
|
||||
Child = light = new Sprite
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Colour = lightColour,
|
||||
Texture = skin.GetTexture(lightImage),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 1,
|
||||
Alpha = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
lightContainer.Anchor = Anchor.TopCentre;
|
||||
lightContainer.Scale = new Vector2(1, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightContainer.Anchor = Anchor.BottomCentre;
|
||||
lightContainer.Scale = Vector2.One;
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == Column.Action.Value)
|
||||
{
|
||||
light.FadeIn();
|
||||
light.ScaleTo(Vector2.One);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(ManiaAction action)
|
||||
{
|
||||
// Todo: Should be 400 * 100 / CurrentBPM
|
||||
const double animation_length = 250;
|
||||
|
||||
if (action == Column.Action.Value)
|
||||
{
|
||||
light.FadeTo(0, animation_length);
|
||||
light.ScaleTo(new Vector2(1, 0), animation_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyHitExplosion : LegacyManiaColumnElement
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Drawable explosion;
|
||||
|
||||
public LegacyHitExplosion()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
string imageName = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.ExplosionImage)?.Value
|
||||
?? "lightingN";
|
||||
|
||||
float explosionScale = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.ExplosionScale)?.Value
|
||||
?? 1;
|
||||
|
||||
// Create a temporary animation to retrieve the number of frames, in an effort to calculate the intended frame length.
|
||||
// This animation is discarded and re-queried with the appropriate frame length afterwards.
|
||||
var tmp = skin.GetAnimation(imageName, true, false);
|
||||
double frameLength = 0;
|
||||
if (tmp is IFramedAnimation tmpAnimation && tmpAnimation.FrameCount > 0)
|
||||
frameLength = Math.Max(1000 / 60.0, 170.0 / tmpAnimation.FrameCount);
|
||||
|
||||
explosion = skin.GetAnimation(imageName, true, false, frameLength: frameLength).With(d =>
|
||||
{
|
||||
if (d == null)
|
||||
return;
|
||||
|
||||
d.Origin = Anchor.Centre;
|
||||
d.Blending = BlendingParameters.Additive;
|
||||
d.Scale = new Vector2(explosionScale);
|
||||
});
|
||||
|
||||
if (explosion != null)
|
||||
InternalChild = explosion;
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (explosion != null)
|
||||
explosion.Anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
explosion?.FadeInFromZero(80)
|
||||
.Then().FadeOut(120);
|
||||
}
|
||||
}
|
||||
}
|
83
osu.Game.Rulesets.Mania/Skinning/LegacyHitTarget.cs
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyHitTarget : LegacyManiaElement
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container directionContainer;
|
||||
|
||||
public LegacyHitTarget()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
string targetImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.HitTargetImage)?.Value
|
||||
?? "mania-stage-hint";
|
||||
|
||||
bool showJudgementLine = GetManiaSkinConfig<bool>(skin, LegacyManiaSkinConfigurationLookups.ShowJudgementLine)?.Value
|
||||
?? true;
|
||||
|
||||
Color4 lineColour = GetManiaSkinConfig<Color4>(skin, LegacyManiaSkinConfigurationLookups.JudgementLineColour)?.Value
|
||||
?? Color4.White;
|
||||
|
||||
InternalChild = directionContainer = new Container
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Sprite
|
||||
{
|
||||
Texture = skin.GetTexture(targetImage),
|
||||
Scale = new Vector2(1, 0.9f * 1.6025f),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 1
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1,
|
||||
Colour = lineColour,
|
||||
Alpha = showJudgementLine ? 0.9f : 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
directionContainer.Anchor = Anchor.TopLeft;
|
||||
directionContainer.Scale = new Vector2(1, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
directionContainer.Anchor = Anchor.BottomLeft;
|
||||
directionContainer.Scale = Vector2.One;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteHeadPiece.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
||||
{
|
||||
protected override Texture GetTexture(ISkinSource skin)
|
||||
{
|
||||
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||
}
|
||||
}
|
||||
}
|
29
osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteTailPiece.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyHoldNoteTailPiece : LegacyNotePiece
|
||||
{
|
||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
// Invert the direction
|
||||
base.OnDirectionChanged(direction.NewValue == ScrollingDirection.Up
|
||||
? new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Down, ScrollingDirection.Down)
|
||||
: new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Up, ScrollingDirection.Up));
|
||||
}
|
||||
|
||||
protected override Texture GetTexture(ISkinSource skin)
|
||||
{
|
||||
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage)
|
||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||
}
|
||||
}
|
||||
}
|
106
osu.Game.Rulesets.Mania/Skinning/LegacyKeyArea.cs
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container directionContainer;
|
||||
private Sprite upSprite;
|
||||
private Sprite downSprite;
|
||||
|
||||
[Resolved]
|
||||
private Column column { get; set; }
|
||||
|
||||
public LegacyKeyArea()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
string upImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.KeyImage)?.Value
|
||||
?? $"mania-key{FallbackColumnIndex}";
|
||||
|
||||
string downImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.KeyImageDown)?.Value
|
||||
?? $"mania-key{FallbackColumnIndex}D";
|
||||
|
||||
InternalChild = directionContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
upSprite = new Sprite
|
||||
{
|
||||
Origin = Anchor.BottomCentre,
|
||||
Texture = skin.GetTexture(upImage),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 1
|
||||
},
|
||||
downSprite = new Sprite
|
||||
{
|
||||
Origin = Anchor.BottomCentre,
|
||||
Texture = skin.GetTexture(downImage),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 1,
|
||||
Alpha = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
directionContainer.Anchor = directionContainer.Origin = Anchor.TopCentre;
|
||||
upSprite.Anchor = downSprite.Anchor = Anchor.TopCentre;
|
||||
upSprite.Scale = downSprite.Scale = new Vector2(1, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
directionContainer.Anchor = directionContainer.Origin = Anchor.BottomCentre;
|
||||
upSprite.Anchor = downSprite.Anchor = Anchor.BottomCentre;
|
||||
upSprite.Scale = downSprite.Scale = Vector2.One;
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
{
|
||||
upSprite.FadeTo(0);
|
||||
downSprite.FadeTo(1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(ManiaAction action)
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
{
|
||||
upSprite.FadeTo(1);
|
||||
downSprite.FadeTo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
osu.Game.Rulesets.Mania/Skinning/LegacyManiaColumnElement.cs
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="CompositeDrawable"/> which is placed somewhere within a <see cref="Column"/>.
|
||||
/// </summary>
|
||||
public class LegacyManiaColumnElement : LegacyManiaElement
|
||||
{
|
||||
[Resolved]
|
||||
protected Column Column { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The column type identifier to use for texture lookups, in the case of no user-provided configuration.
|
||||
/// </summary>
|
||||
protected string FallbackColumnIndex { get; private set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
switch (Column.ColumnType)
|
||||
{
|
||||
case ColumnType.Special:
|
||||
FallbackColumnIndex = "S";
|
||||
break;
|
||||
|
||||
case ColumnType.Odd:
|
||||
FallbackColumnIndex = "1";
|
||||
break;
|
||||
|
||||
case ColumnType.Even:
|
||||
FallbackColumnIndex = "2";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override IBindable<T> GetManiaSkinConfig<T>(ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? index = null)
|
||||
=> base.GetManiaSkinConfig<T>(skin, lookup, index ?? Column.Index);
|
||||
}
|
||||
}
|
25
osu.Game.Rulesets.Mania/Skinning/LegacyManiaElement.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A mania legacy skin element.
|
||||
/// </summary>
|
||||
public class LegacyManiaElement : CompositeDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve a per-column-count skin configuration.
|
||||
/// </summary>
|
||||
/// <param name="skin">The skin from which configuration is retrieved.</param>
|
||||
/// <param name="lookup">The value to retrieve.</param>
|
||||
/// <param name="index">If not null, denotes the index of the column to which the entry applies.</param>
|
||||
protected virtual IBindable<T> GetManiaSkinConfig<T>(ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? index = null)
|
||||
=> skin.GetConfig<ManiaSkinConfigurationLookup, T>(
|
||||
new ManiaSkinConfigurationLookup(lookup, index));
|
||||
}
|
||||
}
|
98
osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyNotePiece : LegacyManiaColumnElement
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container directionContainer;
|
||||
private Sprite noteSprite;
|
||||
|
||||
private float? minimumColumnWidth;
|
||||
|
||||
public LegacyNotePiece()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
minimumColumnWidth = skin.GetConfig<ManiaSkinConfigurationLookup, float>(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth))?.Value;
|
||||
|
||||
InternalChild = directionContainer = new Container
|
||||
{
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = noteSprite = new Sprite { Texture = GetTexture(skin) }
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(OnDirectionChanged, true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (noteSprite.Texture != null)
|
||||
{
|
||||
// The height is scaled to the minimum column width, if provided.
|
||||
float minimumWidth = minimumColumnWidth ?? DrawWidth;
|
||||
|
||||
noteSprite.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), noteSprite.Texture.DisplayWidth);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
directionContainer.Anchor = Anchor.TopCentre;
|
||||
directionContainer.Scale = new Vector2(1, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
directionContainer.Anchor = Anchor.BottomCentre;
|
||||
directionContainer.Scale = Vector2.One;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Texture GetTexture(ISkinSource skin) => GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||
|
||||
protected Texture GetTextureFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup)
|
||||
{
|
||||
string suffix = string.Empty;
|
||||
|
||||
switch (lookup)
|
||||
{
|
||||
case LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage:
|
||||
suffix = "H";
|
||||
break;
|
||||
|
||||
case LegacyManiaSkinConfigurationLookups.HoldNoteTailImage:
|
||||
suffix = "T";
|
||||
break;
|
||||
}
|
||||
|
||||
string noteImage = GetManiaSkinConfig<string>(skin, lookup)?.Value
|
||||
?? $"mania-note{FallbackColumnIndex}{suffix}";
|
||||
|
||||
return skin.GetTexture(noteImage);
|
||||
}
|
||||
}
|
||||
}
|
61
osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs
Normal file
@ -0,0 +1,61 @@
|
||||
// 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.Sprites;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyStageBackground : LegacyManiaElement
|
||||
{
|
||||
private Drawable leftSprite;
|
||||
private Drawable rightSprite;
|
||||
|
||||
public LegacyStageBackground()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
string leftImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.LeftStageImage)?.Value
|
||||
?? "mania-stage-left";
|
||||
|
||||
string rightImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.RightStageImage)?.Value
|
||||
?? "mania-stage-right";
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
leftSprite = new Sprite
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopRight,
|
||||
X = 0.05f,
|
||||
Texture = skin.GetTexture(leftImage),
|
||||
},
|
||||
rightSprite = new Sprite
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopLeft,
|
||||
X = -0.05f,
|
||||
Texture = skin.GetTexture(rightImage)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (leftSprite?.Height > 0)
|
||||
leftSprite.Scale = new Vector2(DrawHeight / leftSprite.Height);
|
||||
|
||||
if (rightSprite?.Height > 0)
|
||||
rightSprite.Scale = new Vector2(DrawHeight / rightSprite.Height);
|
||||
}
|
||||
}
|
||||
}
|
56
osu.Game.Rulesets.Mania/Skinning/LegacyStageForeground.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// 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.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyStageForeground : LegacyManiaElement
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Drawable sprite;
|
||||
|
||||
public LegacyStageForeground()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
string bottomImage = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.BottomStageImage)?.Value
|
||||
?? "mania-stage-bottom";
|
||||
|
||||
sprite = skin.GetAnimation(bottomImage, true, true)?.With(d =>
|
||||
{
|
||||
if (d == null)
|
||||
return;
|
||||
|
||||
d.Scale = new Vector2(1.6f);
|
||||
});
|
||||
|
||||
if (sprite != null)
|
||||
InternalChild = sprite;
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (sprite == null)
|
||||
return;
|
||||
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
sprite.Anchor = sprite.Origin = Anchor.TopCentre;
|
||||
else
|
||||
sprite.Anchor = sprite.Origin = Anchor.BottomCentre;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
@ -14,10 +17,32 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
||||
public class ManiaLegacySkinTransformer : ISkin
|
||||
{
|
||||
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.beatmap = (ManiaBeatmap)beatmap;
|
||||
|
||||
source.SourceChanged += sourceChanged;
|
||||
sourceChanged();
|
||||
}
|
||||
|
||||
private void sourceChanged()
|
||||
{
|
||||
isLegacySkin = new Lazy<bool>(() => source.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version) != null);
|
||||
hasKeyTexture = new Lazy<bool>(() => source.GetAnimation(
|
||||
GetConfig<ManiaSkinConfigurationLookup, string>(
|
||||
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.KeyImage, 0))?.Value
|
||||
?? "mania-key1", true, true) != null);
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component)
|
||||
@ -26,6 +51,45 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
case GameplaySkinComponent<HitResult> 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();
|
||||
|
||||
case ManiaSkinComponents.StageBackground:
|
||||
return new LegacyStageBackground();
|
||||
|
||||
case ManiaSkinComponents.StageForeground:
|
||||
return new LegacyStageForeground();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -61,7 +125,12 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) =>
|
||||
source.GetConfig<TLookup, TValue>(lookup);
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup 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.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.UI.Components;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
[Cached]
|
||||
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||
{
|
||||
public const float COLUMN_WIDTH = 80;
|
||||
private const float special_column_width = 70;
|
||||
public const float SPECIAL_COLUMN_WIDTH = 70;
|
||||
|
||||
/// <summary>
|
||||
/// The index of this column as part of the whole playfield.
|
||||
@ -31,12 +33,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||
|
||||
private readonly ColumnBackground background;
|
||||
private readonly ColumnKeyArea keyArea;
|
||||
private readonly ColumnHitObjectArea hitObjectArea;
|
||||
|
||||
internal readonly Container TopLevelContainer;
|
||||
private readonly Container explosionContainer;
|
||||
|
||||
public Column(int index)
|
||||
{
|
||||
@ -45,95 +44,34 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = COLUMN_WIDTH;
|
||||
|
||||
background = new ColumnBackground { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
Container hitTargetContainer;
|
||||
Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, Index), _ => new DefaultColumnBackground())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
||||
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,
|
||||
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,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
background,
|
||||
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
};
|
||||
|
||||
TopLevelContainer.Add(explosionContainer.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);
|
||||
TopLevelContainer.Add(hitObjectArea.Explosions.CreateProxy());
|
||||
}
|
||||
|
||||
public override Axes RelativeSizeAxes => Axes.Y;
|
||||
|
||||
private bool isSpecial;
|
||||
public ColumnType ColumnType { get; set; }
|
||||
|
||||
public bool IsSpecial
|
||||
{
|
||||
get => isSpecial;
|
||||
set
|
||||
{
|
||||
if (isSpecial == value)
|
||||
return;
|
||||
public bool IsSpecial => ColumnType == ColumnType.Special;
|
||||
|
||||
isSpecial = value;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
public Color4 AccentColour { get; set; }
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
@ -168,11 +106,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
|
||||
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,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
|
||||
hitObjectArea.Explosions.Add(explosion);
|
||||
|
||||
explosion.Delay(200).Expire(true);
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
@ -197,6 +139,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
|
||||
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
|
||||
=> DrawRectangle.Inflate(new Vector2(ManiaStage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
|
||||
=> DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
|
||||
}
|
||||
}
|
||||
|
@ -1,145 +1,45 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// 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.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
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;
|
||||
|
||||
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,
|
||||
Depth = 1
|
||||
},
|
||||
hitObjectContainer
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(dir =>
|
||||
{
|
||||
Anchor anchor = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
|
||||
|
||||
hitTarget.Anchor = hitTarget.Origin = anchor;
|
||||
}, true);
|
||||
}
|
||||
|
||||
private Color4 accentColour;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
|
||||
accentColour = value;
|
||||
|
||||
if (hitTarget is IHasAccentColour colouredHitTarget)
|
||||
colouredHitTarget.AccentColour = accentColour;
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultHitTarget : CompositeDrawable, IHasAccentColour
|
||||
{
|
||||
private const float hit_target_bar_height = 2;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private readonly Container hitTargetLine;
|
||||
private readonly Drawable hitTargetBar;
|
||||
|
||||
public DefaultHitTarget()
|
||||
{
|
||||
InternalChildren = new[]
|
||||
Explosions = new Container
|
||||
{
|
||||
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();
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = -1,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateColours()
|
||||
{
|
||||
if (!IsLoaded)
|
||||
return;
|
||||
protected override void UpdateHitPosition()
|
||||
{
|
||||
base.UpdateHitPosition();
|
||||
|
||||
hitTargetLine.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
Colour = accentColour.Opacity(0.5f),
|
||||
};
|
||||
}
|
||||
if (Direction.Value == ScrollingDirection.Up)
|
||||
hitTarget.Anchor = hitTarget.Origin = Anchor.TopLeft;
|
||||
else
|
||||
hitTarget.Anchor = hitTarget.Origin = Anchor.BottomLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,124 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class ColumnKeyArea : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||
{
|
||||
private const float key_icon_size = 10;
|
||||
private const float key_icon_corner_radius = 3;
|
||||
|
||||
private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container keyIcon;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
this.action.BindTo(action);
|
||||
|
||||
Drawable gradient;
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
gradient = new Box
|
||||
{
|
||||
Name = "Key gradient",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
},
|
||||
keyIcon = new Container
|
||||
{
|
||||
Name = "Key icon",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(key_icon_size),
|
||||
Masking = true,
|
||||
CornerRadius = key_icon_corner_radius,
|
||||
BorderThickness = 2,
|
||||
BorderColour = Color4.White, // Not true
|
||||
Children = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(dir =>
|
||||
{
|
||||
gradient.Colour = ColourInfo.GradientVertical(
|
||||
dir.NewValue == ScrollingDirection.Up ? Color4.Black : Color4.Black.Opacity(0),
|
||||
dir.NewValue == ScrollingDirection.Up ? Color4.Black.Opacity(0) : Color4.Black);
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
updateColours();
|
||||
}
|
||||
|
||||
private Color4 accentColour;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
|
||||
accentColour = value;
|
||||
|
||||
updateColours();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateColours()
|
||||
{
|
||||
if (!IsLoaded)
|
||||
return;
|
||||
|
||||
keyIcon.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
Colour = accentColour.Opacity(0.5f),
|
||||
};
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == this.action.Value)
|
||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(ManiaAction action)
|
||||
{
|
||||
if (action == this.action.Value)
|
||||
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class DefaultColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Color4 brightColour;
|
||||
private Color4 dimColour;
|
||||
|
||||
private Box background;
|
||||
private Box backgroundOverlay;
|
||||
|
||||
[Resolved]
|
||||
private Column column { get; set; }
|
||||
|
||||
public DefaultColumnBackground()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
InternalChildren = new[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
Name = "Background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
backgroundOverlay = new Box
|
||||
{
|
||||
Name = "Background Gradient Overlay",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.5f,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Alpha = 0
|
||||
}
|
||||
};
|
||||
|
||||
background.Colour = column.AccentColour.Darken(5);
|
||||
brightColour = column.AccentColour.Opacity(0.6f);
|
||||
dimColour = column.AccentColour.Opacity(0);
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
backgroundOverlay.Anchor = backgroundOverlay.Origin = Anchor.TopLeft;
|
||||
backgroundOverlay.Colour = ColourInfo.GradientVertical(brightColour, dimColour);
|
||||
}
|
||||
else
|
||||
{
|
||||
backgroundOverlay.Anchor = backgroundOverlay.Origin = Anchor.BottomLeft;
|
||||
backgroundOverlay.Colour = ColourInfo.GradientVertical(dimColour, brightColour);
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(ManiaAction action)
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
80
osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class DefaultHitTarget : CompositeDrawable
|
||||
{
|
||||
private const float hit_target_bar_height = 2;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container hitTargetLine;
|
||||
private Drawable hitTargetBar;
|
||||
|
||||
[Resolved]
|
||||
private Column column { get; set; }
|
||||
|
||||
public DefaultHitTarget()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
InternalChildren = new[]
|
||||
{
|
||||
hitTargetBar = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = DefaultNotePiece.NOTE_HEIGHT,
|
||||
Alpha = 0.6f,
|
||||
Colour = Color4.Black
|
||||
},
|
||||
hitTargetLine = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = hit_target_bar_height,
|
||||
Masking = true,
|
||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
};
|
||||
|
||||
hitTargetLine.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
Colour = column.AccentColour.Opacity(0.5f),
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
hitTargetBar.Anchor = hitTargetBar.Origin = Anchor.TopLeft;
|
||||
hitTargetLine.Anchor = hitTargetLine.Origin = Anchor.TopLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
hitTargetBar.Anchor = hitTargetBar.Origin = Anchor.BottomLeft;
|
||||
hitTargetLine.Anchor = hitTargetLine.Origin = Anchor.BottomLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class DefaultKeyArea : CompositeDrawable, IKeyBindingHandler<ManiaAction>
|
||||
{
|
||||
private const float key_icon_size = 10;
|
||||
private const float key_icon_corner_radius = 3;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container directionContainer;
|
||||
private Container keyIcon;
|
||||
private Drawable gradient;
|
||||
|
||||
[Resolved]
|
||||
private Column column { get; set; }
|
||||
|
||||
public DefaultKeyArea()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
InternalChild = directionContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = Stage.HIT_TARGET_POSITION,
|
||||
Children = new[]
|
||||
{
|
||||
gradient = new Box
|
||||
{
|
||||
Name = "Key gradient",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
},
|
||||
keyIcon = new Container
|
||||
{
|
||||
Name = "Key icon",
|
||||
Size = new Vector2(key_icon_size),
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
CornerRadius = key_icon_corner_radius,
|
||||
BorderThickness = 2,
|
||||
BorderColour = Color4.White, // Not true
|
||||
Children = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keyIcon.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
Colour = column.AccentColour.Opacity(0.5f),
|
||||
};
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
keyIcon.Anchor = Anchor.BottomCentre;
|
||||
keyIcon.Y = -20;
|
||||
directionContainer.Anchor = directionContainer.Origin = Anchor.TopLeft;
|
||||
gradient.Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
keyIcon.Anchor = Anchor.TopCentre;
|
||||
keyIcon.Y = 20;
|
||||
directionContainer.Anchor = directionContainer.Origin = Anchor.BottomLeft;
|
||||
gradient.Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Black);
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(ManiaAction action)
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// 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.Framework.Graphics.Shapes;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class DefaultStageBackground : CompositeDrawable
|
||||
{
|
||||
public DefaultStageBackground()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = new Box
|
||||
{
|
||||
Name = "Background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
55
osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Skinning;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class HitObjectArea : SkinReloadableDrawable
|
||||
{
|
||||
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
public HitObjectArea(HitObjectContainer hitObjectContainer)
|
||||
{
|
||||
InternalChildren = new[]
|
||||
{
|
||||
hitObjectContainer,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
Direction.BindTo(scrollingInfo.Direction);
|
||||
Direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
UpdateHitPosition();
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
UpdateHitPosition();
|
||||
}
|
||||
|
||||
protected virtual void UpdateHitPosition()
|
||||
{
|
||||
float hitPosition = CurrentSkin.GetConfig<ManiaSkinConfigurationLookup, float>(
|
||||
new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition))?.Value
|
||||
?? Stage.HIT_TARGET_POSITION;
|
||||
|
||||
Padding = Direction.Value == ScrollingDirection.Up
|
||||
? new MarginPadding { Top = hitPosition }
|
||||
: new MarginPadding { Bottom = hitPosition };
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +1,35 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// 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.Utils;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
internal class HitExplosion : CompositeDrawable
|
||||
public class DefaultHitExplosion : CompositeDrawable
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => true;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private readonly CircularContainer largeFaint;
|
||||
private readonly CircularContainer mainGlow1;
|
||||
|
||||
public HitExplosion(Color4 objectColour, bool isSmall = false)
|
||||
public DefaultHitExplosion(Color4 objectColour, bool isSmall = false)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = NotePiece.NOTE_HEIGHT;
|
||||
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||
|
||||
// scale roughly in-line with visual appearance of notes
|
||||
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()
|
||||
{
|
||||
const double duration = 200;
|
||||
@ -122,7 +136,20 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint);
|
||||
|
||||
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.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
@ -25,6 +27,16 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
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;
|
||||
|
||||
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
|
||||
@ -46,6 +58,19 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
bool isForCurrentRuleset = Beatmap.BeatmapInfo.Ruleset.Equals(Ruleset.RulesetInfo);
|
||||
|
||||
foreach (var p in ControlPoints)
|
||||
{
|
||||
// Mania doesn't care about global velocity
|
||||
p.Velocity = 1;
|
||||
p.BaseBeatLength *= Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier;
|
||||
|
||||
// For non-mania beatmap, speed changes should only happen through timing points
|
||||
if (!isForCurrentRuleset)
|
||||
p.DifficultyPoint = new DifficultyControlPoint();
|
||||
}
|
||||
|
||||
BarLines.ForEach(Playfield.Add);
|
||||
|
||||
Config.BindWith(ManiaRulesetSetting.ScrollDirection, configDirection);
|
||||
@ -54,6 +79,17 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
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>
|
||||
/// Retrieves the column that intersects a screen-space position.
|
||||
/// </summary>
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaPlayfield : ScrollingPlayfield
|
||||
{
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
private readonly List<Stage> stages = new List<Stage>();
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => stages.Any(s => s.ReceivePositionalInputAt(screenSpacePos));
|
||||
|
||||
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||
{
|
||||
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
var newStage = new Stage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||
|
||||
playfieldGrid.Content[0][i] = newStage;
|
||||
|
||||
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
/// </summary>
|
||||
public int TotalColumns => stages.Sum(s => s.Columns.Count);
|
||||
|
||||
private ManiaStage getStageByColumn(int column)
|
||||
private Stage getStageByColumn(int column)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -13,8 +12,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2(1, 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
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.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -23,30 +24,33 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
/// <summary>
|
||||
/// A collection of <see cref="Column"/>s.
|
||||
/// </summary>
|
||||
public class ManiaStage : ScrollingPlayfield
|
||||
public class Stage : ScrollingPlayfield
|
||||
{
|
||||
public const float COLUMN_SPACING = 1;
|
||||
|
||||
public const float HIT_TARGET_POSITION = 50;
|
||||
public const float HIT_TARGET_POSITION = 110;
|
||||
|
||||
public IReadOnlyList<Column> Columns => columnFlow.Children;
|
||||
private readonly FillFlowContainer<Column> columnFlow;
|
||||
|
||||
private readonly Container barLineContainer;
|
||||
|
||||
public Container<DrawableManiaJudgement> Judgements => judgements;
|
||||
private readonly JudgementContainer<DrawableManiaJudgement> judgements;
|
||||
|
||||
private readonly Drawable barLineContainer;
|
||||
private readonly Container topLevelContainer;
|
||||
|
||||
private List<Color4> normalColumnColours = new List<Color4>();
|
||||
private Color4 specialColumnColour;
|
||||
private readonly Dictionary<ColumnType, Color4> columnColours = new Dictionary<ColumnType, Color4>
|
||||
{
|
||||
{ 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));
|
||||
|
||||
private readonly int firstColumnIndex;
|
||||
|
||||
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||
public Stage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||
{
|
||||
this.firstColumnIndex = firstColumnIndex;
|
||||
|
||||
@ -67,31 +71,17 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground())
|
||||
{
|
||||
Name = "Columns mask",
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
columnFlow = new FillFlowContainer<Column>
|
||||
{
|
||||
Name = "Columns",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Name = "Background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black
|
||||
},
|
||||
columnFlow = new FillFlowContainer<Column>
|
||||
{
|
||||
Name = "Columns",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
|
||||
Spacing = new Vector2(COLUMN_SPACING, 0)
|
||||
},
|
||||
}
|
||||
Direction = FillDirection.Horizontal,
|
||||
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -102,15 +92,18 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
Width = 1366, // Bar lines should only be masked on the vertical axis
|
||||
BypassAutoSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Child = barLineContainer = new Container
|
||||
Child = barLineContainer = new HitObjectArea(HitObjectContainer)
|
||||
{
|
||||
Name = "Bar lines",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Child = HitObjectContainer
|
||||
}
|
||||
},
|
||||
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
judgements = new JudgementContainer<DrawableManiaJudgement>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
@ -125,24 +118,52 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
for (int i = 0; i < definition.Columns; i++)
|
||||
{
|
||||
var isSpecial = definition.IsSpecialColumn(i);
|
||||
var columnType = definition.GetTypeOfColumn(i);
|
||||
var column = new Column(firstColumnIndex + i)
|
||||
{
|
||||
IsSpecial = isSpecial,
|
||||
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
|
||||
ColumnType = columnType,
|
||||
AccentColour = columnColours[columnType],
|
||||
Action = { Value = columnType == ColumnType.Special ? specialColumnStartAction++ : normalColumnStartAction++ }
|
||||
};
|
||||
|
||||
AddColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
Direction.BindValueChanged(dir =>
|
||||
private ISkin currentSkin;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
currentSkin = skin;
|
||||
skin.SourceChanged += onSkinChanged;
|
||||
|
||||
onSkinChanged();
|
||||
}
|
||||
|
||||
private void onSkinChanged()
|
||||
{
|
||||
foreach (var col in columnFlow)
|
||||
{
|
||||
barLineContainer.Padding = new MarginPadding
|
||||
if (col.Index > 0)
|
||||
{
|
||||
Top = dir.NewValue == ScrollingDirection.Up ? HIT_TARGET_POSITION : 0,
|
||||
Bottom = dir.NewValue == ScrollingDirection.Down ? HIT_TARGET_POSITION : 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)
|
||||
@ -195,38 +216,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()
|
||||
{
|
||||
// Due to masking differences, it is not possible to get the width of the columns container automatically
|
21
osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public abstract class OsuSkinnableTestScene : SkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(OsuRuleset),
|
||||
typeof(OsuLegacySkinTransformer),
|
||||
};
|
||||
|
||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 49 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/special-skin/sliderb0.png
Normal file
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 23 KiB |
@ -10,17 +10,16 @@ using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneDrawableJudgement : SkinnableTestScene
|
||||
public class TestSceneDrawableJudgement : OsuSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||
{
|
||||
typeof(DrawableJudgement),
|
||||
typeof(DrawableOsuJudgement)
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
public TestSceneDrawableJudgement()
|
||||
{
|
||||
|
@ -3,26 +3,32 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing.Input;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneGameplayCursor : SkinnableTestScene
|
||||
public class TestSceneGameplayCursor : OsuSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
|
||||
{
|
||||
typeof(GameplayCursorContainer),
|
||||
typeof(OsuCursorContainer),
|
||||
typeof(OsuCursor),
|
||||
typeof(LegacyCursor),
|
||||
typeof(LegacyCursorTrail),
|
||||
typeof(CursorTrail)
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
[Cached]
|
||||
private GameplayBeatmap gameplayBeatmap;
|
||||
|
@ -14,12 +14,11 @@ using osu.Game.Rulesets.Mods;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneHitCircle : SkinnableTestScene
|
||||
public class TestSceneHitCircle : OsuSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
@ -22,12 +22,11 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneSlider : SkinnableTestScene
|
||||
public class TestSceneSlider : OsuSkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
|
253
osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs
Normal file
@ -0,0 +1,253 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Humanizer;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Storyboards;
|
||||
using osuTK;
|
||||
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneSliderSnaking : TestSceneOsuPlayer
|
||||
{
|
||||
[Resolved]
|
||||
private AudioManager audioManager { get; set; }
|
||||
|
||||
private TrackVirtualManual track;
|
||||
|
||||
protected override bool Autoplay => autoplay;
|
||||
private bool autoplay;
|
||||
|
||||
private readonly BindableBool snakingIn = new BindableBool();
|
||||
private readonly BindableBool snakingOut = new BindableBool();
|
||||
|
||||
private const double duration_of_span = 3605;
|
||||
private const double fade_in_modifier = -1200;
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
{
|
||||
var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
|
||||
track = (TrackVirtualManual)working.Track;
|
||||
return working;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetConfigCache configCache)
|
||||
{
|
||||
var config = (OsuRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
||||
config.BindWith(OsuRulesetSetting.SnakingInSliders, snakingIn);
|
||||
config.BindWith(OsuRulesetSetting.SnakingOutSliders, snakingOut);
|
||||
}
|
||||
|
||||
private DrawableSlider slider;
|
||||
|
||||
[SetUpSteps]
|
||||
public override void SetUpSteps() { }
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void TestSnakingEnabled(int sliderIndex)
|
||||
{
|
||||
AddStep("enable autoplay", () => autoplay = true);
|
||||
base.SetUpSteps();
|
||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||
|
||||
double startTime = hitObjects[sliderIndex].StartTime;
|
||||
retrieveDrawableSlider(sliderIndex);
|
||||
setSnaking(true);
|
||||
|
||||
ensureSnakingIn(startTime + fade_in_modifier);
|
||||
|
||||
for (int i = 0; i < sliderIndex; i++)
|
||||
{
|
||||
// non-final repeats should not snake out
|
||||
ensureNoSnakingOut(startTime, i);
|
||||
}
|
||||
|
||||
// final repeat should snake out
|
||||
ensureSnakingOut(startTime, sliderIndex);
|
||||
}
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
public void TestSnakingDisabled(int sliderIndex)
|
||||
{
|
||||
AddStep("have autoplay", () => autoplay = true);
|
||||
base.SetUpSteps();
|
||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||
|
||||
double startTime = hitObjects[sliderIndex].StartTime;
|
||||
retrieveDrawableSlider(sliderIndex);
|
||||
setSnaking(false);
|
||||
|
||||
ensureNoSnakingIn(startTime + fade_in_modifier);
|
||||
|
||||
for (int i = 0; i <= sliderIndex; i++)
|
||||
{
|
||||
// no snaking out ever, including final repeat
|
||||
ensureNoSnakingOut(startTime, i);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRepeatArrowDoesNotMoveWhenHit()
|
||||
{
|
||||
AddStep("enable autoplay", () => autoplay = true);
|
||||
setSnaking(true);
|
||||
base.SetUpSteps();
|
||||
|
||||
// repeat might have a chance to update its position depending on where in the frame its hit,
|
||||
// so some leniency is allowed here instead of checking strict equality
|
||||
checkPositionChange(16600, sliderRepeat, positionAlmostSame);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRepeatArrowMovesWhenNotHit()
|
||||
{
|
||||
AddStep("disable autoplay", () => autoplay = false);
|
||||
setSnaking(true);
|
||||
base.SetUpSteps();
|
||||
|
||||
checkPositionChange(16600, sliderRepeat, positionDecreased);
|
||||
}
|
||||
|
||||
private void retrieveDrawableSlider(int index) => AddStep($"retrieve {(index + 1).ToOrdinalWords()} slider", () =>
|
||||
{
|
||||
slider = (DrawableSlider)Player.DrawableRuleset.Playfield.AllHitObjects.ElementAt(index);
|
||||
});
|
||||
|
||||
private void ensureSnakingIn(double startTime) => checkPositionChange(startTime, sliderEnd, positionIncreased);
|
||||
private void ensureNoSnakingIn(double startTime) => checkPositionChange(startTime, sliderEnd, positionRemainsSame);
|
||||
|
||||
private void ensureSnakingOut(double startTime, int repeatIndex)
|
||||
{
|
||||
var repeatTime = timeAtRepeat(startTime, repeatIndex);
|
||||
|
||||
if (repeatIndex % 2 == 0)
|
||||
checkPositionChange(repeatTime, sliderStart, positionIncreased);
|
||||
else
|
||||
checkPositionChange(repeatTime, sliderEnd, positionDecreased);
|
||||
}
|
||||
|
||||
private void ensureNoSnakingOut(double startTime, int repeatIndex) =>
|
||||
checkPositionChange(timeAtRepeat(startTime, repeatIndex), positionAtRepeat(repeatIndex), positionRemainsSame);
|
||||
|
||||
private double timeAtRepeat(double startTime, int repeatIndex) => startTime + 100 + duration_of_span * repeatIndex;
|
||||
private Func<Vector2> positionAtRepeat(int repeatIndex) => repeatIndex % 2 == 0 ? (Func<Vector2>)sliderStart : sliderEnd;
|
||||
|
||||
private List<Vector2> sliderCurve => ((PlaySliderBody)slider.Body.Drawable).CurrentCurve;
|
||||
private Vector2 sliderStart() => sliderCurve.First();
|
||||
private Vector2 sliderEnd() => sliderCurve.Last();
|
||||
|
||||
private Vector2 sliderRepeat()
|
||||
{
|
||||
var drawable = Player.DrawableRuleset.Playfield.AllHitObjects.ElementAt(1);
|
||||
var repeat = drawable.ChildrenOfType<Container<DrawableSliderRepeat>>().First().Children.First();
|
||||
return repeat.Position;
|
||||
}
|
||||
|
||||
private bool positionRemainsSame(Vector2 previous, Vector2 current) => previous == current;
|
||||
private bool positionIncreased(Vector2 previous, Vector2 current) => current.X > previous.X && current.Y > previous.Y;
|
||||
private bool positionDecreased(Vector2 previous, Vector2 current) => current.X < previous.X && current.Y < previous.Y;
|
||||
private bool positionAlmostSame(Vector2 previous, Vector2 current) => Precision.AlmostEquals(previous, current, 1);
|
||||
|
||||
private void checkPositionChange(double startTime, Func<Vector2> positionToCheck, Func<Vector2, Vector2, bool> positionAssertion)
|
||||
{
|
||||
Vector2 previousPosition = Vector2.Zero;
|
||||
|
||||
string positionDescription = positionToCheck.Method.Name.Humanize(LetterCasing.LowerCase);
|
||||
string assertionDescription = positionAssertion.Method.Name.Humanize(LetterCasing.LowerCase);
|
||||
|
||||
addSeekStep(startTime);
|
||||
AddStep($"save {positionDescription} position", () => previousPosition = positionToCheck.Invoke());
|
||||
addSeekStep(startTime + 100);
|
||||
AddAssert($"{positionDescription} {assertionDescription}", () =>
|
||||
{
|
||||
var currentPosition = positionToCheck.Invoke();
|
||||
return positionAssertion.Invoke(previousPosition, currentPosition);
|
||||
});
|
||||
}
|
||||
|
||||
private void setSnaking(bool value)
|
||||
{
|
||||
AddStep($"{(value ? "enable" : "disable")} snaking", () =>
|
||||
{
|
||||
snakingIn.Value = value;
|
||||
snakingOut.Value = value;
|
||||
});
|
||||
}
|
||||
|
||||
private void addSeekStep(double time)
|
||||
{
|
||||
AddStep($"seek to {time}", () => track.Seek(time));
|
||||
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
|
||||
{
|
||||
HitObjects = hitObjects
|
||||
};
|
||||
|
||||
private readonly List<HitObject> hitObjects = new List<HitObject>
|
||||
{
|
||||
new Slider
|
||||
{
|
||||
StartTime = 3000,
|
||||
Position = new Vector2(100, 100),
|
||||
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(300, 200)
|
||||
}),
|
||||
},
|
||||
new Slider
|
||||
{
|
||||
StartTime = 13000,
|
||||
Position = new Vector2(100, 100),
|
||||
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(300, 200)
|
||||
}),
|
||||
RepeatCount = 1,
|
||||
},
|
||||
new Slider
|
||||
{
|
||||
StartTime = 23000,
|
||||
Position = new Vector2(100, 100),
|
||||
Path = new SliderPath(PathType.PerfectCurve, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(300, 200)
|
||||
}),
|
||||
RepeatCount = 2,
|
||||
},
|
||||
new HitCircle
|
||||
{
|
||||
StartTime = 199999,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -34,6 +35,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPlacementHandler placementHandler { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private EditorBeatmap editorBeatmap { get; set; }
|
||||
|
||||
public SliderSelectionBlueprint(DrawableSlider slider)
|
||||
: base(slider)
|
||||
{
|
||||
@ -162,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
private void updatePath()
|
||||
{
|
||||
HitObject.Path.ExpectedDistance.Value = composer?.GetSnappedDistanceFromDistance(HitObject.StartTime, (float)HitObject.Path.CalculatedDistance) ?? (float)HitObject.Path.CalculatedDistance;
|
||||
UpdateHitObject();
|
||||
editorBeatmap?.UpdateHitObject(HitObject);
|
||||
}
|
||||
|
||||
public override MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
void handleHitCircle(DrawableHitCircle circle)
|
||||
{
|
||||
if (!circle.IsHovered)
|
||||
if (!circle.HitArea.IsHovered)
|
||||
return;
|
||||
|
||||
Debug.Assert(circle.HitObject.HitWindows != null);
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
/// <summary>
|
||||
/// A single follow point positioned between two adjacent <see cref="DrawableOsuHitObject"/>s.
|
||||
/// </summary>
|
||||
public class FollowPoint : Container
|
||||
public class FollowPoint : Container, IAnimationTimeReference
|
||||
{
|
||||
private const float width = 8;
|
||||
|
||||
@ -43,7 +43,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
Anchor = Anchor.Centre,
|
||||
Alpha = 0.5f,
|
||||
}
|
||||
}, confineMode: ConfineMode.NoScaling);
|
||||
});
|
||||
}
|
||||
|
||||
public double AnimationStartTime { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +116,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
int point = 0;
|
||||
|
||||
ClearInternal();
|
||||
|
||||
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
|
||||
{
|
||||
float fraction = (float)d / distance;
|
||||
@ -126,13 +128,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
|
||||
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.Rotation = rotation;
|
||||
@ -142,6 +138,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
if (firstTransformStartTime == null)
|
||||
firstTransformStartTime = fadeInTime;
|
||||
|
||||
fp.AnimationStartTime = fadeInTime;
|
||||
|
||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||
{
|
||||
fp.FadeIn(osuEnd.TimeFadeIn);
|
||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public readonly SkinnableDrawable CirclePiece;
|
||||
private readonly Container scaleContainer;
|
||||
|
||||
protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle;
|
||||
|
||||
public DrawableHitCircle(HitCircle h)
|
||||
: base(h)
|
||||
{
|
||||
@ -57,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
return true;
|
||||
},
|
||||
},
|
||||
CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece()),
|
||||
CirclePiece = new SkinnableDrawable(new OsuSkinComponent(CirclePieceComponent), _ => new MainCirclePiece()),
|
||||
ApproachCircle = new ApproachCircle
|
||||
{
|
||||
Alpha = 0,
|
||||
|
@ -186,7 +186,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
base.ApplySkin(skin, allowFallback);
|
||||
|
||||
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
||||
Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||
Ball.AccentColour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||
|
||||
protected override OsuSkinComponents CirclePieceComponent => OsuSkinComponents.SliderHeadHitCircle;
|
||||
|
||||
private readonly Slider slider;
|
||||
|
||||
public DrawableSliderHead(Slider slider, SliderHeadCircle h)
|
||||
|
@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
|
||||
Blending = BlendingParameters.Additive;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
InternalChild = scaleContainer = new ReverseArrowPiece();
|
||||
@ -87,6 +86,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||
{
|
||||
// When the repeat is hit, the arrow should fade out on spot rather than following the slider
|
||||
if (IsHit) return;
|
||||
|
||||
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
|
||||
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
|
||||
|
||||
|
@ -8,11 +8,16 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public class ReverseArrowPiece : BeatSyncedContainer
|
||||
{
|
||||
[Resolved]
|
||||
private DrawableHitObject drawableRepeat { get; set; }
|
||||
|
||||
public ReverseArrowPiece()
|
||||
{
|
||||
Divisor = 2;
|
||||
@ -21,13 +26,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Blending = BlendingParameters.Additive;
|
||||
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
|
||||
Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Icon = FontAwesome.Solid.ChevronRight,
|
||||
Size = new Vector2(0.35f)
|
||||
})
|
||||
@ -37,7 +41,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) =>
|
||||
Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out);
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||
{
|
||||
if (!drawableRepeat.IsHit)
|
||||
Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
this.drawableSlider = drawableSlider;
|
||||
this.slider = slider;
|
||||
|
||||
Blending = BlendingParameters.Additive;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
@ -241,6 +240,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
Scale = new Vector2(radius / OsuHitObject.OBJECT_RADIUS),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Blending = BlendingParameters.Additive,
|
||||
BorderThickness = 10,
|
||||
BorderColour = Color4.White,
|
||||
Alpha = 1,
|
||||
|
@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
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;
|
||||
|
||||
|
@ -13,6 +13,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
ApproachCircle,
|
||||
ReverseArrow,
|
||||
HitCircleText,
|
||||
SliderHeadHitCircle,
|
||||
SliderFollowCircle,
|
||||
SliderBall,
|
||||
SliderBody,
|
||||
|
@ -6,6 +6,7 @@ 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.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -18,8 +19,12 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -39,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
hitCircleSprite = new Sprite
|
||||
{
|
||||
Texture = skin.GetTexture("hitcircle"),
|
||||
Texture = getTextureWithFallback(string.Empty),
|
||||
Colour = drawableObject.AccentColour.Value,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -51,12 +56,17 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
}, confineMode: ConfineMode.NoScaling),
|
||||
new Sprite
|
||||
{
|
||||
Texture = skin.GetTexture("hitcircleoverlay"),
|
||||
Texture = getTextureWithFallback("overlay"),
|
||||
Anchor = 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.BindValueChanged(updateState, true);
|
||||
|
||||
@ -65,6 +75,16 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
|
||||
indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable);
|
||||
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)
|
||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
public LegacySliderBall(Drawable animationContent)
|
||||
{
|
||||
this.animationContent = animationContent;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|