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 :
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 !