IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaFX Discussion :

Modifier le temps d'une animation (Timeline + Interpolator)


Sujet :

JavaFX

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 56
    Points : 53
    Points
    53
    Par défaut Modifier le temps d'une animation (Timeline + Interpolator)
    Salut !
    J'ai lu récemment un petit cours sur JAVAFX, et je voudrai faire une petite application pour m'exercer et assimiler la chose.
    Je voudrai faire un petit jeu 2D, ou l'on fasse animer une balle afin qu'elle suit un chemin parabolique (la trajectoire d'une balle de tennis par exemple )
    J'utilise pour cela un objet Timeline avec un Interpolator.
    J'avoue je ne comprends pas vraiment comment marche l'objet Interpolator, mon problème réside dans le fait que je voudrai faire en sorte qu'au moment ou la balle arrive tout en bas de la fenêtre l'animation s'arrête.

    J'ai pensé à utiliser deux méthode:
    -La première consiste à arrêter l'animation une fois que la coordonnée Y du centre de la balle (Circle) atteigne la largeur de la fenêtre, sauf que j'ai aucune idée de comment faire
    -La deuxième consiste à arrêter l'animation à un certain moment ' Tf ', j'ai une petite formule qui me permet de savoir à quel temps la coordonnée Y atteigne l'endroit voulu, par contre je ne sais pas non plu comment définir le temps maximal d'un Timeline.

    Ça serait sympa que vous m'expliquiez comment faire pour les deux méthodes
    Voici un petit code de ce que j'ai fait
    Code : 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
     
            Timeline t1 = new Timeline();
            t1.setAutoReverse(false);
            t1.setCycleCount(Timeline.INDEFINITE);
            t1.getKeyFrames().addAll(
                new KeyFrame(new Duration(1000 * Tf),new KeyValue(this.centerXProperty(),0,new Interpolator(){
                    protected double curve(double t){
                        double resultat = coeffAngleX * t;
                        return - resultat;
                    }
                })),
                new KeyFrame(new Duration(1000 * Tf),new KeyValue(this.centerYProperty(),0,new Interpolator(){
                    protected double curve(double t) {
                        double resultat = (a * t * t)
                                 + (coeffAngleY * t);
                        return resultat;
                    }
                }))
            );
    Merci d'avance, Cordialement Mouley.

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    L'interpolator sert généralement a faire varier la valeur animée (x, y, echelle, rotation) de manière lineraire ou non-linéaire durant un même temps constant d'animation pour donner l'illusion qu'on a quelque chose de différent (alors qu'on a la même valeur source, la même valeur destination et surtout le même temps d'animation). En général, comme on modifie des variables de positionnement dans l'espace (x, y, rotation, échelle), cela a pour effet de donner a l’impression au spectateur que c'est la vitesse de l'animation qui va changer et que le mouvement est naturel ou au contraire artificiel (ex: le mouvement de l'objet accélère ou ralentit).

    Code : 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
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    package interpolator;
     
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import javafx.animation.FadeTransition;
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.animation.Interpolator;
    import javafx.animation.ParallelTransition;
    import javafx.animation.PauseTransition;
    import javafx.animation.RotateTransition;
    import javafx.animation.SequentialTransition;
    import javafx.animation.Transition;
    import javafx.animation.TranslateTransition;
    import javafx.application.Platform;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Node;
    import javafx.scene.chart.Chart;
    import javafx.scene.chart.LineChart;
    import javafx.scene.chart.NumberAxis;
    import javafx.scene.control.Label;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.FlowPane;
    import javafx.scene.layout.StackPane;
    import javafx.scene.layout.VBox;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Circle;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    import javafx.stage.StageStyle;
    import javafx.util.Duration;
     
    public class Main extends Application {
     
        @Override
        public void start(final Stage primaryStage) {
            final Interpolator[] interpolators = {Interpolator.LINEAR, Interpolator.EASE_IN, Interpolator.EASE_OUT, Interpolator.EASE_BOTH, Interpolator.DISCRETE};
            final int side = 50;
            final Duration animationDuration = Duration.seconds(3);
            final List<Transition> animationList = new ArrayList<>();
            final FlowPane demoFlow1 = new FlowPane();
            demoFlow1.getChildren().addAll(Arrays.stream(interpolators).
                    map(interpolator -> {
                        final Label label = new Label();
                        label.setText(interpolator.toString());
                        final Rectangle rectangle = new Rectangle(side, side);
                        rectangle.setFill(Color.BLUE);
                        final VBox rectangleVBox = new VBox();
                        rectangleVBox.setPadding(new Insets(10));
                        rectangleVBox.setSpacing(10);
                        rectangleVBox.setAlignment(Pos.CENTER);
                        rectangleVBox.getChildren().setAll(label, rectangle);
                        final RotateTransition rotateTransition = new RotateTransition(animationDuration, rectangle);
                        rotateTransition.setFromAngle(0);
                        rotateTransition.setToAngle(240);
                        rotateTransition.setInterpolator(interpolator);
                        animationList.add(rotateTransition);
                        return rectangleVBox;
                    })
                    .toArray(Node[]::new));
            final FlowPane demoFlow2 = new FlowPane();
            demoFlow2.getChildren().addAll(Arrays.stream(interpolators).
                    map(interpolator -> {
                        final Label label = new Label();
                        label.setText(interpolator.toString());
                        final Circle circle = new Circle(side / 2d);
                        circle.setFill(Color.RED);
                        circle.setOpacity(0.5);
                        final VBox rectangleVBox = new VBox();
                        rectangleVBox.setPadding(new Insets(10));
                        rectangleVBox.setSpacing(10);
                        rectangleVBox.setAlignment(Pos.CENTER);
                        rectangleVBox.getChildren().setAll(label, circle);
                        final TranslateTransition translateTransition = new TranslateTransition(animationDuration, circle);
                        translateTransition.setFromX(0);
                        translateTransition.setFromY(0);
                        translateTransition.setToX(100);
                        translateTransition.setToY(-100);
                        translateTransition.setInterpolator(interpolator);
                        animationList.add(translateTransition);
                        return rectangleVBox;
                    })
                    .toArray(Node[]::new));
            final FlowPane demoFlow3 = new FlowPane();
            demoFlow3.getChildren().addAll(Arrays.stream(interpolators).
                    map(interpolator -> {
                        final Label label = new Label();
                        label.setText(interpolator.toString());
                        final Image image = new Image("http://www.developpez.net/template/images/logo.png", side * 2, side, true, true);
                        final ImageView imageView = new ImageView(image);
                        final VBox rectangleVBox = new VBox();
                        rectangleVBox.setPadding(new Insets(10));
                        rectangleVBox.setSpacing(10);
                        rectangleVBox.setAlignment(Pos.CENTER);
                        rectangleVBox.getChildren().setAll(label, imageView);
                        final FadeTransition fadeTransition = new FadeTransition(animationDuration, imageView);
                        fadeTransition.setFromValue(0);
                        fadeTransition.setToValue(1);
                        fadeTransition.setInterpolator(interpolator);
                        animationList.add(fadeTransition);
                        return rectangleVBox;
                    })
                    .toArray(Node[]::new));
            final ParallelTransition allDemoAnimations = new ParallelTransition();
            allDemoAnimations.getChildren().setAll(animationList);
            final PauseTransition pauseAtEnd = new PauseTransition(Duration.seconds(3));
            final SequentialTransition animation = new SequentialTransition(allDemoAnimations, pauseAtEnd);
            animation.setCycleCount(Transition.INDEFINITE);
            final FlowPane chartFlow = new FlowPane();
            chartFlow.getChildren().addAll(Arrays.stream(interpolators).
                    map(this::createChartForInterpolator)
                    .toArray(Node[]::new));
            final VBox root = new VBox();
            root.setFillWidth(true);
            root.getChildren().setAll(demoFlow1, demoFlow2, demoFlow3, chartFlow);
            final Scene scene = new Scene(root, 1000, 600);
            primaryStage.setTitle("Test interpolators");
            primaryStage.setScene(scene);
            primaryStage.show();
            Platform.runLater(animation::playFromStart);
            final StackPane root2 = new StackPane();
            root2.getChildren().add(createSummaryChartForInterpolators(interpolators));
            final Scene scene2 = new Scene(root2);
            final Stage dialog = new Stage();
            dialog.initStyle(StageStyle.UTILITY);
            dialog.initOwner(primaryStage);
            dialog.setScene(scene2);
            dialog.show();
            dialog.setWidth(600);
            dialog.setHeight(600);
        }
     
        private Chart createChartForInterpolator(final Interpolator interpolator) {
            final double minX = 0;
            final double maxX = 1;
            final LineChart.Series series = new LineChart.Series<>();
            series.setName("y = interpolator(x)");
            for (double x = minX; x <= maxX + 0.01; x += 0.01) {
                final double y = interpolator.interpolate(minX, maxX, x);
                final LineChart.Data data = new LineChart.Data<>(x, y);
                series.getData().add(data);
            }
            final NumberAxis xAxis = new NumberAxis(minX, maxX, (maxX - minX) / 10d);
            final NumberAxis yAxis = new NumberAxis(minX, maxX + 0.1, (maxX - minX) / 10d);
            final LineChart lineChart = new LineChart(xAxis, yAxis);
            lineChart.setPrefWidth(200);
            lineChart.setPrefHeight(200);
            lineChart.setTitle(interpolator.toString());
            lineChart.getData().add(series);
            series.getData()
                    .stream()
                    .forEach(data -> ((LineChart.Data) data).setNode(null));
            return lineChart;
        }
     
        public static void main(String[] args) {
            launch(args);
        }
     
        private Chart createSummaryChartForInterpolators(final Interpolator... interpolators) {
            final double minX = 0;
            final double maxX = 1;
            final LineChart.Series[] allSeries = Arrays.stream(interpolators)
                    .map(interpolator -> {
                        final LineChart.Series series = new LineChart.Series<>();
                        series.setName("y = " + interpolator.toString() + "(x)");
                        for (double x = minX; x <= maxX + 0.01; x += 0.01) {
                            final double y = interpolator.interpolate(minX, maxX, x);
                            final LineChart.Data data = new LineChart.Data<>(x, y);
                            series.getData().add(data);
                        }
                        return series;
                    })
                    .toArray(LineChart.Series[]::new);
            final NumberAxis xAxis = new NumberAxis(minX, maxX, (maxX - minX) / 10d);
            final NumberAxis yAxis = new NumberAxis(minX, maxX + 0.1, (maxX - minX) / 10d);
            final LineChart lineChart = new LineChart(xAxis, yAxis);
            lineChart.setLegendVisible(true);
            lineChart.setPrefWidth(200);
            lineChart.setPrefHeight(200);
            lineChart.setTitle("All Interpolators");
            lineChart.getData().setAll(allSeries);
            Arrays.stream(allSeries)
                    .forEach(series -> series.getData()
                            .stream()
                            .forEach(data -> ((LineChart.Data) data).setNode(null)));
            return lineChart;
        }
     
    }
    Nom : interpolator.jpg
