动画
有几种方法可以做到这一点,但是将飞盘的概念考虑到过渡效果会很好。这里有官方教程:
从那些可用的,PathTransition 会很好地工作。通过转换用户“扔”飞盘的方向,您可以生成飞盘Node 可以跟随的Path。通过修改循环和应用反转,您还可以使飞盘表现得像回旋镖
作为飞盘的旋转,您还可以利用 RotationTransition 并将其应用到沿路径的运动中
应用动画
您可以在飞盘上仅通过 mouseReleased 事件应用上述转换,但正如您特别提到的拖动,我已经修改了下面的代码以显示这两种方法。一个使用已发布事件,另一个使用拖放操作
如果您想了解有关拖放功能的更多信息,请参阅此处:
对原始来源的小改动
在下面的实现中,我删除了您的 Entity 类,将其替换为 Circle,因为 Entity 没有添加任何内容,其目的似乎只是创建一个 Circle
我还删除了 static 声明。在这个特定的示例中,拥有或删除它们没有任何好处,但 static 关键字应该只在需要的地方使用。希望这篇受欢迎的帖子能更好地解释原因:
实现:
我添加了 cmets 以澄清一些步骤,但如果有任何不清楚的地方,或者您有一些改进,请添加评论
鼠标释放方法:
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();
}
}
拖放实现:
与上面唯一的区别在于playGame方法内:
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();
});
}
添加轮播:
可以通过在播放PathTransition之前预先添加以下sn-p来应用旋转:
RotateTransition rotateTransition = new RotateTransition(Duration.seconds(1), frisbee);
rotateTransition.setByAngle(360f);
rotateTransition.setCycleCount(2);
rotateTransition.setAutoReverse(true);
rotateTransition.play();
您可以通过将GradientFill 应用于飞盘而不是块颜色来使旋转更加明显
例如:
frisbee.setFill(new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE,
new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.GREEN)}));
视觉输出
订购:mouseReleased | drag-and-drop | mouseReleased with rotation
(注意拖放实现中的光标变化)