需要帮助动画图像遵循 JavaFX 中的圆形路径
Need help animating an image follow a circular path in JavaFX
我正在做一个大学项目,我必须重新制作音乐椅游戏,我正在为孩子们制作围着椅子转圈的动画。我一直在尝试用沿着圆形路径的矩形进行测试。
问题是我有一个带工具栏的 HBox,小游戏稍后会用到它,而在堆栈窗格中有带路径的矩形,这两件事在 VBox 中,基本上是根。但是矩形在 window 的右下角做动画,我想把它放在堆栈窗格的中心。任何帮助将不胜感激。这是代码:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javafxapplication4;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
import logica.CircularPane;
/**
*
* @author Franklin
*/
public class JavaFXApplication4 extends Application {
@Override
public void start(Stage primaryStage) throws FileNotFoundException {
VBox boxmaster=new VBox();
StackPane stackpane=new StackPane();
HBox tools=new HBox(); tools.setPrefHeight(70);
//Botones y tool bar
//start
Button start=new Button();
start.setPadding(new Insets(-1,-1,-1,-1));
start.setAlignment(Pos.CENTER_LEFT);
tools.getChildren().add(start);
//Cambio de dirección
HBox botones=new HBox(); botones.setSpacing(5);
botones.setAlignment(Pos.CENTER_RIGHT);
//izquierda
Button left=new Button();
left.setPadding(new Insets(-1,-1,-1,-1));
left.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(left);
//derecha
Button right=new Button();
right.setPadding(new Insets(-1,-1,-1,-1));
right.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(right);
//Pause
Button pause=new Button();
pause.setPadding(new Insets(-1,-1,-1,-1));
pause.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(pause);
//Salir
Button exit=new Button();
exit.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 55px; " +
"-fx-min-height: 55px; " +
"-fx-max-width: 55px; " +
"-fx-max-height: 55px;");
exit.setVisible(false);
botones.getChildren().add(exit);
HBox.setHgrow(botones, Priority.ALWAYS);
HBox.setMargin(start, new Insets(14,0,0,40));
tools.getChildren().add(botones);
tools.setPadding(new Insets(2));
boxmaster.getChildren().add(tools);
//Juego como tal
Rectangle rect2 = new Rectangle(20, 20);
rect2.setArcHeight(10);
rect2.setArcWidth(10);
rect2.setFill(Color.GREEN);
stackpane.getChildren().add(rect2);
Path path2 = createEllipsePath(0, 0, 150, 150, 0);
stackpane.getChildren().add(path2);
PathTransition pathCircle=new PathTransition();
pathCircle.setDuration(Duration.seconds(2));
pathCircle.setPath(path2);
pathCircle.setNode(rect2);
pathCircle.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
pathCircle.setCycleCount(Timeline.INDEFINITE);
pathCircle.setAutoReverse(false);
stackpane.setAlignment(Pos.CENTER);
boxmaster.getChildren().add(stackpane);
VBox.setVgrow(stackpane, Priority.ALWAYS);
Scene scene=new Scene(boxmaster,1080,720);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
pathCircle.play();
}
private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate)
{
ArcTo arcTo = new ArcTo();
arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree celcius circle.
arcTo.setY(centerY - radiusY);
arcTo.setSweepFlag(false);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(radiusX);
arcTo.setRadiusY(radiusY);
arcTo.setXAxisRotation(rotate);
Path path = new Path();
path.getElements().addAll(
new MoveTo(centerX - radiusX, centerY - radiusY),
arcTo,
new ClosePath()); // close 1 px gap.
path.setStroke(Color.DODGERBLUE);
path.getStrokeDashArray().setAll(5d, 5d);
return path;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
NOTES= createEllipsePath 代码是我在研究如何创建圆形路径后发现的。
按钮没有文字,因为它们最初有图形。
我不是 JavaFX 方面的专家。我只是玩弄了你的代码,我让它按照我的想法(并希望)你想要它做。我添加了额外的 Path
。第一个 Path
绘制圆,第二个 Path
分配给 PathTransition
。然后我玩弄第二个 Path
的坐标,直到我得到绿色矩形以围绕第一个路径的圆圈移动。
请注意,我从您的代码中删除了未使用的导入,并为您的每个 Button
添加了不同的字母,这样我就可以看到它们在 Scene
.
中的位置
这是代码。
public class JavaFXApplication4 extends Application {
@Override
public void start(Stage primaryStage) { //throws FileNotFoundException {
VBox boxmaster = new VBox();
StackPane stackpane = new StackPane();
HBox tools = new HBox();
tools.setPrefHeight(70);
//Botones y tool bar
//start
Button start = new Button("S");
start.setPadding(new Insets(-1,-1,-1,-1));
start.setAlignment(Pos.CENTER_LEFT);
tools.getChildren().add(start);
//Cambio de dirección
HBox botones = new HBox();
botones.setSpacing(5);
botones.setAlignment(Pos.CENTER_RIGHT);
//izquierda
Button left = new Button("L");
left.setPadding(new Insets(-1,-1,-1,-1));
left.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(left);
//derecha
Button right = new Button("R");
right.setPadding(new Insets(-1,-1,-1,-1));
right.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(right);
//Pause
Button pause = new Button("P");
pause.setPadding(new Insets(-1,-1,-1,-1));
pause.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(pause);
//Salir
Button exit = new Button("E");
exit.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 55px; " +
"-fx-min-height: 55px; " +
"-fx-max-width: 55px; " +
"-fx-max-height: 55px;");
exit.setVisible(false);
botones.getChildren().add(exit);
HBox.setHgrow(botones, Priority.ALWAYS);
HBox.setMargin(start, new Insets(14, 0, 0, 40));
tools.getChildren().add(botones);
tools.setPadding(new Insets(2));
boxmaster.getChildren().add(tools);
//Juego como tal
Rectangle rect2 = new Rectangle(20, 20);
rect2.setArcHeight(10);
rect2.setArcWidth(10);
rect2.setFill(Color.GREEN);
stackpane.getChildren().add(rect2);
Path path2 = createEllipsePath(166, 10, 160, 160, 0); // changed this line.
Path path1 = createEllipsePath(0, 0, 150, 150, 0); // added this line.
stackpane.getChildren().add(path1);
PathTransition pathCircle = new PathTransition();
pathCircle.setDuration(Duration.seconds(2));
pathCircle.setPath(path2);
pathCircle.setNode(rect2);
pathCircle.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
pathCircle.setCycleCount(Timeline.INDEFINITE);
pathCircle.setAutoReverse(false);
stackpane.setAlignment(Pos.CENTER);
boxmaster.getChildren().add(stackpane);
VBox.setVgrow(stackpane, Priority.ALWAYS);
Scene scene=new Scene(boxmaster,1080,720);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
pathCircle.play();
}
private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate)
{
ArcTo arcTo = new ArcTo();
arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree celcius circle.
arcTo.setY(centerY - radiusY);
arcTo.setSweepFlag(false);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(radiusX);
arcTo.setRadiusY(radiusY);
arcTo.setXAxisRotation(rotate);
Path path = new Path();
path.getElements().addAll(
new MoveTo(centerX - radiusX, centerY - radiusY),
arcTo,
new ClosePath()); // close 1 px gap.
path.setStroke(Color.DODGERBLUE);
path.getStrokeDashArray().setAll(5d, 5d);
return path;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
我正在做一个大学项目,我必须重新制作音乐椅游戏,我正在为孩子们制作围着椅子转圈的动画。我一直在尝试用沿着圆形路径的矩形进行测试。 问题是我有一个带工具栏的 HBox,小游戏稍后会用到它,而在堆栈窗格中有带路径的矩形,这两件事在 VBox 中,基本上是根。但是矩形在 window 的右下角做动画,我想把它放在堆栈窗格的中心。任何帮助将不胜感激。这是代码:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javafxapplication4;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
import logica.CircularPane;
/**
*
* @author Franklin
*/
public class JavaFXApplication4 extends Application {
@Override
public void start(Stage primaryStage) throws FileNotFoundException {
VBox boxmaster=new VBox();
StackPane stackpane=new StackPane();
HBox tools=new HBox(); tools.setPrefHeight(70);
//Botones y tool bar
//start
Button start=new Button();
start.setPadding(new Insets(-1,-1,-1,-1));
start.setAlignment(Pos.CENTER_LEFT);
tools.getChildren().add(start);
//Cambio de dirección
HBox botones=new HBox(); botones.setSpacing(5);
botones.setAlignment(Pos.CENTER_RIGHT);
//izquierda
Button left=new Button();
left.setPadding(new Insets(-1,-1,-1,-1));
left.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(left);
//derecha
Button right=new Button();
right.setPadding(new Insets(-1,-1,-1,-1));
right.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(right);
//Pause
Button pause=new Button();
pause.setPadding(new Insets(-1,-1,-1,-1));
pause.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(pause);
//Salir
Button exit=new Button();
exit.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 55px; " +
"-fx-min-height: 55px; " +
"-fx-max-width: 55px; " +
"-fx-max-height: 55px;");
exit.setVisible(false);
botones.getChildren().add(exit);
HBox.setHgrow(botones, Priority.ALWAYS);
HBox.setMargin(start, new Insets(14,0,0,40));
tools.getChildren().add(botones);
tools.setPadding(new Insets(2));
boxmaster.getChildren().add(tools);
//Juego como tal
Rectangle rect2 = new Rectangle(20, 20);
rect2.setArcHeight(10);
rect2.setArcWidth(10);
rect2.setFill(Color.GREEN);
stackpane.getChildren().add(rect2);
Path path2 = createEllipsePath(0, 0, 150, 150, 0);
stackpane.getChildren().add(path2);
PathTransition pathCircle=new PathTransition();
pathCircle.setDuration(Duration.seconds(2));
pathCircle.setPath(path2);
pathCircle.setNode(rect2);
pathCircle.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
pathCircle.setCycleCount(Timeline.INDEFINITE);
pathCircle.setAutoReverse(false);
stackpane.setAlignment(Pos.CENTER);
boxmaster.getChildren().add(stackpane);
VBox.setVgrow(stackpane, Priority.ALWAYS);
Scene scene=new Scene(boxmaster,1080,720);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
pathCircle.play();
}
private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate)
{
ArcTo arcTo = new ArcTo();
arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree celcius circle.
arcTo.setY(centerY - radiusY);
arcTo.setSweepFlag(false);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(radiusX);
arcTo.setRadiusY(radiusY);
arcTo.setXAxisRotation(rotate);
Path path = new Path();
path.getElements().addAll(
new MoveTo(centerX - radiusX, centerY - radiusY),
arcTo,
new ClosePath()); // close 1 px gap.
path.setStroke(Color.DODGERBLUE);
path.getStrokeDashArray().setAll(5d, 5d);
return path;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
NOTES= createEllipsePath 代码是我在研究如何创建圆形路径后发现的。 按钮没有文字,因为它们最初有图形。
我不是 JavaFX 方面的专家。我只是玩弄了你的代码,我让它按照我的想法(并希望)你想要它做。我添加了额外的 Path
。第一个 Path
绘制圆,第二个 Path
分配给 PathTransition
。然后我玩弄第二个 Path
的坐标,直到我得到绿色矩形以围绕第一个路径的圆圈移动。
请注意,我从您的代码中删除了未使用的导入,并为您的每个 Button
添加了不同的字母,这样我就可以看到它们在 Scene
.
这是代码。
public class JavaFXApplication4 extends Application {
@Override
public void start(Stage primaryStage) { //throws FileNotFoundException {
VBox boxmaster = new VBox();
StackPane stackpane = new StackPane();
HBox tools = new HBox();
tools.setPrefHeight(70);
//Botones y tool bar
//start
Button start = new Button("S");
start.setPadding(new Insets(-1,-1,-1,-1));
start.setAlignment(Pos.CENTER_LEFT);
tools.getChildren().add(start);
//Cambio de dirección
HBox botones = new HBox();
botones.setSpacing(5);
botones.setAlignment(Pos.CENTER_RIGHT);
//izquierda
Button left = new Button("L");
left.setPadding(new Insets(-1,-1,-1,-1));
left.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(left);
//derecha
Button right = new Button("R");
right.setPadding(new Insets(-1,-1,-1,-1));
right.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(right);
//Pause
Button pause = new Button("P");
pause.setPadding(new Insets(-1,-1,-1,-1));
pause.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 50px; " +
"-fx-min-height: 50px; " +
"-fx-max-width: 50px; " +
"-fx-max-height: 50px;");
botones.getChildren().add(pause);
//Salir
Button exit = new Button("E");
exit.setStyle("-fx-background-radius: 5em; " +
"-fx-min-width: 55px; " +
"-fx-min-height: 55px; " +
"-fx-max-width: 55px; " +
"-fx-max-height: 55px;");
exit.setVisible(false);
botones.getChildren().add(exit);
HBox.setHgrow(botones, Priority.ALWAYS);
HBox.setMargin(start, new Insets(14, 0, 0, 40));
tools.getChildren().add(botones);
tools.setPadding(new Insets(2));
boxmaster.getChildren().add(tools);
//Juego como tal
Rectangle rect2 = new Rectangle(20, 20);
rect2.setArcHeight(10);
rect2.setArcWidth(10);
rect2.setFill(Color.GREEN);
stackpane.getChildren().add(rect2);
Path path2 = createEllipsePath(166, 10, 160, 160, 0); // changed this line.
Path path1 = createEllipsePath(0, 0, 150, 150, 0); // added this line.
stackpane.getChildren().add(path1);
PathTransition pathCircle = new PathTransition();
pathCircle.setDuration(Duration.seconds(2));
pathCircle.setPath(path2);
pathCircle.setNode(rect2);
pathCircle.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
pathCircle.setCycleCount(Timeline.INDEFINITE);
pathCircle.setAutoReverse(false);
stackpane.setAlignment(Pos.CENTER);
boxmaster.getChildren().add(stackpane);
VBox.setVgrow(stackpane, Priority.ALWAYS);
Scene scene=new Scene(boxmaster,1080,720);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
pathCircle.play();
}
private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate)
{
ArcTo arcTo = new ArcTo();
arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree celcius circle.
arcTo.setY(centerY - radiusY);
arcTo.setSweepFlag(false);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(radiusX);
arcTo.setRadiusY(radiusY);
arcTo.setXAxisRotation(rotate);
Path path = new Path();
path.getElements().addAll(
new MoveTo(centerX - radiusX, centerY - radiusY),
arcTo,
new ClosePath()); // close 1 px gap.
path.setStroke(Color.DODGERBLUE);
path.getStrokeDashArray().setAll(5d, 5d);
return path;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}