2016-04-23 12 views
1

Ich habe eine Frage bezüglich der richtigen Art und Weise, ein Mausereignis in JavaFX zu implementieren.JavaFX Frisbee Bewegung auf Maus/Ziehereignis

Meine playGame() Methode macht zur Zeit Verwendung von onMouseClicked, aber dies ist nur ein Platzhalter für jetzt

Idealerweise möchte ich die ‚Frisbee‘ der Maus ziehen Sie in Richtung „geworfen“ werden.

Was wäre ein guter Weg, dies zu tun?

package FrisbeeToss; 

import javafx.application.Application; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.scene.text.Text; 
import javafx.stage.Stage; 

public class FrisbeeTossMain extends Application { 

private Text info = new Text(); 
private Entity frisbee, target; 

private static final int APP_W = 800; 
private static final int APP_H = 600; 

private static class Entity extends Parent { 
    public Entity(double x, double y, double r, Color c) { 
     setTranslateX(x); 
     setTranslateY(y); 
     Circle circ = new Circle(r, c); 
     getChildren().add(circ); 
    } 
} 

private Parent createContent() { 
    Pane root = new Pane(); 
    root.setPrefSize(APP_W, APP_H); 

    info.setTranslateX(50); 
    info.setTranslateY(50); 

    target = new Entity(APP_W /2, APP_H /2, 75, Color.RED); 
    frisbee = new Entity(APP_W -20, APP_H -20, 60, Color.GREEN); 

    root.getChildren().addAll(info, target, frisbee); 

    return root; 
} 

private void checkCollision(Entity a, Entity b){ 
    if (a.getBoundsInParent().intersects(b.getBoundsInParent())) { 
     info.setText("Target caught frisbee!"); 
    } 
    else { 
     info.setText(""); 
    } 
} 

private void playGame() { 
    frisbee.setOnMouseClicked(event -> { 
     System.out.println("Frisbee clicked"); 

     checkCollision(frisbee, target); 
    }); 
} 

@Override 
public void start(Stage primaryStage) throws Exception { 
    Scene scene = new Scene(createContent()); 

    primaryStage.setTitle("Frisbee Toss"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 

    playGame(); 

    } 
} 

Antwort

1

Animation,

Es gibt ein paar Möglichkeiten, dies getan werden könnte, aber das Konzept einer Frisbee in Betracht Übergänge nehmen würde gut funktionieren. Es gibt ein offizielles Tutorial hier:

Von denjenigen, würde die PathTransition gut funktionieren. Durch die Umwandlung der Richtung, in die der Benutzer den Frisbee "hineinwirft", können Sie eine Path erzeugen, die der Frisbee Node folgen kann. Durch die Zyklen ändern und die Anwendung Umkehrung Sie könnte auch die Frisbee wie ein Bumerang

Als Frisbee Spin verhalten machen, können Sie auch die Vorteile einer RotationTransition nehmen und wenden es neben der Bewegung entlang des Weges


Anwendung Die Animation (en)

Sie können die obigen Übergänge mit nur einem mouseReleased Event auf dem Frisbee anwenden, aber wie Sie speziell erwähnt ziehen, habe ich Ihren Code unten geändert, um beide Ansätze zu zeigen. Ein mit dem freigesetzten Ereignisse und die andere per Drag-and-Drop

Wenn Sie mehr über die Drag-and-Drop-Funktion lesen mögen, ist es hier abgedeckt:


Minor, um seine Quelle Änderungen

In den Implementierungen unten habe ich IhreentferntKlasse es mit einem Circle als die Entity ersetzt wurde nichts hinzugefügt, mit dem Zweck, scheinbar sein nur ein Circle

zu schaffen habe ich entfernt auch die static Erklärungen. In diesem speziellen Beispiel ist es nicht vorteilhaft, sie zu haben oder zu entfernen, aber das Schlüsselwort static sollte nur dort verwendet werden, wo es benötigt wird.Hoffentlich ist dieser beliebte Post kann besser erklären, warum:


Implementationen:

ich Kommentare hinzugefügt haben einige Schritte zu klären, aber wenn irgendetwas nicht klar ist, oder Sie haben einige Verbesserungen, bitte geben Sie einen Kommentar

mouseReleased approac h:

public class FrisbeeTossMain extends Application { 
    private Pane root; 
    private Text info = new Text(); 
    private Circle frisbee, target; 
    private PathTransition transition; 

    private final int APP_W = 800; 
    private final int APP_H = 600; 
    private final double frisbeeX = APP_W -20; 
    private final double frisbeeY = APP_H -20; 

