Animare su un percorso arbitrario

Sempre nella pagina Learn di JavaFX.com, sezione animazione, passo all'articolo Animation Along an Arbitrary Path di Peter Zhelezniakov.

Si tratta qui dell'uso della classe javafx.animation.transition.PathTransition che permette una delle transizioni più sofisticate tra quelle disponibili in JavaFX. Nonostante ciò é anche una classe facile da usare: si crea un percorso, un oggetto che lo deve percorrere, li si passa alla PathTransition che fornisce la logica per l'animazione.

Il codice completo sviluppato da Peter viene messo a disposizione qui. Teniamolo da traccia e sviluppiamo passo dopo passo l'applicazione.

Il risultato finale viene mostrato qui.

Finestra principale

Peter ha evidentemente un profondo background in java, e la strutturazione del suo codice lo riflette. La cosa più evidente é che Peter, invece di lasciare a JavaFX il compito di interpolare la funzione run() da chiamare al momento dell'esecuzione, creando lo stage e le funzioni solitamente sparse nello script, preferisce esplicitarla. Seguiamo volentieri la sua impostazione, creandoci lo stage e la scena in questo modo:

package pathanim;

import javafx.stage.Stage;
import javafx.scene.Scene;

function run(): Void {
Stage {
title: "Path Animation"
scene: Scene {
width: 400, height: 300
}
};
}

Oggetto animato

Creamo un oggetto che faremo muovere lungo un percorso:

import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

def bar1 = Rectangle {
width: 5, height: 50
fill: Color.RED
};

Il percorso

E questo é il percorso che vogliamo che il nostro oggetto segua:

import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;

def track1 = Path {
stroke: Color.BLUE
strokeWidth: 4
elements: [
MoveTo { x: 50, y: 100 },
CubicCurveTo {
controlX1: 100, controlY1: -50
controlX2: 300, controlY2: 250
x: 350, y: 100
}
]
};

Specifichiamo il punto iniziale con MoveTo, e poi il percorso é la cubica definita da CubicCurveTo.

L'animazione

Ci pensa PathTransition ad associare oggetto a percorso, usando i parametri passati per definire le modalità dell'animazione:

def anim1 = PathTransition {
node: bar1
path: AnimationPath.createFromPath(track1)
orientation: OrientationType.NONE
interpolator: Interpolator.LINEAR
duration: 5s
repeatCount: Timeline.INDEFINITE
};

Come orientamento abbiamo specificato OrientationType.NONE che é il default e che significa che l'oggetto si muove lungo il percorso senza cambiare orientamento. Più interessante é OrientationType.ORTHOGONAL_TO_TANGENT, in cui l'oggetto trasla come farebbe chiunque seguendo un percorso, seguendo il proprio naso. Il secondo oggetto sul secondo percorso (vedi codice completo più sotto) segue appunto questa modalità.

Esecuzione

Aggiorniamo la funzione run() in modo da mettere sulla scena i nostri oggetti e far partire l'animazione:

function run(): Void {
Stage {
title: "Path Animation"
scene: Scene {
width: 400, height: 300
content: [ track1, bar1 ]
}
};

anim1.play();
}

Codice completo

Nel codice completo raddoppiamo gli oggetti in scena:

package pathanim;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.transition.AnimationPath;
import javafx.animation.transition.OrientationType;
import javafx.animation.transition.PathTransition;
import javafx.scene.paint.Color;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;

def bar1 = Rectangle {
width: 5, height: 50
fill: Color.RED
};

def bar2 = Rectangle {
width: 5, height: 50
fill: Color.BLUE
};

def track1 = Path {
stroke: Color.BLUE
strokeWidth: 4
elements: [
MoveTo { x: 50, y: 100 },
CubicCurveTo {
controlX1: 100, controlY1: -50
controlX2: 300, controlY2: 250
x: 350, y: 100
}
]
};

def track2 = Path {
stroke: Color.RED
strokeWidth: 4
elements: [
MoveTo { x: 50, y: 200 },
CubicCurveTo {
controlX1: 100, controlY1: 50
controlX2: 300, controlY2: 350
x: 350, y: 200
}
]
};

def anim1 = PathTransition {
node: bar1
path: AnimationPath.createFromPath(track1)
orientation: OrientationType.NONE
interpolator: Interpolator.LINEAR
duration: 5s
repeatCount: Timeline.INDEFINITE
};

def anim2 = PathTransition {
node: bar2
path: AnimationPath.createFromPath(track2)
orientation: OrientationType.ORTHOGONAL_TO_TANGENT
interpolator: Interpolator.LINEAR
duration: 5s
repeatCount: Timeline.INDEFINITE
};

function run(): Void {
Stage {
title: "Path Animation"
scene: Scene {
width: 400, height: 300
content: [ track1, track2, bar1, bar2 ]
}
};

anim1.play();
anim2.play();
}

Nessun commento:

Posta un commento