Chessistics/Scripts/UI/MetricsOverlay.cs
Samuel Bouchet 450c069854 Juice pass: procedural SFX, particles, polished visuals
Sound (SfxManager.cs):
- Procedural audio synthesis via AudioStreamWav — no external files
- Distinct tones for place, produce, transfer, deliver, move, destroy, victory
- Simple ADSR envelope, sine/triangle waveforms, filtered noise for swooshes

Pieces (PieceView.cs):
- Warm earthy palette: sage green, deep teal, dusty rose, burnt sienna
- Drop shadow under each piece for depth
- 3-stop radial gradient (bright center → main → dark rim)
- Scale bounce on placement (0 → 1.15 → 1.0 with back-out easing)
- Cargo indicator pulses gently when carrying

Trajectories (TrajectView.cs):
- Arrowhead at endpoint showing movement direction
- Antialiased lines with piece-matched colors

Cells (CellView.cs):
- Warmer palette: parchment/walnut board, deep forest production, aged gold demand
- Production flash uses warm golden glow instead of white
- Subtle inner shadow for visual depth

Animations (EventAnimator.cs):
- Production: golden particles burst from production cells
- Transfer: cargo slides with 2-particle trail + back-out whip easing
- Destruction: pieces shrink + spin + red particle explosion
- Victory: 40 confetti particles rain across the screen
- All phases trigger appropriate SFX

UI polish:
- ControlBar: styled buttons with rounded corners, disabled states
- MetricsOverlay: fade-in + scale animation, sequential metric reveals
- ObjectivePanel: animated progress bars, styled fills, green flash on completion
- Main: fade-in/out transitions between level select and gameplay

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:05:55 +02:00

159 lines
5.3 KiB
C#

using Godot;
using Chessistics.Engine.Model;
namespace Chessistics.Scripts.UI;
public partial class MetricsOverlay : PanelContainer
{
[Signal]
public delegate void NextLevelPressedEventHandler();
[Signal]
public delegate void RetryPressedEventHandler();
private Label _titleLabel = null!;
private Label _piecesLabel = null!;
private Label _turnsLabel = null!;
private Label _cellsLabel = null!;
private HBoxContainer _buttons = null!;
public override void _Ready()
{
var style = new StyleBoxFlat
{
BgColor = new Color(0.1f, 0.1f, 0.12f, 0.95f),
BorderColor = new Color("#B8942A"),
BorderWidthBottom = 2, BorderWidthTop = 2,
BorderWidthLeft = 2, BorderWidthRight = 2,
CornerRadiusTopLeft = 12, CornerRadiusTopRight = 12,
CornerRadiusBottomLeft = 12, CornerRadiusBottomRight = 12,
ContentMarginLeft = 32, ContentMarginRight = 32,
ContentMarginTop = 28, ContentMarginBottom = 28
};
AddThemeStyleboxOverride("panel", style);
var vbox = new VBoxContainer();
vbox.AddThemeConstantOverride("separation", 8);
_titleLabel = new Label
{
Text = "VICTOIRE !",
HorizontalAlignment = HorizontalAlignment.Center
};
_titleLabel.AddThemeFontSizeOverride("font_size", 26);
_titleLabel.AddThemeColorOverride("font_color", new Color("#FFD700"));
vbox.AddChild(_titleLabel);
vbox.AddChild(new HSeparator());
_piecesLabel = CreateMetricLabel();
vbox.AddChild(_piecesLabel);
_turnsLabel = CreateMetricLabel();
vbox.AddChild(_turnsLabel);
_cellsLabel = CreateMetricLabel();
vbox.AddChild(_cellsLabel);
vbox.AddChild(new HSeparator());
_buttons = new HBoxContainer { Alignment = BoxContainer.AlignmentMode.Center };
_buttons.AddThemeConstantOverride("separation", 16);
var retryBtn = CreateStyledButton("Rejouer");
retryBtn.Pressed += () => EmitSignal(SignalName.RetryPressed);
_buttons.AddChild(retryBtn);
var nextBtn = CreateStyledButton("Niveau suivant");
nextBtn.Pressed += () => EmitSignal(SignalName.NextLevelPressed);
_buttons.AddChild(nextBtn);
vbox.AddChild(_buttons);
AddChild(vbox);
Visible = false;
}
public void ShowMetrics(Metrics metrics)
{
_piecesLabel.Text = $"Pieces utilisees: {metrics.PiecesUsed}";
_turnsLabel.Text = $"Coups: {metrics.TurnsTaken}";
_cellsLabel.Text = $"Cases occupees: {metrics.CellsOccupied}";
// Start invisible, fade + scale in
Modulate = new Color(1, 1, 1, 0);
Scale = new Vector2(0.85f, 0.85f);
PivotOffset = Size / 2f;
Visible = true;
// Hide metrics initially, reveal sequentially
_piecesLabel.Modulate = new Color(1, 1, 1, 0);
_turnsLabel.Modulate = new Color(1, 1, 1, 0);
_cellsLabel.Modulate = new Color(1, 1, 1, 0);
_buttons.Modulate = new Color(1, 1, 1, 0);
var tween = CreateTween();
// Panel fade in
tween.SetParallel(true);
tween.TweenProperty(this, "modulate:a", 1f, 0.3f)
.SetEase(Tween.EaseType.Out);
tween.TweenProperty(this, "scale", Vector2.One, 0.35f)
.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Back);
tween.SetParallel(false);
// Sequential metric reveals
tween.TweenInterval(0.15f);
tween.TweenProperty(_piecesLabel, "modulate:a", 1f, 0.2f);
tween.TweenInterval(0.1f);
tween.TweenProperty(_turnsLabel, "modulate:a", 1f, 0.2f);
tween.TweenInterval(0.1f);
tween.TweenProperty(_cellsLabel, "modulate:a", 1f, 0.2f);
tween.TweenInterval(0.15f);
tween.TweenProperty(_buttons, "modulate:a", 1f, 0.2f);
}
public new void Hide()
{
Visible = false;
}
private static Label CreateMetricLabel()
{
var label = new Label
{
Text = "",
HorizontalAlignment = HorizontalAlignment.Center
};
label.AddThemeFontSizeOverride("font_size", 14);
label.AddThemeColorOverride("font_color", new Color("#CCCCCC"));
return label;
}
private static Button CreateStyledButton(string text)
{
var btn = new Button
{
Text = text,
CustomMinimumSize = new Vector2(130, 36)
};
var normal = new StyleBoxFlat
{
BgColor = new Color("#3D6B8E"),
CornerRadiusTopLeft = 6, CornerRadiusTopRight = 6,
CornerRadiusBottomLeft = 6, CornerRadiusBottomRight = 6,
ContentMarginLeft = 16, ContentMarginRight = 16,
ContentMarginTop = 6, ContentMarginBottom = 6
};
var hover = new StyleBoxFlat
{
BgColor = new Color("#4A8EBF"),
CornerRadiusTopLeft = 6, CornerRadiusTopRight = 6,
CornerRadiusBottomLeft = 6, CornerRadiusBottomRight = 6,
ContentMarginLeft = 16, ContentMarginRight = 16,
ContentMarginTop = 6, ContentMarginBottom = 6
};
btn.AddThemeStyleboxOverride("normal", normal);
btn.AddThemeStyleboxOverride("hover", hover);
btn.AddThemeFontSizeOverride("font_size", 13);
return btn;
}
}