mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 07:33:20 +08:00
Merge pull request #26254 from frenzibyte/mania-combo-counter
Add argon/classic osu!mania combo counter
This commit is contained in:
commit
5710f0f302
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
CreateTest();
|
CreateTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
AddAssert("legacy HUD combo counter not added", () => !Player.ChildrenOfType<LegacyComboCounter>().Any());
|
AddAssert("legacy HUD combo counter not added", () => !Player.ChildrenOfType<LegacyDefaultComboCounter>().Any());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -32,12 +31,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
switch (lookup)
|
switch (lookup)
|
||||||
{
|
{
|
||||||
case SkinComponentsContainerLookup containerLookup:
|
case SkinComponentsContainerLookup containerLookup:
|
||||||
if (containerLookup.Target != SkinComponentsContainerLookup.TargetArea.MainHUDComponents)
|
// Only handle per ruleset defaults here.
|
||||||
return base.GetDrawableComponent(lookup);
|
|
||||||
|
|
||||||
// Modifications for global components.
|
|
||||||
if (containerLookup.Ruleset == null)
|
if (containerLookup.Ruleset == null)
|
||||||
return base.GetDrawableComponent(lookup) as Container;
|
return base.GetDrawableComponent(lookup);
|
||||||
|
|
||||||
// Skin has configuration.
|
// Skin has configuration.
|
||||||
if (base.GetDrawableComponent(lookup) is UserConfiguredLayoutContainer d)
|
if (base.GetDrawableComponent(lookup) is UserConfiguredLayoutContainer d)
|
||||||
@ -48,6 +44,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Our own ruleset components default.
|
// Our own ruleset components default.
|
||||||
|
switch (containerLookup.Target)
|
||||||
|
{
|
||||||
|
case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
|
||||||
// todo: remove CatchSkinComponents.CatchComboCounter and refactor LegacyCatchComboCounter to be added here instead.
|
// todo: remove CatchSkinComponents.CatchComboCounter and refactor LegacyCatchComboCounter to be added here instead.
|
||||||
return new DefaultSkinComponentsContainer(container =>
|
return new DefaultSkinComponentsContainer(container =>
|
||||||
{
|
{
|
||||||
@ -69,6 +68,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
new LegacyKeyCounterDisplay(),
|
new LegacyKeyCounterDisplay(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case CatchSkinComponentLookup catchSkinComponent:
|
case CatchSkinComponentLookup catchSkinComponent:
|
||||||
switch (catchSkinComponent.Component)
|
switch (catchSkinComponent.Component)
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
// 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.Testing;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning.Argon;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning.Legacy;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public partial class TestSceneComboCounter : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor(new ManiaRuleset());
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("setup", () => SetContents(s =>
|
||||||
|
{
|
||||||
|
if (s is ArgonSkin)
|
||||||
|
return new ArgonManiaComboCounter();
|
||||||
|
|
||||||
|
if (s is LegacySkin)
|
||||||
|
return new LegacyManiaComboCounter();
|
||||||
|
|
||||||
|
return new LegacyManiaComboCounter();
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddRepeatStep("perform hit", () => scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Great }), 20);
|
||||||
|
AddStep("perform miss", () => scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Miss }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,15 +3,22 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
{
|
{
|
||||||
public partial class TestScenePlayfield : ManiaSkinnableTestScene
|
public partial class TestScenePlayfield : ManiaSkinnableTestScene
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
|
private ScoreProcessor scoreProcessor = new ScoreProcessor(new ManiaRuleset());
|
||||||
|
|
||||||
private List<StageDefinition> stageDefinitions = new List<StageDefinition>();
|
private List<StageDefinition> stageDefinitions = new List<StageDefinition>();
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -29,6 +36,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
Child = new ManiaPlayfield(stageDefinitions)
|
Child = new ManiaPlayfield(stageDefinitions)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddRepeatStep("perform hit", () => scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Perfect }), 20);
|
||||||
|
AddStep("perform miss", () => scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Miss }));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(2)]
|
[TestCase(2)]
|
||||||
@ -54,6 +64,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddRepeatStep("perform hit", () => scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Perfect }), 20);
|
||||||
|
AddStep("perform miss", () => scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Miss }));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IBeatmap CreateBeatmapForSkinProvider()
|
protected override IBeatmap CreateBeatmapForSkinProvider()
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
|
{
|
||||||
|
public partial class TestSceneManiaPlayerLegacySkin : LegacySkinPlayerTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
|
||||||
|
|
||||||
|
// play with a converted beatmap to allow dual stages mod to work.
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(new RulesetInfo());
|
||||||
|
|
||||||
|
protected override bool HasCustomSteps => true;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleStage()
|
||||||
|
{
|
||||||
|
AddStep("Load single stage", LoadPlayer);
|
||||||
|
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDualStage()
|
||||||
|
{
|
||||||
|
AddStep("Load dual stage", () => LoadPlayer(new Mod[] { new ManiaModDualStages() }));
|
||||||
|
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
||||||
|
{
|
||||||
|
public partial class ArgonManiaComboCounter : ArgonComboCounter
|
||||||
|
{
|
||||||
|
protected override bool DisplayXSymbol => false;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IScrollingInfo scrollingInfo { get; set; } = null!;
|
||||||
|
|
||||||
|
private IBindable<ScrollingDirection> direction = null!;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
// the logic of flipping the position of the combo counter w.r.t. the direction does not work with "Closest" anchor,
|
||||||
|
// because it always forces the anchor to be top or bottom based on scrolling direction.
|
||||||
|
UsesFixedAnchor = true;
|
||||||
|
|
||||||
|
direction = scrollingInfo.Direction.GetBoundCopy();
|
||||||
|
direction.BindValueChanged(_ => updateAnchor());
|
||||||
|
|
||||||
|
// two schedules are required so that updateAnchor is executed in the next frame,
|
||||||
|
// which is when the combo counter receives its Y position by the default layout in ArgonManiaSkinTransformer.
|
||||||
|
Schedule(() => Schedule(updateAnchor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAnchor()
|
||||||
|
{
|
||||||
|
// if the anchor isn't a vertical center, set top or bottom anchor based on scroll direction
|
||||||
|
if (!Anchor.HasFlag(Anchor.y1))
|
||||||
|
{
|
||||||
|
Anchor &= ~(Anchor.y0 | Anchor.y2);
|
||||||
|
Anchor |= direction.Value == ScrollingDirection.Up ? Anchor.y2 : Anchor.y0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// change the sign of the Y coordinate in line with the scrolling direction.
|
||||||
|
// i.e. if the user changes direction from down to up, the anchor is changed from top to bottom, and the Y is flipped from positive to negative here.
|
||||||
|
Y = Math.Abs(Y) * (direction.Value == ScrollingDirection.Up ? -1 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,10 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -26,6 +28,37 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
{
|
{
|
||||||
switch (lookup)
|
switch (lookup)
|
||||||
{
|
{
|
||||||
|
case SkinComponentsContainerLookup containerLookup:
|
||||||
|
// Only handle per ruleset defaults here.
|
||||||
|
if (containerLookup.Ruleset == null)
|
||||||
|
return base.GetDrawableComponent(lookup);
|
||||||
|
|
||||||
|
// Skin has configuration.
|
||||||
|
if (base.GetDrawableComponent(lookup) is UserConfiguredLayoutContainer d)
|
||||||
|
return d;
|
||||||
|
|
||||||
|
switch (containerLookup.Target)
|
||||||
|
{
|
||||||
|
case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
|
||||||
|
return new DefaultSkinComponentsContainer(container =>
|
||||||
|
{
|
||||||
|
var combo = container.ChildrenOfType<ArgonManiaComboCounter>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (combo != null)
|
||||||
|
{
|
||||||
|
combo.ShowLabel.Value = false;
|
||||||
|
combo.Anchor = Anchor.TopCentre;
|
||||||
|
combo.Origin = Anchor.Centre;
|
||||||
|
combo.Y = 200;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
new ArgonManiaComboCounter(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
||||||
// This should eventually be moved to a skin setting, when supported.
|
// This should eventually be moved to a skin setting, when supported.
|
||||||
if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great)
|
if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great)
|
||||||
|
@ -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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
|
{
|
||||||
|
public partial class LegacyManiaComboCounter : LegacyComboCounter
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin)
|
||||||
|
{
|
||||||
|
DisplayedCountText.Anchor = Anchor.Centre;
|
||||||
|
DisplayedCountText.Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
PopOutCountText.Anchor = Anchor.Centre;
|
||||||
|
PopOutCountText.Origin = Anchor.Centre;
|
||||||
|
PopOutCountText.Colour = skin.GetManiaSkinConfig<Color4>(LegacyManiaSkinConfigurationLookups.ComboBreakColour)?.Value ?? Color4.Red;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IScrollingInfo scrollingInfo { get; set; } = null!;
|
||||||
|
|
||||||
|
private IBindable<ScrollingDirection> direction = null!;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
direction = scrollingInfo.Direction.GetBoundCopy();
|
||||||
|
direction.BindValueChanged(_ => updateAnchor());
|
||||||
|
|
||||||
|
// two schedules are required so that updateAnchor is executed in the next frame,
|
||||||
|
// which is when the combo counter receives its Y position by the default layout in LegacyManiaSkinTransformer.
|
||||||
|
Schedule(() => Schedule(updateAnchor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAnchor()
|
||||||
|
{
|
||||||
|
// if the anchor isn't a vertical center, set top or bottom anchor based on scroll direction
|
||||||
|
if (!Anchor.HasFlag(Anchor.y1))
|
||||||
|
{
|
||||||
|
Anchor &= ~(Anchor.y0 | Anchor.y2);
|
||||||
|
Anchor |= direction.Value == ScrollingDirection.Up ? Anchor.y2 : Anchor.y0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we flip the vertical anchor when changing scroll direction,
|
||||||
|
// we can use the sign of the Y value as an indicator to make the combo counter displayed correctly.
|
||||||
|
if ((Y < 0 && direction.Value == ScrollingDirection.Down) || (Y > 0 && direction.Value == ScrollingDirection.Up))
|
||||||
|
Y = -Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCountIncrement()
|
||||||
|
{
|
||||||
|
base.OnCountIncrement();
|
||||||
|
|
||||||
|
PopOutCountText.Hide();
|
||||||
|
DisplayedCountText.ScaleTo(new Vector2(1f, 1.4f))
|
||||||
|
.ScaleTo(new Vector2(1f), 300, Easing.Out)
|
||||||
|
.FadeIn(120);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCountChange()
|
||||||
|
{
|
||||||
|
base.OnCountChange();
|
||||||
|
|
||||||
|
PopOutCountText.Hide();
|
||||||
|
DisplayedCountText.ScaleTo(1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCountRolling()
|
||||||
|
{
|
||||||
|
if (DisplayedCount > 0)
|
||||||
|
{
|
||||||
|
PopOutCountText.Text = FormatCount(DisplayedCount);
|
||||||
|
PopOutCountText.FadeTo(0.8f).FadeOut(200)
|
||||||
|
.ScaleTo(1f).ScaleTo(4f, 200);
|
||||||
|
|
||||||
|
DisplayedCountText.FadeTo(0.5f, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnCountRolling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,11 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
@ -78,6 +80,40 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
switch (lookup)
|
switch (lookup)
|
||||||
{
|
{
|
||||||
|
case SkinComponentsContainerLookup containerLookup:
|
||||||
|
// Modifications for global components.
|
||||||
|
if (containerLookup.Ruleset == null)
|
||||||
|
return base.GetDrawableComponent(lookup);
|
||||||
|
|
||||||
|
// Skin has configuration.
|
||||||
|
if (base.GetDrawableComponent(lookup) is UserConfiguredLayoutContainer d)
|
||||||
|
return d;
|
||||||
|
|
||||||
|
// we don't have enough assets to display these components (this is especially the case on a "beatmap" skin).
|
||||||
|
if (!IsProvidingLegacyResources)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (containerLookup.Target)
|
||||||
|
{
|
||||||
|
case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
|
||||||
|
return new DefaultSkinComponentsContainer(container =>
|
||||||
|
{
|
||||||
|
var combo = container.ChildrenOfType<LegacyManiaComboCounter>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (combo != null)
|
||||||
|
{
|
||||||
|
combo.Anchor = Anchor.TopCentre;
|
||||||
|
combo.Origin = Anchor.Centre;
|
||||||
|
combo.Y = this.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.ComboPosition)?.Value ?? 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
new LegacyManiaComboCounter(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
||||||
return getResult(resultComponent.Component);
|
return getResult(resultComponent.Component);
|
||||||
|
|
||||||
|
@ -74,11 +74,20 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
// 340px is the default height inherit from stable
|
// 340px is the default height inherit from stable
|
||||||
keyCounter.Y = container.ToLocalSpace(new Vector2(0, container.ScreenSpaceDrawQuad.Centre.Y - 340f)).Y;
|
keyCounter.Y = container.ToLocalSpace(new Vector2(0, container.ScreenSpaceDrawQuad.Centre.Y - 340f)).Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var combo = container.OfType<LegacyDefaultComboCounter>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (combo != null)
|
||||||
|
{
|
||||||
|
combo.Anchor = Anchor.BottomLeft;
|
||||||
|
combo.Origin = Anchor.BottomLeft;
|
||||||
|
combo.Scale = new Vector2(1.28f);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new LegacyComboCounter(),
|
new LegacyDefaultComboCounter(),
|
||||||
new LegacyKeyCounterDisplay(),
|
new LegacyKeyCounterDisplay(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -90,7 +99,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
switch (osuComponent.Component)
|
switch (osuComponent.Component)
|
||||||
{
|
{
|
||||||
case OsuSkinComponents.FollowPoint:
|
case OsuSkinComponents.FollowPoint:
|
||||||
return this.GetAnimation("followpoint", true, true, true, startAtCurrentTime: false, maxSize: new Vector2(OsuHitObject.OBJECT_RADIUS * 2, OsuHitObject.OBJECT_RADIUS));
|
return this.GetAnimation("followpoint", true, true, true, startAtCurrentTime: false,
|
||||||
|
maxSize: new Vector2(OsuHitObject.OBJECT_RADIUS * 2, OsuHitObject.OBJECT_RADIUS));
|
||||||
|
|
||||||
case OsuSkinComponents.SliderScorePoint:
|
case OsuSkinComponents.SliderScorePoint:
|
||||||
return this.GetAnimation("sliderscorepoint", false, false, maxSize: OsuHitObject.OBJECT_DIMENSIONS);
|
return this.GetAnimation("sliderscorepoint", false, false, maxSize: OsuHitObject.OBJECT_DIMENSIONS);
|
||||||
|
@ -443,7 +443,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("no combo in global target", () => !globalHUDTarget.Components.OfType<LegacyComboCounter>().Any());
|
AddAssert("no combo in global target", () => !globalHUDTarget.Components.OfType<LegacyComboCounter>().Any());
|
||||||
AddAssert("combo placed in ruleset target", () => rulesetHUDTarget.Components.OfType<LegacyComboCounter>().Count() == 1);
|
AddAssert("combo placed in ruleset target", () => rulesetHUDTarget.Components.OfType<LegacyComboCounter>().Count() == 1);
|
||||||
|
|
||||||
AddStep("add combo to global target", () => globalHUDTarget.Add(new LegacyComboCounter
|
AddStep("add combo to global target", () => globalHUDTarget.Add(new LegacyDefaultComboCounter
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected override Drawable CreateArgonImplementation() => new ArgonComboCounter();
|
protected override Drawable CreateArgonImplementation() => new ArgonComboCounter();
|
||||||
protected override Drawable CreateDefaultImplementation() => new DefaultComboCounter();
|
protected override Drawable CreateDefaultImplementation() => new DefaultComboCounter();
|
||||||
protected override Drawable CreateLegacyImplementation() => new LegacyComboCounter();
|
protected override Drawable CreateLegacyImplementation() => new LegacyDefaultComboCounter();
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestComboCounterIncrementing()
|
public void TestComboCounterIncrementing()
|
||||||
|
@ -19,10 +19,12 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
public partial class ArgonComboCounter : ComboCounter
|
public partial class ArgonComboCounter : ComboCounter
|
||||||
{
|
{
|
||||||
private ArgonCounterTextComponent text = null!;
|
protected ArgonCounterTextComponent Text = null!;
|
||||||
|
|
||||||
protected override double RollingDuration => 250;
|
protected override double RollingDuration => 250;
|
||||||
|
|
||||||
|
protected virtual bool DisplayXSymbol => true;
|
||||||
|
|
||||||
[SettingSource("Wireframe opacity", "Controls the opacity of the wireframes behind the digits.")]
|
[SettingSource("Wireframe opacity", "Controls the opacity of the wireframes behind the digits.")]
|
||||||
public BindableFloat WireframeOpacity { get; } = new BindableFloat(0.25f)
|
public BindableFloat WireframeOpacity { get; } = new BindableFloat(0.25f)
|
||||||
{
|
{
|
||||||
@ -43,16 +45,16 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
bool wasIncrease = combo.NewValue > combo.OldValue;
|
bool wasIncrease = combo.NewValue > combo.OldValue;
|
||||||
bool wasMiss = combo.OldValue > 1 && combo.NewValue == 0;
|
bool wasMiss = combo.OldValue > 1 && combo.NewValue == 0;
|
||||||
|
|
||||||
float newScale = Math.Clamp(text.NumberContainer.Scale.X * (wasIncrease ? 1.1f : 0.8f), 0.6f, 1.4f);
|
float newScale = Math.Clamp(Text.NumberContainer.Scale.X * (wasIncrease ? 1.1f : 0.8f), 0.6f, 1.4f);
|
||||||
|
|
||||||
float duration = wasMiss ? 2000 : 500;
|
float duration = wasMiss ? 2000 : 500;
|
||||||
|
|
||||||
text.NumberContainer
|
Text.NumberContainer
|
||||||
.ScaleTo(new Vector2(newScale))
|
.ScaleTo(new Vector2(newScale))
|
||||||
.ScaleTo(Vector2.One, duration, Easing.OutQuint);
|
.ScaleTo(Vector2.One, duration, Easing.OutQuint);
|
||||||
|
|
||||||
if (wasMiss)
|
if (wasMiss)
|
||||||
text.FlashColour(Color4.Red, duration, Easing.OutQuint);
|
Text.FlashColour(Color4.Red, duration, Easing.OutQuint);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,23 +72,23 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
int digitsRequiredForDisplayCount = getDigitsRequiredForDisplayCount();
|
int digitsRequiredForDisplayCount = getDigitsRequiredForDisplayCount();
|
||||||
|
|
||||||
if (digitsRequiredForDisplayCount != text.WireframeTemplate.Length)
|
if (digitsRequiredForDisplayCount != Text.WireframeTemplate.Length)
|
||||||
text.WireframeTemplate = new string('#', digitsRequiredForDisplayCount);
|
Text.WireframeTemplate = new string('#', digitsRequiredForDisplayCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getDigitsRequiredForDisplayCount()
|
private int getDigitsRequiredForDisplayCount()
|
||||||
{
|
{
|
||||||
// one for the single presumed starting digit, one for the "x" at the end.
|
// one for the single presumed starting digit, one for the "x" at the end (unless disabled).
|
||||||
int digitsRequired = 2;
|
int digitsRequired = DisplayXSymbol ? 2 : 1;
|
||||||
long c = DisplayedCount;
|
long c = DisplayedCount;
|
||||||
while ((c /= 10) > 0)
|
while ((c /= 10) > 0)
|
||||||
digitsRequired++;
|
digitsRequired++;
|
||||||
return digitsRequired;
|
return digitsRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override LocalisableString FormatCount(int count) => $@"{count}x";
|
protected override LocalisableString FormatCount(int count) => DisplayXSymbol ? $@"{count}x" : count.ToString();
|
||||||
|
|
||||||
protected override IHasText CreateText() => text = new ArgonCounterTextComponent(Anchor.TopLeft, MatchesStrings.MatchScoreStatsCombo.ToUpper())
|
protected override IHasText CreateText() => Text = new ArgonCounterTextComponent(Anchor.TopLeft, MatchesStrings.MatchScoreStatsCombo.ToUpper())
|
||||||
{
|
{
|
||||||
WireframeOpacity = { BindTarget = WireframeOpacity },
|
WireframeOpacity = { BindTarget = WireframeOpacity },
|
||||||
ShowLabel = { BindTarget = ShowLabel },
|
ShowLabel = { BindTarget = ShowLabel },
|
||||||
|
@ -32,6 +32,7 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Scoring.Legacy;
|
using osu.Game.Scoring.Legacy;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
@ -236,6 +237,9 @@ namespace osu.Game.Screens.Play
|
|||||||
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, gameplayMods);
|
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, gameplayMods);
|
||||||
dependencies.CacheAs(DrawableRuleset);
|
dependencies.CacheAs(DrawableRuleset);
|
||||||
|
|
||||||
|
if (DrawableRuleset is IDrawableScrollingRuleset scrollingRuleset)
|
||||||
|
dependencies.CacheAs(scrollingRuleset.ScrollingInfo);
|
||||||
|
|
||||||
ScoreProcessor = ruleset.CreateScoreProcessor();
|
ScoreProcessor = ruleset.CreateScoreProcessor();
|
||||||
ScoreProcessor.Mods.Value = gameplayMods;
|
ScoreProcessor.Mods.Value = gameplayMods;
|
||||||
ScoreProcessor.ApplyBeatmap(playableBeatmap);
|
ScoreProcessor.ApplyBeatmap(playableBeatmap);
|
||||||
|
@ -5,25 +5,17 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Skinning
|
namespace osu.Game.Skinning
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uses the 'x' symbol and has a pop-out effect while rolling over.
|
/// Uses the 'x' symbol and has a pop-out effect while rolling over.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class LegacyComboCounter : CompositeDrawable, ISerialisableDrawable
|
public abstract partial class LegacyComboCounter : CompositeDrawable, ISerialisableDrawable
|
||||||
{
|
{
|
||||||
public Bindable<int> Current { get; } = new BindableInt { MinValue = 0 };
|
public Bindable<int> Current { get; } = new BindableInt { MinValue = 0 };
|
||||||
|
|
||||||
private uint scheduledPopOutCurrentId;
|
|
||||||
|
|
||||||
private const double big_pop_out_duration = 300;
|
|
||||||
|
|
||||||
private const double small_pop_out_duration = 100;
|
|
||||||
|
|
||||||
private const double fade_out_duration = 100;
|
private const double fade_out_duration = 100;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -31,9 +23,8 @@ namespace osu.Game.Skinning
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const double rolling_duration = 20;
|
private const double rolling_duration = 20;
|
||||||
|
|
||||||
private readonly Drawable popOutCount;
|
protected readonly LegacySpriteText PopOutCountText;
|
||||||
|
protected readonly LegacySpriteText DisplayedCountText;
|
||||||
private readonly Drawable displayedCountSpriteText;
|
|
||||||
|
|
||||||
private int previousValue;
|
private int previousValue;
|
||||||
|
|
||||||
@ -45,17 +36,10 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public bool UsesFixedAnchor { get; set; }
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
|
||||||
public LegacyComboCounter()
|
protected LegacyComboCounter()
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Anchor = Anchor.BottomLeft;
|
|
||||||
Origin = Anchor.BottomLeft;
|
|
||||||
|
|
||||||
Margin = new MarginPadding(10);
|
|
||||||
|
|
||||||
Scale = new Vector2(1.28f);
|
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
counterContainer = new Container
|
counterContainer = new Container
|
||||||
@ -63,18 +47,16 @@ namespace osu.Game.Skinning
|
|||||||
AlwaysPresent = true,
|
AlwaysPresent = true,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
popOutCount = new LegacySpriteText(LegacyFont.Combo)
|
PopOutCountText = new LegacySpriteText(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
BypassAutoSizeAxes = Axes.Both,
|
BypassAutoSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
displayedCountSpriteText = new LegacySpriteText(LegacyFont.Combo)
|
DisplayedCountText = new LegacySpriteText(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
AlwaysPresent = true,
|
AlwaysPresent = true,
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
BypassAutoSizeAxes = Axes.Both,
|
BypassAutoSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -114,26 +96,12 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
((IHasText)displayedCountSpriteText).Text = formatCount(Current.Value);
|
DisplayedCountText.Text = FormatCount(Current.Value);
|
||||||
((IHasText)popOutCount).Text = formatCount(Current.Value);
|
PopOutCountText.Text = FormatCount(Current.Value);
|
||||||
|
|
||||||
Current.BindValueChanged(combo => updateCount(combo.NewValue == 0), true);
|
Current.BindValueChanged(combo => updateCount(combo.NewValue == 0), true);
|
||||||
|
|
||||||
updateLayout();
|
counterContainer.Size = DisplayedCountText.Size;
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLayout()
|
|
||||||
{
|
|
||||||
const float font_height_ratio = 0.625f;
|
|
||||||
const float vertical_offset = 9;
|
|
||||||
|
|
||||||
displayedCountSpriteText.OriginPosition = new Vector2(0, font_height_ratio * displayedCountSpriteText.Height + vertical_offset);
|
|
||||||
displayedCountSpriteText.Position = new Vector2(0, -(1 - font_height_ratio) * displayedCountSpriteText.Height + vertical_offset);
|
|
||||||
|
|
||||||
popOutCount.OriginPosition = new Vector2(3, font_height_ratio * popOutCount.Height + vertical_offset); // In stable, the bigger pop out scales a bit to the left
|
|
||||||
popOutCount.Position = new Vector2(0, -(1 - font_height_ratio) * popOutCount.Height + vertical_offset);
|
|
||||||
|
|
||||||
counterContainer.Size = displayedCountSpriteText.Size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCount(bool rolling)
|
private void updateCount(bool rolling)
|
||||||
@ -147,127 +115,84 @@ namespace osu.Game.Skinning
|
|||||||
if (!rolling)
|
if (!rolling)
|
||||||
{
|
{
|
||||||
FinishTransforms(false, nameof(DisplayedCount));
|
FinishTransforms(false, nameof(DisplayedCount));
|
||||||
|
|
||||||
isRolling = false;
|
isRolling = false;
|
||||||
DisplayedCount = prev;
|
DisplayedCount = prev;
|
||||||
|
|
||||||
if (prev + 1 == Current.Value)
|
if (prev + 1 == Current.Value)
|
||||||
onCountIncrement(prev, Current.Value);
|
OnCountIncrement();
|
||||||
else
|
else
|
||||||
onCountChange(Current.Value);
|
OnCountChange();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
onCountRolling(displayedCount, Current.Value);
|
OnCountRolling();
|
||||||
isRolling = true;
|
isRolling = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transformPopOut(int newValue)
|
/// <summary>
|
||||||
|
/// Raised when the counter should display the new value with transitions.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCountIncrement()
|
||||||
{
|
{
|
||||||
((IHasText)popOutCount).Text = formatCount(newValue);
|
if (DisplayedCount < Current.Value - 1)
|
||||||
|
DisplayedCount++;
|
||||||
popOutCount.ScaleTo(1.56f)
|
|
||||||
.ScaleTo(1, big_pop_out_duration);
|
|
||||||
|
|
||||||
popOutCount.FadeTo(0.6f)
|
|
||||||
.FadeOut(big_pop_out_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void transformNoPopOut(int newValue)
|
|
||||||
{
|
|
||||||
((IHasText)displayedCountSpriteText).Text = formatCount(newValue);
|
|
||||||
|
|
||||||
counterContainer.Size = displayedCountSpriteText.Size;
|
|
||||||
|
|
||||||
displayedCountSpriteText.ScaleTo(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void transformPopOutSmall(int newValue)
|
|
||||||
{
|
|
||||||
((IHasText)displayedCountSpriteText).Text = formatCount(newValue);
|
|
||||||
|
|
||||||
counterContainer.Size = displayedCountSpriteText.Size;
|
|
||||||
|
|
||||||
displayedCountSpriteText.ScaleTo(1).Then()
|
|
||||||
.ScaleTo(1.1f, small_pop_out_duration / 2, Easing.In).Then()
|
|
||||||
.ScaleTo(1, small_pop_out_duration / 2, Easing.Out);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scheduledPopOutSmall(uint id)
|
|
||||||
{
|
|
||||||
// Too late; scheduled task invalidated
|
|
||||||
if (id != scheduledPopOutCurrentId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DisplayedCount++;
|
DisplayedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCountIncrement(int currentValue, int newValue)
|
/// <summary>
|
||||||
|
/// Raised when the counter should roll to the new combo value (usually roll back to zero).
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCountRolling()
|
||||||
{
|
{
|
||||||
scheduledPopOutCurrentId++;
|
|
||||||
|
|
||||||
if (DisplayedCount < currentValue)
|
|
||||||
DisplayedCount++;
|
|
||||||
|
|
||||||
displayedCountSpriteText.Show();
|
|
||||||
|
|
||||||
transformPopOut(newValue);
|
|
||||||
|
|
||||||
uint newTaskId = scheduledPopOutCurrentId;
|
|
||||||
|
|
||||||
Scheduler.AddDelayed(delegate
|
|
||||||
{
|
|
||||||
scheduledPopOutSmall(newTaskId);
|
|
||||||
}, big_pop_out_duration - 140);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onCountRolling(int currentValue, int newValue)
|
|
||||||
{
|
|
||||||
scheduledPopOutCurrentId++;
|
|
||||||
|
|
||||||
// Hides displayed count if was increasing from 0 to 1 but didn't finish
|
// Hides displayed count if was increasing from 0 to 1 but didn't finish
|
||||||
if (currentValue == 0 && newValue == 0)
|
if (DisplayedCount == 0 && Current.Value == 0)
|
||||||
displayedCountSpriteText.FadeOut(fade_out_duration);
|
DisplayedCountText.FadeOut(fade_out_duration);
|
||||||
|
|
||||||
transformRoll(currentValue, newValue);
|
transformRoll(DisplayedCount, Current.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCountChange(int newValue)
|
/// <summary>
|
||||||
|
/// Raised when the counter should display the new combo value without any transitions.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCountChange()
|
||||||
{
|
{
|
||||||
scheduledPopOutCurrentId++;
|
if (Current.Value == 0)
|
||||||
|
DisplayedCountText.FadeOut();
|
||||||
|
|
||||||
if (newValue == 0)
|
DisplayedCount = Current.Value;
|
||||||
displayedCountSpriteText.FadeOut();
|
|
||||||
|
|
||||||
DisplayedCount = newValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisplayedCountRolling(int newValue)
|
private void onDisplayedCountRolling(int newValue)
|
||||||
{
|
{
|
||||||
if (newValue == 0)
|
if (newValue == 0)
|
||||||
displayedCountSpriteText.FadeOut(fade_out_duration);
|
DisplayedCountText.FadeOut(fade_out_duration);
|
||||||
else
|
|
||||||
displayedCountSpriteText.Show();
|
|
||||||
|
|
||||||
transformNoPopOut(newValue);
|
DisplayedCountText.Text = FormatCount(newValue);
|
||||||
|
counterContainer.Size = DisplayedCountText.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisplayedCountChange(int newValue)
|
private void onDisplayedCountChange(int newValue)
|
||||||
{
|
{
|
||||||
displayedCountSpriteText.FadeTo(newValue == 0 ? 0 : 1);
|
DisplayedCountText.FadeTo(newValue == 0 ? 0 : 1);
|
||||||
transformNoPopOut(newValue);
|
DisplayedCountText.Text = FormatCount(newValue);
|
||||||
|
|
||||||
|
counterContainer.Size = DisplayedCountText.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisplayedCountIncrement(int newValue)
|
private void onDisplayedCountIncrement(int newValue)
|
||||||
{
|
{
|
||||||
displayedCountSpriteText.Show();
|
DisplayedCountText.Text = FormatCount(newValue);
|
||||||
transformPopOutSmall(newValue);
|
|
||||||
|
counterContainer.Size = DisplayedCountText.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transformRoll(int currentValue, int newValue) =>
|
private void transformRoll(int currentValue, int newValue) =>
|
||||||
this.TransformTo(nameof(DisplayedCount), newValue, getProportionalDuration(currentValue, newValue));
|
this.TransformTo(nameof(DisplayedCount), newValue, getProportionalDuration(currentValue, newValue));
|
||||||
|
|
||||||
private string formatCount(int count) => $@"{count}x";
|
protected virtual string FormatCount(int count) => $@"{count}";
|
||||||
|
|
||||||
private double getProportionalDuration(int currentValue, int newValue)
|
private double getProportionalDuration(int currentValue, int newValue)
|
||||||
{
|
{
|
||||||
|
85
osu.Game/Skinning/LegacyDefaultComboCounter.cs
Normal file
85
osu.Game/Skinning/LegacyDefaultComboCounter.cs
Normal file
@ -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 osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Uses the 'x' symbol and has a pop-out effect while rolling over.
|
||||||
|
/// </summary>
|
||||||
|
public partial class LegacyDefaultComboCounter : LegacyComboCounter
|
||||||
|
{
|
||||||
|
private const double big_pop_out_duration = 300;
|
||||||
|
private const double small_pop_out_duration = 100;
|
||||||
|
|
||||||
|
private ScheduledDelegate? scheduledPopOut;
|
||||||
|
|
||||||
|
public LegacyDefaultComboCounter()
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(10);
|
||||||
|
|
||||||
|
PopOutCountText.Anchor = Anchor.BottomLeft;
|
||||||
|
DisplayedCountText.Anchor = Anchor.BottomLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
const float font_height_ratio = 0.625f;
|
||||||
|
const float vertical_offset = 9;
|
||||||
|
|
||||||
|
DisplayedCountText.OriginPosition = new Vector2(0, font_height_ratio * DisplayedCountText.Height + vertical_offset);
|
||||||
|
DisplayedCountText.Position = new Vector2(0, -(1 - font_height_ratio) * DisplayedCountText.Height + vertical_offset);
|
||||||
|
|
||||||
|
PopOutCountText.OriginPosition = new Vector2(3, font_height_ratio * PopOutCountText.Height + vertical_offset); // In stable, the bigger pop out scales a bit to the left
|
||||||
|
PopOutCountText.Position = new Vector2(0, -(1 - font_height_ratio) * PopOutCountText.Height + vertical_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCountIncrement()
|
||||||
|
{
|
||||||
|
scheduledPopOut?.Cancel();
|
||||||
|
scheduledPopOut = null;
|
||||||
|
|
||||||
|
DisplayedCountText.Show();
|
||||||
|
|
||||||
|
PopOutCountText.Text = FormatCount(Current.Value);
|
||||||
|
|
||||||
|
PopOutCountText.ScaleTo(1.56f)
|
||||||
|
.ScaleTo(1, big_pop_out_duration);
|
||||||
|
|
||||||
|
PopOutCountText.FadeTo(0.6f)
|
||||||
|
.FadeOut(big_pop_out_duration);
|
||||||
|
|
||||||
|
this.Delay(big_pop_out_duration - 140).Schedule(() =>
|
||||||
|
{
|
||||||
|
base.OnCountIncrement();
|
||||||
|
|
||||||
|
DisplayedCountText.ScaleTo(1).Then()
|
||||||
|
.ScaleTo(1.1f, small_pop_out_duration / 2, Easing.In).Then()
|
||||||
|
.ScaleTo(1, small_pop_out_duration / 2, Easing.Out);
|
||||||
|
}, out scheduledPopOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCountRolling()
|
||||||
|
{
|
||||||
|
scheduledPopOut?.Cancel();
|
||||||
|
scheduledPopOut = null;
|
||||||
|
|
||||||
|
base.OnCountRolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnCountChange()
|
||||||
|
{
|
||||||
|
scheduledPopOut?.Cancel();
|
||||||
|
scheduledPopOut = null;
|
||||||
|
|
||||||
|
base.OnCountChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string FormatCount(int count) => $@"{count}x";
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public float HitPosition = DEFAULT_HIT_POSITION;
|
public float HitPosition = DEFAULT_HIT_POSITION;
|
||||||
public float LightPosition = (480 - 413) * POSITION_SCALE_FACTOR;
|
public float LightPosition = (480 - 413) * POSITION_SCALE_FACTOR;
|
||||||
|
public float ComboPosition = 111 * POSITION_SCALE_FACTOR;
|
||||||
public float ScorePosition = 300 * POSITION_SCALE_FACTOR;
|
public float ScorePosition = 300 * POSITION_SCALE_FACTOR;
|
||||||
public bool ShowJudgementLine = true;
|
public bool ShowJudgementLine = true;
|
||||||
public bool KeysUnderNotes;
|
public bool KeysUnderNotes;
|
||||||
|
@ -42,6 +42,7 @@ namespace osu.Game.Skinning
|
|||||||
LeftLineWidth,
|
LeftLineWidth,
|
||||||
RightLineWidth,
|
RightLineWidth,
|
||||||
HitPosition,
|
HitPosition,
|
||||||
|
ComboPosition,
|
||||||
ScorePosition,
|
ScorePosition,
|
||||||
LightPosition,
|
LightPosition,
|
||||||
StagePaddingTop,
|
StagePaddingTop,
|
||||||
@ -63,6 +64,7 @@ namespace osu.Game.Skinning
|
|||||||
JudgementLineColour,
|
JudgementLineColour,
|
||||||
ColumnBackgroundColour,
|
ColumnBackgroundColour,
|
||||||
ColumnLightColour,
|
ColumnLightColour,
|
||||||
|
ComboBreakColour,
|
||||||
MinimumColumnWidth,
|
MinimumColumnWidth,
|
||||||
LeftStageImage,
|
LeftStageImage,
|
||||||
RightStageImage,
|
RightStageImage,
|
||||||
|
@ -94,6 +94,10 @@ namespace osu.Game.Skinning
|
|||||||
currentConfig.LightPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
currentConfig.LightPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "ComboPosition":
|
||||||
|
currentConfig.ComboPosition = (float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
||||||
|
break;
|
||||||
|
|
||||||
case "ScorePosition":
|
case "ScorePosition":
|
||||||
currentConfig.ScorePosition = (float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
currentConfig.ScorePosition = (float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
||||||
break;
|
break;
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -24,6 +23,7 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
||||||
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Skinning
|
namespace osu.Game.Skinning
|
||||||
@ -155,6 +155,9 @@ namespace osu.Game.Skinning
|
|||||||
case LegacyManiaSkinConfigurationLookups.HitPosition:
|
case LegacyManiaSkinConfigurationLookups.HitPosition:
|
||||||
return SkinUtils.As<TValue>(new Bindable<float>(existing.HitPosition));
|
return SkinUtils.As<TValue>(new Bindable<float>(existing.HitPosition));
|
||||||
|
|
||||||
|
case LegacyManiaSkinConfigurationLookups.ComboPosition:
|
||||||
|
return SkinUtils.As<TValue>(new Bindable<float>(existing.ComboPosition));
|
||||||
|
|
||||||
case LegacyManiaSkinConfigurationLookups.ScorePosition:
|
case LegacyManiaSkinConfigurationLookups.ScorePosition:
|
||||||
return SkinUtils.As<TValue>(new Bindable<float>(existing.ScorePosition));
|
return SkinUtils.As<TValue>(new Bindable<float>(existing.ScorePosition));
|
||||||
|
|
||||||
@ -192,6 +195,9 @@ namespace osu.Game.Skinning
|
|||||||
Debug.Assert(maniaLookup.ColumnIndex != null);
|
Debug.Assert(maniaLookup.ColumnIndex != null);
|
||||||
return SkinUtils.As<TValue>(getCustomColour(existing, $"ColourLight{maniaLookup.ColumnIndex + 1}"));
|
return SkinUtils.As<TValue>(getCustomColour(existing, $"ColourLight{maniaLookup.ColumnIndex + 1}"));
|
||||||
|
|
||||||
|
case LegacyManiaSkinConfigurationLookups.ComboBreakColour:
|
||||||
|
return SkinUtils.As<TValue>(getCustomColour(existing, "ColourBreak"));
|
||||||
|
|
||||||
case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth:
|
case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth:
|
||||||
return SkinUtils.As<TValue>(new Bindable<float>(existing.MinimumColumnWidth));
|
return SkinUtils.As<TValue>(new Bindable<float>(existing.MinimumColumnWidth));
|
||||||
|
|
||||||
@ -361,10 +367,19 @@ namespace osu.Game.Skinning
|
|||||||
case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
|
case SkinComponentsContainerLookup.TargetArea.MainHUDComponents:
|
||||||
if (containerLookup.Ruleset != null)
|
if (containerLookup.Ruleset != null)
|
||||||
{
|
{
|
||||||
return new Container
|
return new DefaultSkinComponentsContainer(container =>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
var combo = container.OfType<LegacyDefaultComboCounter>().FirstOrDefault();
|
||||||
Child = new LegacyComboCounter(),
|
|
||||||
|
if (combo != null)
|
||||||
|
{
|
||||||
|
combo.Anchor = Anchor.BottomLeft;
|
||||||
|
combo.Origin = Anchor.BottomLeft;
|
||||||
|
combo.Scale = new Vector2(1.28f);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
new LegacyDefaultComboCounter()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +213,7 @@ namespace osu.Game.Skinning
|
|||||||
// handle namespace changes...
|
// handle namespace changes...
|
||||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress");
|
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.SongProgress", @"osu.Game.Screens.Play.HUD.DefaultSongProgress");
|
||||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter");
|
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.LegacyComboCounter", @"osu.Game.Skinning.LegacyComboCounter");
|
||||||
|
jsonContent = jsonContent.Replace(@"osu.Game.Skinning.LegacyComboCounter", @"osu.Game.Skinning.LegacyDefaultComboCounter");
|
||||||
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.PerformancePointsCounter", @"osu.Game.Skinning.Triangles.TrianglesPerformancePointsCounter");
|
jsonContent = jsonContent.Replace(@"osu.Game.Screens.Play.HUD.PerformancePointsCounter", @"osu.Game.Skinning.Triangles.TrianglesPerformancePointsCounter");
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -250,13 +251,15 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
|
// Combo counters were moved out of the global HUD components into per-ruleset.
|
||||||
|
// This is to allow some rulesets to customise further (ie. mania and catch moving the combo to within their play area).
|
||||||
if (target != SkinComponentsContainerLookup.TargetArea.MainHUDComponents ||
|
if (target != SkinComponentsContainerLookup.TargetArea.MainHUDComponents ||
|
||||||
!layout.TryGetDrawableInfo(null, out var globalHUDComponents) ||
|
!layout.TryGetDrawableInfo(null, out var globalHUDComponents) ||
|
||||||
resources == null)
|
resources == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var comboCounters = globalHUDComponents.Where(c =>
|
var comboCounters = globalHUDComponents.Where(c =>
|
||||||
c.Type.Name == nameof(LegacyComboCounter) ||
|
c.Type.Name == nameof(LegacyDefaultComboCounter) ||
|
||||||
c.Type.Name == nameof(DefaultComboCounter) ||
|
c.Type.Name == nameof(DefaultComboCounter) ||
|
||||||
c.Type.Name == nameof(ArgonComboCounter)).ToArray();
|
c.Type.Name == nameof(ArgonComboCounter)).ToArray();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user