    private Parent createContent() { 
     root = new Pane(); 
     root.setPrefSize(APP_W, APP_H); 

     info.setTranslateX(50); 
     info.setTranslateY(50); 

     target = new Circle(75, Color.RED); 
     target.setLayoutX(APP_W /2); 
     target.setLayoutY(APP_H /2); 

     frisbee = new Circle(60, Color.GREEN); 
     frisbee.setLayoutX(frisbeeX); 
     frisbee.setLayoutY(frisbeeY); 
     frisbee.setFill(new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, 
       new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.GREEN)})); 

     SimpleBooleanProperty isFrisbeeVisuallyCollidingWithTarget = new SimpleBooleanProperty(false); 
     frisbee.boundsInParentProperty().addListener((observable, oldValue, newValue) -> { 
      isFrisbeeVisuallyCollidingWithTarget.set(
        Shape.intersect(frisbee, target).getBoundsInParent().getWidth() >= 0 ? true : false); 
     }); 

     isFrisbeeVisuallyCollidingWithTarget.addListener((observable, oldValue, newValue) -> { 
      if(newValue && transition != null){ 
       //Stop the animation making it appear as though the frisbee was caught 
       transition.stop(); 
      } 
     }); 

     info.textProperty().bind(Bindings.when(isFrisbeeVisuallyCollidingWithTarget) 
       .then("Target caught frisbee!").otherwise("")); 
     root.getChildren().addAll(info, target, frisbee); 

     return root; 
    } 

    private void playGame() { 
     frisbee.setOnMouseReleased(event -> { 
      //Starting point for the line 
      double fromX = frisbeeX - frisbee.getRadius(); 
      double fromY = frisbeeY - frisbee.getRadius(); 

      //Only "throw" the frisbee if the user has released outside of the frisbee itself 
      if(frisbee.getBoundsInParent().contains(event.getSceneX(), event.getSceneY())){ 
       return; 
      } 

      //Create a path between the frisbee and released location 
      Line line = new Line(fromX, fromY, event.getSceneX(), event.getSceneY()); 
      transition = new PathTransition(Duration.seconds(1), line, frisbee); 
      transition.setAutoReverse(true); //Set the node to reverse along the path 
      transition.setCycleCount(2); //2 cycles, first to navigate the path, second to return 
      frisbee.relocate(0, 0); //Allow the path to control the location of the frisbee 

      RotateTransition rotateTransition = 
        new RotateTransition(Duration.seconds(1), frisbee); 
      rotateTransition.setByAngle(360f); 
      rotateTransition.setCycleCount(2); 
      rotateTransition.setAutoReverse(true); 

      rotateTransition.play(); 
      transition.play(); 
     }); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     Scene scene = new Scene(createContent()); 

     primaryStage.setTitle("Frisbee Toss"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     playGame(); 
    } 
} 

Drag-and-Drop-Implementierung:

Der einzige Unterschied zu dem obigen ist, ist innerhalb der playGame Methode:

private void playGame() { 
    frisbee.setId("frisbee"); 

    frisbee.setOnDragDetected(event -> { 
     Dragboard db = frisbee.startDragAndDrop(TransferMode.ANY); 
     ClipboardContent content = new ClipboardContent(); 
     // Store node ID in order to know what is dragged. 
     content.putString(frisbee.getId()); 
     db.setContent(content); 
     event.consume(); 
    }); 

    root.setOnDragOver(event -> { 
     event.acceptTransferModes(TransferMode.COPY_OR_MOVE); 
     event.consume(); 
    }); 

    root.setOnDragDropped(event -> { 
     //Starting point for the line 
     double fromX = frisbeeX - frisbee.getRadius(); 
     double fromY = frisbeeY - frisbee.getRadius(); 

     //Only "throw" the frisbee if the user has released outside of the frisbee itself 
     if(frisbee.getBoundsInParent().contains(event.getSceneX(), event.getSceneY())){ 
      return; 
     } 

     //Create a path between the frisbee and released location 
     Line line = new Line(fromX, fromY, event.getSceneX(), event.getSceneY()); 
     transition = new PathTransition(Duration.seconds(1), line, frisbee); 
     transition.setAutoReverse(true); //Set the node to reverse along the path 
     transition.setCycleCount(2); //2 cycles, first to navigate the path, second to return 
     frisbee.relocate(0, 0); //Allow the path to control the location of the frisbee 

     transition.setOnFinished(finishedEvent -> { 
      event.setDropCompleted(true); 
      event.consume(); 
     }); 
     transition.play(); 
    }); 
} 


Hinzufügen Drehung:

Die Drehung kann die durch vorge bis zur folgenden Schnipsel anwenden, bevor Sie spielen PathTransition:

RotateTransition rotateTransition = new RotateTransition(Duration.seconds(1), frisbee); 
rotateTransition.setByAngle(360f); 
rotateTransition.setCycleCount(2); 
rotateTransition.setAutoReverse(true); 
rotateTransition.play(); 

Sie die Rotation mehr Notiz-Lage durch ein GradientFill zum Frisbee Anwendung im Gegensatz zu machen, zu einem Block Farbe

ZB:

frisbee.setFill(new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, 
    new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.GREEN)})); 


Visuelle Ausgabe

Auftrag: mouseReleased | drag-and-drop | mouseReleased with rotation

(Beachten Sie den Cursor Änderung der Drag-and-Drop-Implementierung)

Frisbee Released Frisbee Drag Frisbee Released with rotation