gpt4 book ai didi

鼠标/拖动事件上的 JavaFX 飞盘运动

转载 作者:行者123 更新时间:2023-11-30 07:26:01 27 4
gpt4 key购买 nike

我有一个关于在 JavaFX 中实现鼠标拖动事件的正确方法的问题。

我的 playGame() 方法当前使用 onMouseClicked,但这只是一个占位符

理想情况下,我希望“飞盘”沿着鼠标拖动的方向“ throw ”。

什么是做到这一点的好方法?

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();

}
}

最佳答案

动画

有几种方法可以做到这一点,但考虑到飞盘的概念,过渡会很有效。这里有一个官方教程:

从可用的情况来看,PathTransition 可以很好地工作。通过转换用户“扔”飞盘的方向,您可以生成飞盘节点可以遵循的路径。通过修改周期并应用反转,您还可以使飞盘表现得像回旋镖

作为飞盘的旋转,您还可以利用 RotationTransition 并将其与沿路径的运动一起应用

<小时/> 应用动画

您可以仅通过飞盘上的 mouseReleased 事件应用上述转换,但正如您特别提到的拖动,我修改了下面的代码以显示这两种方法。一个使用已发布的事件,另一个使用拖放

如果您想了解有关拖放功能的更多信息,请参阅此处:

<小时/> 对原始来源进行了细微更改

在下面的实现中,我删除了您的 Entity 类,并将其替换为 Circle,因为 Entity 没有添加任何内容,目的似乎只是创建一个Circle

我还删除了 static 声明。在这个特定的示例中,拥有或删除它们没有任何好处,但是 static 关键字应该只在需要的地方使用。希望这篇热门文章能够更好地解释原因:

<小时/> 实现:

我添加了评论来澄清一些步骤,但如果有任何不清楚的地方,或者您有一些改进,请添加评论

鼠标释放方法:

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 之前预先添加以下代码片段来应用旋转:

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

您可以通过对飞盘应用GradientFill(而不是 block 颜色)来使旋转更加明显

例如:

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 |拖放|鼠标旋转释放

(注意拖放实现中光标的变化)

Frisbee Released Frisbee Drag Frisbee Released with rotation

关于鼠标/拖动事件上的 JavaFX 飞盘运动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36806141/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com