Add bidirectional arrows and idle pulsation on piece trajectories

TrajectView now draws an arrow at each endpoint (since pieces oscillate
between start and end, both directions are relevant) and runs a looped
width/alpha tween that breathes between 0.3 and 0.75 over ~2.2s. The
pulse makes stationary relays visually distinct from static board art
without competing with active cargo/particle animations.
This commit is contained in:
Samuel Bouchet 2026-04-17 22:31:56 +02:00
parent 1d0999a78e
commit 480c783bd6
3 changed files with 57 additions and 22 deletions

View file

@ -5,34 +5,54 @@ namespace Chessistics.Scripts.Pieces;
public partial class TrajectView : Line2D
{
public int PieceId { get; private set; }
private Polygon2D? _arrow;
private Polygon2D? _arrowEnd;
private Polygon2D? _arrowStart;
private Tween? _pulseTween;
private Color _baseColor;
public void Setup(int pieceId, Vector2 from, Vector2 to, Color color)
{
PieceId = pieceId;
Width = 2.5f;
DefaultColor = new Color(color, 0.35f);
_baseColor = color;
Width = 3f;
DefaultColor = new Color(color, 0.4f);
Antialiased = true;
ClearPoints();
AddPoint(from);
AddPoint(to);
ZIndex = -1;
// Arrowhead at the end point
_arrowEnd = BuildArrow(from, to, color);
_arrowStart = BuildArrow(to, from, color);
AddChild(_arrowEnd);
AddChild(_arrowStart);
StartPulse();
}
private static Polygon2D BuildArrow(Vector2 from, Vector2 to, Color color)
{
var dir = (to - from).Normalized();
var perp = new Vector2(-dir.Y, dir.X);
float arrowSize = 8f;
var tip = to - dir * 4f; // slightly inset from end
const float arrowSize = 9f;
var tip = to - dir * 4f;
var baseL = tip - dir * arrowSize + perp * arrowSize * 0.5f;
var baseR = tip - dir * arrowSize - perp * arrowSize * 0.5f;
_arrow = new Polygon2D
return new Polygon2D
{
Polygon = [tip - Position, baseL - Position, baseR - Position],
Color = new Color(color, 0.4f),
Position = Vector2.Zero
Polygon = [tip, baseL, baseR],
Color = new Color(color, 0.5f)
};
// Position relative to parent, not this Line2D
AddChild(_arrow);
}
private void StartPulse()
{
_pulseTween?.Kill();
_pulseTween = CreateTween();
_pulseTween.SetLoops();
_pulseTween.TweenProperty(this, "default_color:a", 0.75f, 1.1f)
.SetEase(Tween.EaseType.InOut).SetTrans(Tween.TransitionType.Sine);
_pulseTween.TweenProperty(this, "default_color:a", 0.3f, 1.1f)
.SetEase(Tween.EaseType.InOut).SetTrans(Tween.TransitionType.Sine);
}
}

View file

@ -12,15 +12,6 @@ et l'extension de la campagne.
Le moteur expose deja les commandes et events requis ; cote Godot il manque
les surfaces d'interaction et d'animation.
### 1.5 Cinematique de transition de mission
Sur `MissionStartedEvent` (hors mission 0) :
- Titre "Nouvelle mission" plein ecran en fade-in.
- Lock pan/zoom ; la camera se deplace vers la nouvelle zone.
- Animation d'expansion pour les cases debloquees par le `TerrainPatch`.
- Le titre glisse ensuite vers le panneau d'objectifs avant de disparaitre
(guide l'oeil).
- Unlock pan/zoom, la simulation reprend.
### 1.6 Visualisation des trajets
`TrajectView` existe. Manque :
- Fleches directionnelles sur le trait.

View file

@ -0,0 +1,24 @@
"""Visual smoke for trajectory arrows + pulsation."""
import sys, time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from tools.automation.harness import Harness
def main():
with Harness.launch(run_name="trajectory") as h:
h.load_mission("campaign_01", 0)
h.place("Pawn", (0, 1), (1, 1))
h.place("Pawn", (2, 1), (3, 1))
# Capture two frames at different phases of the pulse loop
h.screenshot("01_placed_a")
time.sleep(0.8)
h.screenshot("02_placed_b_pulse")
print("OK — trajectories rendered; see screens for arrows + pulse")
if __name__ == "__main__":
main()