Affichages : 1345
Taille : 88,8 Ko
    Nom : interpolator2.jpg
Affichages : 1217
Taille : 53,8 Ko

    Ici, les 3 animations (rotation, translation et transparence) prennent exactement le meme temps et bien sur on les memes valeurs sources et destinations mais via l'usage des interpolateur on peut croire (visuellement) que certaines sont plus rapides que d'autres (notamment les translations du cercle). Bien sur avec une capture a un instant T comme ici on voit que la position Y des cercles (ou, mais c'est plus dur, l'angle de rotation des carres ou la transparence des images) ne sont pas les memes. Cependant toutes les 5 animations se termineront en meme temps aux mème valeurs car le temps est le même pour toutes.

    Voici ce que ça donne avec les 5 interpolateurs par défaut (tu peux même tenter d'en créer un custom et de l'ajouter a la liste si tu veux) lorsqu'on interprète les graphes :

    • Interpolator.LINEAR - comme son nom l'indique l’accélération du changement de la valeur est constant avec le temps : en général l'oeil détecte assez vite une animation constante et donc sait que le mouvement est artificiel.
    • Interpolator.EASE_IN - l’accélération de changement est initialement faible avant d'atteindre une valeur constante (pente plus abrupte que sur LINEAR mais identique a EASE_OUT) : ça donne l'impression que l'objet a du mal a démarrer et a besoin d’accélérer au début de son mouvement pour atteindre sa vitesse de croisière qui sera un peu plus rapide pour rattraper son retard.
    • Interpolator.EASE_OUT - l’accélération de changement est initialement constante (pente plus abrupte que sur LINEAR mais identique a EASE_IN) puis ralenti sur la fin : ça donne l'impression que l'objet arrive plus vite sur sa position finale mais doit ensuite ralentir / freiner un peu avant la fin avant de s’immobiliser.
    • Interpolator.EASE_BOTH - l’accélération de changement est initialement faible avant d'atteindre une valeur constante puis ralenti sur la fin. La partie constante est plus rapide (pentue) que les autres modes car l'objet va devoir rattraper son retard au depart et a l'arrivee.
    • Interpolator.DISCRETE - La valeur ne change pas avant d'atteindre le dernier pas de temps auquel elle passe brusquement de la valeur source a la valeur finale.


    Tu peux penser par exemple que pour simuler le mouvement d'une balle, va commencer a une grande vitesse puis verra son accélération diminuer puis être nulle au sommet de sa trajectoire avant qu'elle ne prenne a nouveau de la vitesse lorsqu'elle commencera a redescendre.

    Bien sur, il est possible de créer son propre interpolateur pour donner des pseudo effet de rebond / ressort (effet "spring" quand on passe la souris ou clique sur un bouton par exemple). Cependant je ne suis pas sur que transition + interpolateur soit le bon moyen de modéliser correctement une trajectoire de balle en partant des équations physiques. Car ici on est dans la simulation et l'illusion du mouvement naturel ce qui convient bien a de petites animations et non pas pas dans la modélisation (qui doit être la plus exacte possible par rapport a l’énoncée).

    Je serai plus partant d'utiliser le timer d'animation qui permettra de calculer les positons X et Y en fonction du temps, de l’équation de la trajectoire et des divers paramètres du modèle (et faire intervenir la gravité par exemple si on doit la modéliser). Pour ce qui est de la condition d’arrêt sur le bas de la fenêtre il va falloir faire des tests sur la positon de la balle (bien sur) idem sur les rebonds si tu es amené a les modéliser..
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 56
    Points : 53
    Points
    53
    Par défaut
    Re,
    Merci pour ta réponse.
    Pour le AnimationTimer je devrai coder une boucle qui change les coordonnées du centre de la balle ? ou existerait il une façon (des classes par exemple) qui permettent de faire ce genre de choses ? parce que moi mon but c'est de connaitre au maximum le langage Java FX, du coup j'aimerai utiliser les outils déjà disponibles.
    Autre chose, l'AnimationTimer fonctionne comme un Thread en quelque sorte, ou il y aurait des différences ? sinon je ne vois pas l’intérêt de l'avoir codé.
    Et aussi est il possible que tu me passes un petit exemple pour comprendre comment cette interface fonctionne ?
    Merci encore.

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Non, le timer fait la boucle pour toi. Ca devrait etre qq chose dans ce genre :

    Code : 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
    final AnimationTimer worldTimer = new AnimationTimer() {
     
        private long last = Long.MIN_VALUE;
     
        @Override
        public void handle(final long now) {
           if (last ==  Long.MIN_VALUE) {
               last = now;
           }
           final long t = now - last;
           last = now;
           // Changer le monde au temps t.
           [...]
        }
    };
    worldTimer.start();
    A vérifier aussi dans quel thread handle() est invoquée.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 56
    Points : 53
    Points
    53
    Par défaut
    Re !
    Merci beaucoup pour la réponse (y), tout est clair à présent.
    Juste une dernière chose, est il possible d'augmenter la vitesse de l'animation ?
    Et si tu as des idées pour rendre l'animation plus réaliste, par exemple là la balle traine quelques millisecondes d'une position à une autre, c'est pas très réaliste, contrairement à l'animation que j'ai vu en utilisant un Interpolator avec le Timeline, à me passer, ça serai très sympa (y), ou un cours sur comment rendre une animation plus nette et réaliste
    Merci encore (y)

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Pas de bonne idee. Le timer d'animation tourne a 60fps donc si c'est a la traine c'est que qq chose ne vas pas. Le reste c'est juste de l'illusion ou de la poudre aux yeux pour donner a l'utilisateur l'illusion que le mouvement est fluide (ex: motion blur).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 12
    Dernier message: 25/02/2014, 09h42
  2. Modifier une animation pour en retirer le menu
    Par Requiem82 dans le forum Flash
    Réponses: 2
    Dernier message: 19/03/2009, 13h08
  3. Réponses: 4
    Dernier message: 05/11/2007, 11h21
  4. modifier une animation flash
    Par Edta dans le forum Flash
    Réponses: 5
    Dernier message: 02/05/2007, 19h25
  5. Réponses: 1
    Dernier message: 31/10/2006, 11h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo