Voir le flux RSS

bouye

[Actualité] Faire tourner les cartes - partie 2

Noter ce billet
par , 20/01/2015 à 00h50 (1972 Affichages)
Enfin de retour ! L’été bat son plein ici et j'avais décidé de prendre 15 jours de congés après le break des fêtes de fin d’année pour me détendre. Mais bon toutes les bonnes choses ont une fin et ce n'est pas plus mal car il pleut désormais à verse depuis hier (une dépression tropicale est proche).

Dans l’entrée précédente, nous avons vu comment simuler la rotation d'une carte sur elle même en utilisant une transformation de mise à l’échelle. Bien que n’étant pas graphiquement très réaliste, cette manière de faire à l'avantage d’être en 2D et de ne pas demander beaucoup de puissance.

Aujourd'hui, nous allons rester en 2D mais nous allons être amené à utiliser une transformation (ou plutôt, dans ce cas, un effet) plus réaliste : une transformation de perspective en utilisant la classe PerspectiveTransform. Cet effet créant une transformation qui n'est pas affine, il est plus gourmand en puissance graphique et de calcul et peut demander également plus de mémoire.

Il s'agit d'un effet graphique qui prend les 4 coins d'un nœud et les déplace aux coordonnées désignées, déformant ainsi le contenu du nœud (dans notre cas une instance d'ImageView).

Nom : perspective.png
Affichages : 1151
Taille : 20,6 Ko

L'image s’inscrit dans une boite englobante rectangulaire qui contient 4 sommets :
  • UL - le coin supérieur gauche (Upper Left).
  • UR - le coin supérieur droit (Upper Right).
  • LL - le coin inférieur gauche (Lower Left).
  • LR - le coin inférieur droit (Lower Right).


Nous allons leur appliquer une modification d'enveloppe : c'est à dire que nous allons déplacer les coordonnées de ces 4 points en spécifiant une quadrilatère défini par les coordonnées destination des 4 sommets. Quand la transformation est appliquée, l'image s'en trouve modifiée et a une apparence déformée. C'est là le principe de l'effet de perspective.

Note : ici nous effectuons la rotation sur des instances d'ImageView. Mais on pourrait tout aussi bien le faire sur des contrôles interactif (ce qui était le but initial du poseur de la question sur OTN). Or, la transformation correcte des coordonnées des événements souris n'est pas garantie lors que l'effet PerspectiveTransformest utilisé. Mieux vaudra donc désactiver toute saisie utilisateur durant l'animation du passage d'un contrôle à un autre pour ensuite les réactiver lorsque l'animation est terminée.


Nom : Cards-perspective.jpg
Affichages : 1339
Taille : 18,0 Ko
Une fausse animation en utilisant un effet de perspective.

Ici, il ne s'agit pas non-plus d'une vraie rotation de la carte sur elle-même. Nous utilisons simplement un effet graphique qui donne l'impression que la rotation a lieu.

Lors du passage de 0° à 90°, l'enveloppe de la transformation de la face avant est modifiée de manière à ce que UL, UR, LL et LR soient alignés sur une seule et même ligne verticale.

Nom : perspective-effect.png
Affichages : 1188
Taille : 9,7 Ko
Les déplacement des 4 sommets à 0°, 45° et 90° (face avant).

Lors du passage de 90° à 180°, l'enveloppe de la transformation de la face arrière est modifiée de manière à ce que UL, UR, LL et LR, qui initialement étaient alignés sur une seule et même ligne verticale, reprennent leur positions d'origine pour afficher afficher la carte de face.

Nom : perspective-effect2.png
Affichages : 1159
Taille : 8,2 Ko
Les déplacement des 4 sommets à 90°, 135° et 180° (face arrière).

Le déplacement de chacun des 4 points s'effectue de manière linéaire ; il n'y a pas besoin de s’embêter à essayer de calculer un déplacement en suivant une courbe pour tenter de simuler la perspective : l'animation étant rapide, elle est déjà suffisante en soit pour tromper l’œil.

