[JavaFX] Rotation d'une sphère

a marqué ce sujet comme résolu.

Salut tout le monde !

Je suis en train d’essayer de faire une application ou on voit la Terre en train de tourner (fonctionnel) et ou l’utilisateur peut zoomer (fonctionnel) et la faire tourner lui-même en la bougeant avec sa souris. Le problème, c’est que j’arrive à la tourner horizontalement dans les deux sens mais pas verticalement, auriez-vous une idée ?

Une image de l’application parce-que c’est toujours sympa :

Image

Et le code :

Main.java

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.image.Image;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundImage;
import javafx.scene.layout.BackgroundPosition;
import javafx.scene.layout.BackgroundRepeat;
import javafx.scene.layout.BackgroundSize;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;

public class Main extends Application {

    private final String SPACE_BACKGROUND = getClass().getResource("images/space_background.png").toExternalForm() ;

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

    @Override
    public void start(Stage primaryStage) {

        // Création du borderpane parent

        BorderPane root = new BorderPane() ;
        root.setBackground(new Background(new BackgroundImage(new Image(SPACE_BACKGROUND),
                BackgroundRepeat.REPEAT, BackgroundRepeat.REPEAT,
                BackgroundPosition.CENTER, BackgroundSize.DEFAULT))) ; // Mise en place de l'image de fond
        root.setPadding(new Insets(10)) ;

        // Ajout du globe dans le borderpane

        Group globeContainer = new Group();
        root.setCenter(globeContainer) ;
        globeContainer.setPickOnBounds(true) ;

        // Création de la scène & Paramètrage du stage
        
        Scene scene = new Scene(root, 800, 600, true, SceneAntialiasing.BALANCED) ;
        scene.setFill(Color.BLACK) ;

        primaryStage.setScene(scene) ;
        
        primaryStage.show() ;
        primaryStage.requestFocus() ;

        // Ajouts à la scène principale

        EarthUX earthux = new EarthUX() ;
        Sphere earth = earthux.getEarth() ;
        AnimationTimer timer = earthux.getTimer() ;
        globeContainer.getChildren().add(earth) ;
        
        // Zoom
        scene.setOnScroll(new ZoomEventHandler(earth)) ;
        // Drag pour tourner la Terre
        scene.setOnMouseDragged(new DragEventHandler(earth, timer)) ;
        scene.setOnMouseReleased(event -> { timer.start() ; }) ;

    }

}

EarthUX.java

import java.io.InputStream ;

import javafx.animation.AnimationTimer;
import javafx.scene.image.Image;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;

public class EarthUX {
    
    private final InputStream EARTH_TEXTURE = getClass().getResourceAsStream("images/earth_texture.jpg") ;

    private Sphere earth = new Sphere() ;
    private AnimationTimer timer ;
    private static final int rotation_speed = 50_000_000 ; // En ms

    public EarthUX() {

        // Récupèration de l'image & Création texture

        earth.setPickOnBounds(true) ;

        Image earthTexture = new Image(EARTH_TEXTURE) ;
        PhongMaterial earthMaterial = new PhongMaterial() ;
        earthMaterial.setDiffuseMap(earthTexture) ;

        // Calcul le radius par rapport à la diffuse map

        double width = earthMaterial.getDiffuseMap().getWidth() ;
        double height = earthMaterial.getDiffuseMap().getHeight() ;
        double radius = Math.max(width, height) / 30.0 ; // Ratio modifiable

        earth.setRadius(radius) ; // Application du radius
        earth.setMaterial(earthMaterial) ; // Application de la texture à la Terre

        // Rotation
        
        Rotate rotate = new Rotate(0, Rotate.Y_AXIS) ;
        earth.getTransforms().add(rotate) ;

        // Animation de rotation de la Terre
        AnimationTimer timer = new AnimationTimer() {
            private long lastUpdate ;

            @Override
            public void handle(long now) {
                if (now - lastUpdate >= rotation_speed) {
                    rotate.setAngle(rotate.getAngle() + 1) ;
                    lastUpdate = now ;
                }
            }
        } ;
        timer.start() ;

        this.timer = timer ;

    }

    public Sphere getEarth() {
        return this.earth  ;
    }

    public AnimationTimer getTimer() {
        return this.timer ;
    }
    
}

Et enfin DragEventHandler.java :

import javafx.animation.AnimationTimer;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;

public class DragEventHandler implements EventHandler<MouseEvent> {

    private Sphere earth ;
    private double mouseX, mouseY ;
    private AnimationTimer timer ;

    public DragEventHandler(Sphere earth, AnimationTimer timer) {
        this.earth = earth ;
        this.timer = timer ;
    }

    @Override
    public void handle(MouseEvent event) {

        timer.stop() ;
        
        double deltaX = event.getSceneX() - mouseX;
        double deltaY = event.getSceneY() - mouseY;

        earth.setRotationAxis(Rotate.X_AXIS);
        earth.setRotate(earth.getRotate() - deltaY * 0.1);

        earth.setRotationAxis(Rotate.Y_AXIS);
        earth.setRotate(earth.getRotate() - deltaX * 0.1);

        mouseX = event.getSceneX();
        mouseY = event.getSceneY();

    }
    
}

D’ailleurs, même horizontalement, quand je fais un drag de la souris le centre de rotation est celui ou l’utilisateur à cliqué pour le précédent drag. J’imagine que c’est dû au mouseX = event.getSceneX() etc. mais je ne vois pas trop comment le modifier…

Merci d’avance pour votre réponse ! :)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte