Improved animations (#907)

* Smoother countdown and new menu and in-game animations

- Countdown digits pop in and fade out each second, with a ring of dots showing the remaining part of the second
- Medley countdown uses a smoothed timer and no longer stutters
- Rating popups scale in from below and drift upwards while fading out
- Player scores pulse briefly at the end of a line
- Pause menu fades and scales in and out
- Buttons and select slides pulse briefly when they get selected
- Shared easing functions and a draw transform for animations

* Retrigger CI
This commit is contained in:
McSchneidar authored and GitHub committed 2026-10-17 12:39:18 +02:00
1 parent 602417e773
commit e665e31f4a
17 files changed
+489 -46

No files matched your search

+40
View File
@@ -15,6 +15,7 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Diagnostics;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
@@ -74,10 +75,17 @@ namespace VocaluxeLib.Menu
}
}
private readonly Stopwatch _SelectTimer = new Stopwatch();
public override bool Selected
{
set
{
if (value && !base.Selected)
{
_SelectTimer.Restart();
}
base.Selected = value;
Text.Selected = value;
}
@@ -171,6 +179,38 @@ namespace VocaluxeLib.Menu
}
public void Draw()
{
var scale = _GetSelectionScale();
if (scale > 1f)
{
CBase.Drawing.PushTransform(scale, Rect.X + Rect.W / 2f, Rect.Y + Rect.H / 2f, 0f, 1f);
_DrawButton();
CBase.Drawing.PopTransform();
}
else
{
_DrawButton();
}
}
private float _GetSelectionScale()
{
if (!Selected || !_Selectable || !_SelectTimer.IsRunning || CBase.Settings.GetProgramState() == EProgramState.EditTheme)
{
return 1f;
}
var progress = _SelectTimer.ElapsedMilliseconds / 450f;
if (progress >= 1f)
{
_SelectTimer.Stop();
return 1f;
}
return 1f + 0.025f * (float)Math.Sin(Math.PI * progress);
}
private void _DrawButton()
{
if (!Visible && CBase.Settings.GetProgramState() != EProgramState.EditTheme)
{
+31 -3
View File
@@ -1,4 +1,5 @@
using System.Xml.Serialization;
using System;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
namespace VocaluxeLib.Menu
@@ -29,6 +30,8 @@ namespace VocaluxeLib.Menu
public bool ThemeLoaded { get; private set; }
public CText Text;
public float Alpha = 1;
public float Scale = 1;
public float OffsetY;
public SColorF Color;
public CRatingPopup(int partyModeId)
@@ -65,12 +68,37 @@ namespace VocaluxeLib.Menu
color.A = Alpha;
Text.Color.A = Alpha;
var w = Rect.W * Scale;
var h = Rect.H * Scale;
var x = Rect.X + (Rect.W - w) / 2f;
var y = Rect.Y + (Rect.H - h) / 2f + OffsetY;
if (_TextureRatingPopup != null)
{
CBase.Drawing.DrawTexture(_TextureRatingPopup, Rect, color, false);
CBase.Drawing.DrawTexture(_TextureRatingPopup, new SRectF(x, y, w, h, Rect.Z), color, false);
}
Text.DrawRelative(Rect.X, Rect.Y);
if (Math.Abs(Scale - 1f) < 0.001f)
{
Text.DrawRelative(x, y);
return;
}
var textX = Text.X;
var textY = Text.Y;
var textW = Text.W;
var fontHeight = Text.Font.Height;
Text.X = textX * Scale;
Text.Y = textY * Scale;
Text.W = textW * Scale;
Text.Font.Height = fontHeight * Scale;
Text.DrawRelative(x, y);
Text.X = textX;
Text.Y = textY;
Text.W = textW;
Text.Font.Height = fontHeight;
}
public object GetTheme()
+39
View File
@@ -144,10 +144,17 @@ namespace VocaluxeLib.Menu
}
}
private readonly Stopwatch _SelectTimer = new Stopwatch();
public override bool Selected
{
set
{
if (value && !base.Selected)
{
_SelectTimer.Restart();
}
base.Selected = value;
if (!value)
@@ -582,6 +589,38 @@ namespace VocaluxeLib.Menu
}
public void Draw()
{
var scale = _GetSelectionScale();
if (scale > 1f)
{
CBase.Drawing.PushTransform(scale, Rect.X + Rect.W / 2f, Rect.Y + Rect.H / 2f, 0f, 1f);
_DrawSelectSlide();
CBase.Drawing.PopTransform();
}
else
{
_DrawSelectSlide();
}
}
private float _GetSelectionScale()
{
if (!Selected || !_SelectTimer.IsRunning || CBase.Settings.GetProgramState() == EProgramState.EditTheme)
{
return 1f;
}
var progress = _SelectTimer.ElapsedMilliseconds / 450f;
if (progress >= 1f)
{
_SelectTimer.Stop();
return 1f;
}
return 1f + 0.025f * (float)Math.Sin(Math.PI * progress);
}
private void _DrawSelectSlide()
{
if (!Visible && CBase.Settings.GetProgramState() != EProgramState.EditTheme)
{