Tout d'abord, nous allons définir une variable offset qui va contenir le décalage verticale maximal de la perspective et, ici, lui donner une valeur de 10 pixels.

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
private final double offset = 10;

Initialisons ensuite nos instances d'ImageView en leur donnant à chacune un effet graphique de type PerspectiveTransform :

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
final ImageView frontCard = new ImageView(sourceImage);
frontCard.setViewport(new Rectangle2D(0, 286, 98, 143));
final PerspectiveTransform frontPerspective = new PerspectiveTransform(0, 0, 98, 0, 98, 143, 0, 143);
frontCard.setEffect(frontPerspective);
//
final ImageView backCard = new ImageView(sourceImage);
backCard.setViewport(new Rectangle2D(197, 572, 98, 143));
final PerspectiveTransform backPerspective = new PerspectiveTransform(98 / 2d, -offset, 98 / 2d, offset, 98 / 2d, 143 - offset, 98 / 2d, 143 + offset);
backCard.setEffect(backPerspective);

Ici, l'enveloppe de la face avant de la carte n'est pas modifiée (on voit donc l'as de face) tandis que tous les points du dos sont alignés sur une même ligne verticale (on ne voit donc pas cette face).

Une fois de plus, pour rendre la chose plus aisément compréhensible, nous allons découper l'animation en plusieurs sous-parties. Ce n'est pas forcement la manière la plus optimisée de faire, mais cela rend le code moins complexe à saisir.

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
final SequentialTransition animation = new SequentialTransition(
        flip(98, 143, frontCard, frontPerspective, backCard, backPerspective),
        flip(98, 143, backCard, backPerspective, frontCard, frontPerspective));
animation.setCycleCount(SequentialTransition.INDEFINITE);

Nous implémentons maintenant la méthode flip() pour animer séparément chaque face. Ici, nous allons créer une Timeline qui permettra d'animer chaque point de l'enveloppe. À chaque KeyFrame (étape clé de l’animation) nous avons 4 points avec 2 coordonnées X et Y par point = 8 valeurs à spécifier.

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private Transition flip(double width, double height, Node front, PerspectiveTransform frontPerspective, Node back, PerspectiveTransform backPerspective) {
    final Timeline perspectiveOutFront = new Timeline(
            new KeyFrame(Duration.ZERO,
                    new KeyValue(frontPerspective.ulxProperty(), 0),
                    new KeyValue(frontPerspective.ulyProperty(), 0),
                    new KeyValue(frontPerspective.urxProperty(), width),
                    new KeyValue(frontPerspective.uryProperty(), 0),
                    new KeyValue(frontPerspective.lrxProperty(), width),
                    new KeyValue(frontPerspective.lryProperty(), height),
                    new KeyValue(frontPerspective.llxProperty(), 0),
                    new KeyValue(frontPerspective.llyProperty(), height)
            ),
            new KeyFrame(halfFlipDuration,
                    new KeyValue(frontPerspective.ulxProperty(), width / 2d),
                    new KeyValue(frontPerspective.ulyProperty(), offset),
                    new KeyValue(frontPerspective.urxProperty(), width / 2d),
                    new KeyValue(frontPerspective.uryProperty(), -offset),
                    new KeyValue(frontPerspective.lrxProperty(), width / 2d),
                    new KeyValue(frontPerspective.lryProperty(), height + offset),
                    new KeyValue(frontPerspective.llxProperty(), width / 2d),
                    new KeyValue(frontPerspective.llyProperty(), height - offset)
            ));
    //
    final Timeline perspectiveInBack = new Timeline(
            new KeyFrame(Duration.ZERO,
                    new KeyValue(backPerspective.ulxProperty(), width / 2d),
                    new KeyValue(backPerspective.ulyProperty(), -offset),
                    new KeyValue(backPerspective.urxProperty(), width / 2d),
                    new KeyValue(backPerspective.uryProperty(), offset),
                    new KeyValue(backPerspective.lrxProperty(), width / 2d),
                    new KeyValue(backPerspective.lryProperty(), height - offset),
                    new KeyValue(backPerspective.llxProperty(), width / 2d),
                    new KeyValue(backPerspective.llyProperty(), height + offset)
            ),
            new KeyFrame(halfFlipDuration,
                    new KeyValue(backPerspective.ulxProperty(), 0),
                    new KeyValue(backPerspective.ulyProperty(), 0),
                    new KeyValue(backPerspective.urxProperty(), width),
                    new KeyValue(backPerspective.uryProperty(), 0),
                    new KeyValue(backPerspective.lrxProperty(), width),
                    new KeyValue(backPerspective.lryProperty(), height),
                    new KeyValue(backPerspective.llxProperty(), 0),
                    new KeyValue(backPerspective.llyProperty(), height)
            ));
 
    //
    return new SequentialTransition(perspectiveOutFront, perspectiveInBack);
}

Et nous répétons ces mêmes animations en inversant les faces des cartes pour l'animation de 180° a 360°.

Voici le code complet du test :

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package test;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToolBar;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Test_D2Perspective1 extends Application {

    private final Duration halfFlipDuration = Duration.seconds(1);

    private final double offset = 10;

    @Override
    public void start(Stage primaryStage) {
        final Image sourceImage = new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Svg-cards-2.0.svg/1280px-Svg-cards-2.0.svg.png");
        //
        final ImageView frontCard = new ImageView(sourceImage);
        frontCard.setViewport(new Rectangle2D(0, 286, 98, 143));
        final PerspectiveTransform frontPerspective = new PerspectiveTransform(0, 0, 98, 0, 98, 143, 0, 143);
        frontCard.setEffect(frontPerspective);
        //
        final ImageView backCard = new ImageView(sourceImage);
        backCard.setViewport(new Rectangle2D(197, 572, 98, 143));
        final PerspectiveTransform backPerspective = new PerspectiveTransform(98 / 2d, -offset, 98 / 2d, offset, 98 / 2d, 143 - offset, 98 / 2d, 143 + offset);
        backCard.setEffect(backPerspective);
        //
        final StackPane stackPane = new StackPane();
        stackPane.getChildren().addAll(frontCard, backCard);
        final ToggleButton playButton = new ToggleButton("Play");
        StackPane.setAlignment(playButton, Pos.TOP_LEFT);
        final Slider timeSlider = new Slider(0, 4 * halfFlipDuration.toMillis(), 0);
        timeSlider.setDisable(true);
        final ToolBar toolBar = new ToolBar();
        toolBar.getItems().addAll(playButton, timeSlider);
        final BorderPane root = new BorderPane();
        root.setTop(toolBar);
        root.setCenter(stackPane);
        final Scene scene = new Scene(root, 300, 250);
        primaryStage.setTitle("2D: perspective");
        primaryStage.setScene(scene);
        primaryStage.show();
        //
        final SequentialTransition animation = new SequentialTransition(
                flip(98, 143, frontCard, frontPerspective, backCard, backPerspective),
                flip(98, 143, backCard, backPerspective, frontCard, frontPerspective));
        animation.setCycleCount(SequentialTransition.INDEFINITE);
        playButton.selectedProperty().addListener((observableValue, oldValue, newValue) -> {
            if (newValue) {
                animation.play();
            } else {
                animation.pause();
            }
        });
        timeSlider.valueProperty().bind(new DoubleBinding() {
            {
                bind(animation.currentTimeProperty());
            }

            @Override
            public void dispose() {
                super.dispose();
                unbind(animation.currentTimeProperty());
            }

            @Override
            protected double computeValue() {
                return animation.getCurrentTime().toMillis();
            }
        });
    }

    private Transition flip(double width, double height, Node front, PerspectiveTransform frontPerspective, Node back, PerspectiveTransform backPerspective) {
        final Timeline perspectiveOutFront = new Timeline(
                new KeyFrame(Duration.ZERO,
                        new KeyValue(frontPerspective.ulxProperty(), 0),
                        new KeyValue(frontPerspective.ulyProperty(), 0),
                        new KeyValue(frontPerspective.urxProperty(), width),
                        new KeyValue(frontPerspective.uryProperty(), 0),
                        new KeyValue(frontPerspective.lrxProperty(), width),
                        new KeyValue(frontPerspective.lryProperty(), height),
                        new KeyValue(frontPerspective.llxProperty(), 0),
                        new KeyValue(frontPerspective.llyProperty(), height)
                ),
                new KeyFrame(halfFlipDuration,
                        new KeyValue(frontPerspective.ulxProperty(), width / 2d),
                        new KeyValue(frontPerspective.ulyProperty(), offset),
                        new KeyValue(frontPerspective.urxProperty(), width / 2d),
                        new KeyValue(frontPerspective.uryProperty(), -offset),
                        new KeyValue(frontPerspective.lrxProperty(), width / 2d),
                        new KeyValue(frontPerspective.lryProperty(), height + offset),
                        new KeyValue(frontPerspective.llxProperty(), width / 2d),
                        new KeyValue(frontPerspective.llyProperty(), height - offset)
                ));
        //
        final Timeline perspectiveInBack = new Timeline(
                new KeyFrame(Duration.ZERO,
                        new KeyValue(backPerspective.ulxProperty(), width / 2d),
                        new KeyValue(backPerspective.ulyProperty(), -offset),
                        new KeyValue(backPerspective.urxProperty(), width / 2d),
                        new KeyValue(backPerspective.uryProperty(), offset),
                        new KeyValue(backPerspective.lrxProperty(), width / 2d),
                        new KeyValue(backPerspective.lryProperty(), height - offset),
                        new KeyValue(backPerspective.llxProperty(), width / 2d),
                        new KeyValue(backPerspective.llyProperty(), height + offset)
                ),
                new KeyFrame(halfFlipDuration,
                        new KeyValue(backPerspective.ulxProperty(), 0),
                        new KeyValue(backPerspective.ulyProperty(), 0),
                        new KeyValue(backPerspective.urxProperty(), width),
                        new KeyValue(backPerspective.uryProperty(), 0),
                        new KeyValue(backPerspective.lrxProperty(), width),
                        new KeyValue(backPerspective.lryProperty(), height),
                        new KeyValue(backPerspective.llxProperty(), 0),
                        new KeyValue(backPerspective.llyProperty(), height)
                ));

        //
        return new SequentialTransition(perspectiveOutFront, perspectiveInBack);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Une fois de plus, nous pouvons également utiliser un effet de changement de couleur pour simuler l'assombrissement des faces de manière à rendre la fausse rotation plus réaliste :

Nom : Cards-perspective2.jpg
Affichages : 1122
Taille : 17,3 Ko

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package test;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.ParallelTransition;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToolBar;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Test_D2Perspective2 extends Application {

    private final Duration halfFlipDuration = Duration.seconds(1);

    private final double offset = 10;

    @Override
    public void start(Stage primaryStage) {
        final Image sourceImage = new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Svg-cards-2.0.svg/1280px-Svg-cards-2.0.svg.png");
        //
        final ImageView frontCard = new ImageView(sourceImage);
        frontCard.setViewport(new Rectangle2D(0, 286, 98, 143));
        final PerspectiveTransform frontPerspective = new PerspectiveTransform(0, 0, 98, 0, 98, 143, 0, 143);
        frontCard.setEffect(frontPerspective);
        final ColorAdjust frontColorAdjust = new ColorAdjust();
        frontPerspective.setInput(frontColorAdjust);
        //
        final ImageView backCard = new ImageView(sourceImage);
        backCard.setViewport(new Rectangle2D(197, 572, 98, 143));
        final PerspectiveTransform backPerspective = new PerspectiveTransform(98 / 2d, -offset, 98 / 2d, offset, 98 / 2d, 143 - offset, 98 / 2d, 143 + offset);
        backCard.setEffect(backPerspective);
        final ColorAdjust backColorAdjust = new ColorAdjust();
        backPerspective.setInput(backColorAdjust);
        //
        final StackPane stackPane = new StackPane();
        stackPane.getChildren().addAll(frontCard, backCard);
        final ToggleButton playButton = new ToggleButton("Play");
        StackPane.setAlignment(playButton, Pos.TOP_LEFT);
        final Slider timeSlider = new Slider(0, 4 * halfFlipDuration.toMillis(), 0);
        timeSlider.setDisable(true);
        final ToolBar toolBar = new ToolBar();
        toolBar.getItems().addAll(playButton, timeSlider);
        final BorderPane root = new BorderPane();
        root.setTop(toolBar);
        root.setCenter(stackPane);
        final Scene scene = new Scene(root, 300, 250);
        primaryStage.setTitle("2D: perspective + shadow");
        primaryStage.setScene(scene);
        primaryStage.show();
        //
        final SequentialTransition animation = new SequentialTransition(
                flip(98, 143, frontCard, frontPerspective, frontColorAdjust, backCard, backPerspective, backColorAdjust),
                flip(98, 143, backCard, backPerspective, backColorAdjust, frontCard, frontPerspective, frontColorAdjust));
        animation.setCycleCount(SequentialTransition.INDEFINITE);
        playButton.selectedProperty().addListener((observableValue, oldValue, newValue) -> {
            if (newValue) {
                animation.play();
            } else {
                animation.pause();
            }
        });
        timeSlider.valueProperty().bind(new DoubleBinding() {
            {
                bind(animation.currentTimeProperty());
            }

            @Override
            public void dispose() {
                super.dispose();
                unbind(animation.currentTimeProperty());
            }

            @Override
            protected double computeValue() {
                return animation.getCurrentTime().toMillis();
            }
        });
    }

    private Transition flip(double width, double height, Node front, PerspectiveTransform frontPerspective, ColorAdjust frontColorAdjust, Node back, PerspectiveTransform backPerspective, ColorAdjust backColorAdjust) {
        final Timeline perspectiveOutFront = new Timeline(
                new KeyFrame(Duration.ZERO,
                        new KeyValue(frontPerspective.ulxProperty(), 0),
                        new KeyValue(frontPerspective.ulyProperty(), 0),
                        new KeyValue(frontPerspective.urxProperty(), width),
                        new KeyValue(frontPerspective.uryProperty(), 0),
                        new KeyValue(frontPerspective.lrxProperty(), width),
                        new KeyValue(frontPerspective.lryProperty(), height),
                        new KeyValue(frontPerspective.llxProperty(), 0),
                        new KeyValue(frontPerspective.llyProperty(), height)
                ),
                new KeyFrame(halfFlipDuration,
                        new KeyValue(frontPerspective.ulxProperty(), width / 2d),
                        new KeyValue(frontPerspective.ulyProperty(), offset),
                        new KeyValue(frontPerspective.urxProperty(), width / 2d),
                        new KeyValue(frontPerspective.uryProperty(), -offset),
                        new KeyValue(frontPerspective.lrxProperty(), width / 2d),
                        new KeyValue(frontPerspective.lryProperty(), height + offset),
                        new KeyValue(frontPerspective.llxProperty(), width / 2d),
                        new KeyValue(frontPerspective.llyProperty(), height - offset)
                ));
        final Timeline changeBrightnessFront = new Timeline(
                new KeyFrame(Duration.ZERO, new KeyValue(frontColorAdjust.brightnessProperty(), 0)),
                new KeyFrame(halfFlipDuration, new KeyValue(frontColorAdjust.brightnessProperty(), -1)));
        final ParallelTransition flipOutFront = new ParallelTransition(perspectiveOutFront, changeBrightnessFront);
        //
        final Timeline perspectiveInBack = new Timeline(
                new KeyFrame(Duration.ZERO,
                        new KeyValue(backPerspective.ulxProperty(), width / 2d),
                        new KeyValue(backPerspective.ulyProperty(), -offset),
                        new KeyValue(backPerspective.urxProperty(), width / 2d),
                        new KeyValue(backPerspective.uryProperty(), offset),
                        new KeyValue(backPerspective.lrxProperty(), width / 2d),
                        new KeyValue(backPerspective.lryProperty(), height - offset),
                        new KeyValue(backPerspective.llxProperty(), width / 2d),
                        new KeyValue(backPerspective.llyProperty(), height + offset)
                ),
                new KeyFrame(halfFlipDuration,
                        new KeyValue(backPerspective.ulxProperty(), 0),
                        new KeyValue(backPerspective.ulyProperty(), 0),
                        new KeyValue(backPerspective.urxProperty(), width),
                        new KeyValue(backPerspective.uryProperty(), 0),
                        new KeyValue(backPerspective.lrxProperty(), width),
                        new KeyValue(backPerspective.lryProperty(), height),
                        new KeyValue(backPerspective.llxProperty(), 0),
                        new KeyValue(backPerspective.llyProperty(), height)
                ));
        final Timeline changeBrightnessBack = new Timeline(
                new KeyFrame(Duration.ZERO, new KeyValue(backColorAdjust.brightnessProperty(), -1)),
                new KeyFrame(halfFlipDuration, new KeyValue(backColorAdjust.brightnessProperty(), 0)));
        final ParallelTransition flipInBack = new ParallelTransition(perspectiveInBack, changeBrightnessBack);
        //
        return new SequentialTransition(flipOutFront, flipInBack);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Ici, j'ai créé des instances de Timeline séparées pour gérer la perspective et le changement de couleur mais, bien sûr, il est tout a fait possible de rajouter les instances de KeyFrame dans une seule et unique ligne temporelle.

Voila, c'est tout pour cette fois, lors du prochain billet, nous laisserons de coté la 2D et nous attaquerons enfin la 3D !

Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Viadeo Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Twitter Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Google Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Facebook Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Digg Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Delicious Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog MySpace Envoyer le billet « Faire tourner les cartes - partie 2 » dans le blog Yahoo

Mis à jour 20/01/2015 à 22h31 par bouye

Tags: carte
Catégories
Java , Java , JavaFX

Commentaires

  1. Avatar de kolodz
    • |
    • permalink
    Merci pour ce tutoriel très instructif.

    A noté que tu utilise une expressions lambda, ce qui fait qu'il est nécessaire d'être en Java 8.

    Si l'application n'as pas accès à internet, il est aussi possible de remplacer l'url de l'image par :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    final Image sourceImage = new Image("file:1280px-Svg-cards-2.0.svg.png");
    Si celle-ci se trouve à la racine de votre projet/dossier de travail.

    La carte affiché est sélectionné avec :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    frontCard.setViewport(new Rectangle2D(0, 286, 98, 143));
    A noter que certains cartes ont un pixel en commun pour avoir des "jolis" bord.
    Il serai possible d'accèder au cartes de cette manière :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    frontCard.setViewport(new Rectangle2D((98*(numeroCarte-1)), (143*idCouleur), 98, 143));

    Cordialement,
    Patrick Kolodziejczyk.

    Ps : Tu as laissé échappé une balise :
    [codeinline]Timeline[codeinline]
    Tu peux, aussi, utilise la balise [c] qui est un alias.
  2. Avatar de bouye
    • |
    • permalink
    C'est corrigé, merci.

    Pour le reste, souviens toi que le but est de faire un exemple clair et rapidement compréhensible, pas forcement "du mieux/plus joli possible", d’où le fait que certaines constantes soient écrites en dur et beaucoup d’améliorations sont possibles (ex : on gagnerait beaucoup en flexibilité mais on perdrait également beaucoup en lisibilité en ayant qu'une seule et unique Timeline).

    La FAQ JavaFX indique aux gens les différentes modalités de chargement des images en ligne comme hors ligne.

    Pour ce qui est du code, sauf besoin spécifiques, je ne posterai plus de code événementiel au format Java1-7. La transformation de code 8 en code antérieur est de toute manière assez simple à effectuer pour peu qu'on connaisse les classes de l'API (ici encore, j'ai souvent mis les deux manières de faire cote à cote dans mes didacticiels ou dans la FAQ).
  3. Avatar de kolodz
    • |
    • permalink
    C'est juste moi qui voulais avoir un poste qui a un peu plus de consistance que "Tu as une balise visible" ^^