Skip to content

Commit

Permalink
Abstractify LegacyComboCounter to re-use for mania
Browse files Browse the repository at this point in the history
  • Loading branch information
frenzibyte committed Dec 30, 2023
1 parent e469e06 commit 78cb6b6
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void TestLegacyHUDComboCounterNotExistent([Values] bool withModifiedSkin)
CreateTest();
}

AddAssert("legacy HUD combo counter not added", () => !Player.ChildrenOfType<LegacyComboCounter>().Any());
AddAssert("legacy HUD combo counter not added", () => !Player.ChildrenOfType<LegacyDefaultComboCounter>().Any());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public partial class TestSceneSkinnableComboCounter : SkinnableHUDComponentTestS

protected override Drawable CreateArgonImplementation() => new ArgonComboCounter();
protected override Drawable CreateDefaultImplementation() => new DefaultComboCounter();
protected override Drawable CreateLegacyImplementation() => new LegacyComboCounter();
protected override Drawable CreateLegacyImplementation() => new LegacyDefaultComboCounter();

[Test]
public void TestComboCounterIncrementing()
Expand Down
163 changes: 44 additions & 119 deletions osu.Game/Skinning/LegacyComboCounter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,26 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
using osuTK;

namespace osu.Game.Skinning
{
/// <summary>
/// Uses the 'x' symbol and has a pop-out effect while rolling over.
/// </summary>
public partial class LegacyComboCounter : CompositeDrawable, ISerialisableDrawable
public abstract partial class LegacyComboCounter : CompositeDrawable, ISerialisableDrawable
{
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;

/// <summary>
/// Duration in milliseconds for the counter roll-up animation for each element.
/// </summary>
private const double rolling_duration = 20;

private readonly Drawable popOutCount;

private readonly Drawable displayedCountSpriteText;
protected readonly LegacySpriteText PopOutCountText;
protected readonly LegacySpriteText DisplayedCountText;

private int previousValue;

Expand All @@ -45,36 +36,27 @@ public partial class LegacyComboCounter : CompositeDrawable, ISerialisableDrawab

public bool UsesFixedAnchor { get; set; }

public LegacyComboCounter()
protected LegacyComboCounter()
{
AutoSizeAxes = Axes.Both;

Anchor = Anchor.BottomLeft;
Origin = Anchor.BottomLeft;

Margin = new MarginPadding(10);

Scale = new Vector2(1.28f);

InternalChildren = new[]
{
counterContainer = new Container
{
AlwaysPresent = true,
Children = new[]
{
popOutCount = new LegacySpriteText(LegacyFont.Combo)
PopOutCountText = new LegacySpriteText(LegacyFont.Combo)
{
Alpha = 0,
Blending = BlendingParameters.Additive,
Anchor = Anchor.BottomLeft,
BypassAutoSizeAxes = Axes.Both,
},
displayedCountSpriteText = new LegacySpriteText(LegacyFont.Combo)
DisplayedCountText = new LegacySpriteText(LegacyFont.Combo)
{
Alpha = 0,
AlwaysPresent = true,
Anchor = Anchor.BottomLeft,
BypassAutoSizeAxes = Axes.Both,
},
}
Expand Down Expand Up @@ -114,26 +96,12 @@ protected override void LoadComplete()
{
base.LoadComplete();

((IHasText)displayedCountSpriteText).Text = formatCount(Current.Value);
((IHasText)popOutCount).Text = formatCount(Current.Value);
DisplayedCountText.Text = FormatCount(Current.Value);
PopOutCountText.Text = FormatCount(Current.Value);

Current.BindValueChanged(combo => updateCount(combo.NewValue == 0), true);

updateLayout();
}

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;
counterContainer.Size = DisplayedCountText.Size;
}

private void updateCount(bool rolling)
Expand All @@ -147,127 +115,84 @@ private void updateCount(bool rolling)
if (!rolling)
{
FinishTransforms(false, nameof(DisplayedCount));

isRolling = false;
DisplayedCount = prev;

if (prev + 1 == Current.Value)
onCountIncrement(prev, Current.Value);
OnCountIncrement();
else
onCountChange(Current.Value);
OnCountChange();
}
else
{
onCountRolling(displayedCount, Current.Value);
OnCountRolling();
isRolling = true;
}
}

private void transformPopOut(int newValue)
{
((IHasText)popOutCount).Text = formatCount(newValue);

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++;
}

private void onCountIncrement(int currentValue, int newValue)
/// <summary>
/// Raised when the counter should display the new value with transitions.
/// </summary>
protected virtual void OnCountIncrement()
{
scheduledPopOutCurrentId++;

if (DisplayedCount < currentValue)
if (DisplayedCount < Current.Value - 1)
DisplayedCount++;

displayedCountSpriteText.Show();

transformPopOut(newValue);

uint newTaskId = scheduledPopOutCurrentId;

Scheduler.AddDelayed(delegate
{
scheduledPopOutSmall(newTaskId);
}, big_pop_out_duration - 140);
DisplayedCount++;
}

private void onCountRolling(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++;

// Hides displayed count if was increasing from 0 to 1 but didn't finish
if (currentValue == 0 && newValue == 0)
displayedCountSpriteText.FadeOut(fade_out_duration);
if (DisplayedCount == 0 && Current.Value == 0)
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 (newValue == 0)
displayedCountSpriteText.FadeOut();
if (Current.Value == 0)
DisplayedCountText.FadeOut();

DisplayedCount = newValue;
DisplayedCount = Current.Value;
}

private void onDisplayedCountRolling(int newValue)
{
if (newValue == 0)
displayedCountSpriteText.FadeOut(fade_out_duration);
else
displayedCountSpriteText.Show();
DisplayedCountText.FadeOut(fade_out_duration);

transformNoPopOut(newValue);
DisplayedCountText.Text = FormatCount(newValue);
counterContainer.Size = DisplayedCountText.Size;
}

private void onDisplayedCountChange(int newValue)
{
displayedCountSpriteText.FadeTo(newValue == 0 ? 0 : 1);
transformNoPopOut(newValue);
DisplayedCountText.FadeTo(newValue == 0 ? 0 : 1);
DisplayedCountText.Text = FormatCount(newValue);

counterContainer.Size = DisplayedCountText.Size;
}

private void onDisplayedCountIncrement(int newValue)
{
displayedCountSpriteText.Show();
transformPopOutSmall(newValue);
DisplayedCountText.Text = FormatCount(newValue);

counterContainer.Size = DisplayedCountText.Size;
}

private void transformRoll(int currentValue, int 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)
{
Expand Down
85 changes: 85 additions & 0 deletions osu.Game/Skinning/LegacyDefaultComboCounter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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";
}
}
4 changes: 2 additions & 2 deletions osu.Game/Skinning/LegacySkinTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public LegacySkinTransformer(ISkin skin)

rulesetHUDComponents ??= new DefaultSkinComponentsContainer(container =>
{
var combo = container.OfType<LegacyComboCounter>().FirstOrDefault();
var combo = container.OfType<LegacyDefaultComboCounter>().FirstOrDefault();

if (combo != null)
{
Expand All @@ -45,7 +45,7 @@ public LegacySkinTransformer(ISkin skin)
}
})
{
new LegacyComboCounter()
new LegacyDefaultComboCounter()
};

return rulesetHUDComponents;
Expand Down
Loading

0 comments on commit 78cb6b6

Please sign in to comment.