Add cinematic on mission transition (cell pop-in, camera pan, title overlay)

OnMissionAdvanced now plays a three-track cinematic when the auto-advance
fires between missions:
  - Every cell in the rebuilt board pops in with a scale+fade tween
    (0.45s, back ease) so terrain expansion reads as "appearing".
  - The camera smooth-pans + zooms back to the new board center over
    0.7s, undoing any collision zoom that was active.
  - A full-size "Mission N\nName" overlay fades in, holds for ~1.4s,
    then fades out and frees itself.

The per-cell animation doubles as the expansion cue; a dedicated
new-cells-only tween can be layered later if needed. No new engine
surface — hooks onto the existing MissionStartedEvent path.
This commit is contained in:
Samuel Bouchet 2026-04-17 22:30:15 +02:00
parent 6c28665c38
commit 1d0999a78e
2 changed files with 65 additions and 6 deletions

View file

@ -985,7 +985,7 @@ public partial class Main : Node2D
private void OnMissionAdvanced() private void OnMissionAdvanced()
{ {
// Auto-advance happened during simulation — rebuild board seamlessly // Auto-advance happened during simulation — rebuild board + cinematic
if (_sim == null || _campaignDef == null) return; if (_sim == null || _campaignDef == null) return;
var snap = _sim.GetSnapshot(); var snap = _sim.GetSnapshot();
@ -994,10 +994,73 @@ public partial class Main : Node2D
BuildBoardFromSnapshot(snap); BuildBoardFromSnapshot(snap);
SetupUIForMission(snap, mission); SetupUIForMission(snap, mission);
CenterCameraOnBoard(snap.Width, snap.Height); PlayMissionTransitionCinematic(mission, snap);
_inputMapper.SetSnapshot(snap); _inputMapper.SetSnapshot(snap);
} }
private void PlayMissionTransitionCinematic(MissionDef mission, BoardSnapshot snap)
{
// 1. Board cells "pop in": start small and invisible, scale up
foreach (var cell in _boardView.GetChildren())
{
if (cell is CellView cv)
{
cv.Modulate = new Color(1, 1, 1, 0);
cv.Scale = new Vector2(0.6f, 0.6f);
var t = cv.CreateTween();
t.SetParallel(true);
t.TweenProperty(cv, "modulate:a", 1f, 0.45f);
t.TweenProperty(cv, "scale", Vector2.One, 0.45f)
.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Back);
}
}
// 2. Smooth camera pan + zoom to new board center
var targetPos = new Vector2(
snap.Width * BoardView.CellSize / 2f,
-snap.Height * BoardView.CellSize / 2f + BoardView.CellSize);
var camTween = CreateTween();
camTween.SetParallel(true);
camTween.TweenProperty(_camera, "position", targetPos, 0.7f)
.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Sine);
camTween.TweenProperty(_camera, "offset",
new Vector2(SidePanelWidth / 2f, (ControlBarHeight - TitleBarHeight) / 2f), 0.7f);
// Reset zoom in case we were zoomed in from a collision event
camTween.TweenProperty(_camera, "zoom", Vector2.One, 0.7f)
.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Sine);
// 3. Title overlay — "Mission N: Name" big fade-in then slide-out
ShowMissionTitleOverlay(mission, snap);
}
private void ShowMissionTitleOverlay(MissionDef mission, BoardSnapshot snap)
{
var missionNum = snap.Campaign!.CurrentMissionIndex + 1;
var label = new Label
{
Text = $"Mission {missionNum}\n{mission.Name}",
MouseFilter = Control.MouseFilterEnum.Ignore,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
label.AddThemeFontSizeOverride("font_size", 38);
label.AddThemeColorOverride("font_color", new Color("#FFE8D0"));
label.AddThemeColorOverride("font_outline_color", new Color(0, 0, 0, 0.9f));
label.AddThemeConstantOverride("outline_size", 8);
label.SetAnchorsPreset(Control.LayoutPreset.FullRect);
label.OffsetRight = -SidePanelWidth;
label.OffsetBottom = -ControlBarHeight;
label.Modulate = new Color(1, 1, 1, 0);
_uiLayer.AddChild(label);
var tween = label.CreateTween();
tween.TweenProperty(label, "modulate:a", 1f, 0.4f);
tween.TweenInterval(1.4f);
tween.TweenProperty(label, "modulate:a", 0f, 0.6f);
tween.TweenCallback(Callable.From(() => label.QueueFree()));
}
// --- Navigation --- // --- Navigation ---
private void OnBackToMenu() private void OnBackToMenu()

View file

@ -12,10 +12,6 @@ et l'extension de la campagne.
Le moteur expose deja les commandes et events requis ; cote Godot il manque Le moteur expose deja les commandes et events requis ; cote Godot il manque
les surfaces d'interaction et d'animation. les surfaces d'interaction et d'animation.
### 1.4 Touche Suppr pour retirer une piece
Le bouton `[Retirer]` du `DetailPanel` existe. Ajouter en complement :
selection + `Delete` → meme effet que le bouton.
### 1.5 Cinematique de transition de mission ### 1.5 Cinematique de transition de mission
Sur `MissionStartedEvent` (hors mission 0) : Sur `MissionStartedEvent` (hors mission 0) :
- Titre "Nouvelle mission" plein ecran en fade-in. - Titre "Nouvelle mission" plein ecran en fade-in.