我的 javafx 动画计时器似乎没有改变我正在更新的圆圈的位置?
My javafx animation timer doesn't seem to change the location of the circles I am updating?
因此,我受到 Daniel Shiffman 编码挑战视频 (https://www.youtube.com/watch?v=17WoOqgXsRM&t=328s) 和新星球大战的启发,在 java 中制作了某种超 space 模拟动画。我是初学者到中级程序员,我确实研究了我遇到的问题,但似乎找不到答案,但如果其他人找到了类似的问题并有答案,请随时 link 回答。反正我已经设置了一个class已知
作为这里的明星。
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Circle;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.scene.canvas.Canvas;
import javafx.animation.AnimationTimer;
/**
* @author (Richard Zins)
* @version (1)
*/
public class Star extends Circle
{
double x = 0;
double y = 0;
double z = 0;
public Star()
{
x = Math.random()*800;
y = Math.random()*800;
z = Math.random()*800;
}
public void update(){
z = z - 10 ;
}
我正在使用它为 800X800 space 中的星星创建随机起始位置并稍后更改值。另外,是的,我确实知道我没有将我的实例字段设为私有,因此我可以在不使用我知道这不是约定的方法的情况下在我的主中将我的星星创建为圆圈时轻松地引用它们,但我可以稍后更改它。无论如何,我的问题是在我创建星星并创建相应的圆之后,当我尝试通过使用我编写的更新方法更改我的 z 值来更新它们的位置,然后获取圆的 x 值并减去新的 z 我认为它们应该全部移动但他们没有。我也知道,目前他们如果这能奏效,它不会在视频中产生相同的效果,但我只是想让他们现在全部移动。我认为应该执行此操作的代码位于匿名内部 class 动画计时器中,该计时器位于我的主要 class 波纹管中。
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Circle;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.scene.canvas.Canvas;
import javafx.animation.AnimationTimer;
/**
* @author (Richard Zins)
* @version (1)
*/
public class Starfield extends Application
{
public static void main(String[]args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Starfield Simulation");
Group layout = new Group();
Canvas canvas = new Canvas(800,800);
layout.getChildren().add(canvas);
//puts all the stars onto the scene
Star[] stars = new Star[100];
for(int i = 0;i < stars.length;i++){
stars[i] = new Star();
}
Circle[] circles = new Circle[100];
for(int i = 0;i < stars.length;i++){
for(int r = 0;r < circles.length;r++){
layout.getChildren().add(circles[r] = new Circle(stars[i].x,stars[i].y,5,Color.WHITE));
}
}
//going to handle moving the stars with animation timer
final long startNanoTime = System.nanoTime();
new AnimationTimer(){
public void handle(long currentNanoTime){
for(int i = 0;i < stars.length;i++){
for(int r = 0;r < circles.length;r++){
stars[i].update();
circles[r].setCenterX(stars[i].x - stars[i].z);
circles[r].setCenterY(stars[i].y - stars[i].z);
}
}
}
} .start();
Scene sim = new Scene(layout,800,800,Color.BLACK);
primaryStage.setScene(sim);
primaryStage.show();
}
}
对于解决此问题的任何帮助或对其他方法的建议或对我的代码的总体建议,我将不胜感激。
JavaFX 使用的默认相机是 ParallelCamera。如果在使用平行相机时更新 z 坐标,用户将无法感知和移动。
- 对于深度感知,PerspectiveCamera 应该是
用过的。
- 您不需要在代码中定义 Canvas
不要使用一个。
- 您的 Star 继承自 Circle,因此您无需定义额外的圆形数组。
- 您正在使用嵌套循环为 100 个星星定义 100 个圆圈,创建 10 000 个圆圈,而每个星星只需要 1 个圆圈。
- 您不需要为星星定义 x、y、z 成员,因为它们是圆圈,并且圆圈已经有 translateX、translateY 和 translateZ 的成员。
- 您应该检查您的环境是否支持 SCENE3D。
- 您应该在使用 3D 时在场景中打开深度缓冲区(对于这个模拟不会真正产生影响,但对其他模拟会有影响)。
- 不要使用注释,而是将代码拆分为命名方法(只是一种风格建议)。
对于一般代码审查,http://codereview.stackexchange.com is better (make sure you read about asking 在发布之前)。
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Starfield extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
Group layout = new Group();
Star[] stars = createStars(layout);
animateStars(stars);
Scene sim = new Scene(layout, 800, 800, true);
sim.setFill(Color.BLACK);
sim.setCamera(new PerspectiveCamera());
stage.setScene(sim);
stage.show();
}
private void animateStars(final Star[] stars) {
new AnimationTimer() {
public void handle(long currentNanoTime) {
for (Star star : stars) {
star.update();
}
}
}.start();
}
private Star[] createStars(Group layout) {
Star[] stars = new Star[100];
for (int i = 0; i < stars.length; i++) {
stars[i] = new Star();
layout.getChildren().add(
stars[i]
);
}
return stars;
}
public class Star extends Circle {
public Star() {
super(5, Color.WHITE);
setTranslateX(Math.random() * 800);
setTranslateY(Math.random() * 800);
setTranslateZ(Math.random() * 800);
}
public void update() {
double newTranslateZ = getTranslateZ() - 10;
if (newTranslateZ < -2000) {
newTranslateZ = Math.random() * 800;
}
setTranslateZ(newTranslateZ);
}
}
}
我添加了一个 -2000 z 的模糊因子来回收星星,因为它们离相机越来越近。这不是很精确,可以使用一些数学 determine if the point remains within the field of view before it gets recycled. Some of the math for such calculations is documented in the Camera class. node.computeAreaInScreen()
应该能够帮助进行此类计算,但它没有像我预期的那样工作。
其他问题的答案
follow up question this might be a silly question but why did you make the animateStars method and createStars method private?
只是习惯,在这种情况下方法是否私有并不重要。对于较大的程序,它可以使代码更容易推理和分析,因为在检查 public 接口时可以忽略私有细节。 information hiding. Other principles such as immutable objects 的 OOP 原则还可以使事情更易于推理(尤其是在编写并发代码时)。
注意 Java 的默认值很差,默认情况下项目应该是私有的和最终的,这将使 Java 程序不那么冗长,也鼓励人们编写更容易推理的程序。 Ceylon 等较新的语言使用更合理的默认值。
因此,我受到 Daniel Shiffman 编码挑战视频 (https://www.youtube.com/watch?v=17WoOqgXsRM&t=328s) 和新星球大战的启发,在 java 中制作了某种超 space 模拟动画。我是初学者到中级程序员,我确实研究了我遇到的问题,但似乎找不到答案,但如果其他人找到了类似的问题并有答案,请随时 link 回答。反正我已经设置了一个class已知 作为这里的明星。
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Circle;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.scene.canvas.Canvas;
import javafx.animation.AnimationTimer;
/**
* @author (Richard Zins)
* @version (1)
*/
public class Star extends Circle
{
double x = 0;
double y = 0;
double z = 0;
public Star()
{
x = Math.random()*800;
y = Math.random()*800;
z = Math.random()*800;
}
public void update(){
z = z - 10 ;
}
我正在使用它为 800X800 space 中的星星创建随机起始位置并稍后更改值。另外,是的,我确实知道我没有将我的实例字段设为私有,因此我可以在不使用我知道这不是约定的方法的情况下在我的主中将我的星星创建为圆圈时轻松地引用它们,但我可以稍后更改它。无论如何,我的问题是在我创建星星并创建相应的圆之后,当我尝试通过使用我编写的更新方法更改我的 z 值来更新它们的位置,然后获取圆的 x 值并减去新的 z 我认为它们应该全部移动但他们没有。我也知道,目前他们如果这能奏效,它不会在视频中产生相同的效果,但我只是想让他们现在全部移动。我认为应该执行此操作的代码位于匿名内部 class 动画计时器中,该计时器位于我的主要 class 波纹管中。
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Circle;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.scene.canvas.Canvas;
import javafx.animation.AnimationTimer;
/**
* @author (Richard Zins)
* @version (1)
*/
public class Starfield extends Application
{
public static void main(String[]args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Starfield Simulation");
Group layout = new Group();
Canvas canvas = new Canvas(800,800);
layout.getChildren().add(canvas);
//puts all the stars onto the scene
Star[] stars = new Star[100];
for(int i = 0;i < stars.length;i++){
stars[i] = new Star();
}
Circle[] circles = new Circle[100];
for(int i = 0;i < stars.length;i++){
for(int r = 0;r < circles.length;r++){
layout.getChildren().add(circles[r] = new Circle(stars[i].x,stars[i].y,5,Color.WHITE));
}
}
//going to handle moving the stars with animation timer
final long startNanoTime = System.nanoTime();
new AnimationTimer(){
public void handle(long currentNanoTime){
for(int i = 0;i < stars.length;i++){
for(int r = 0;r < circles.length;r++){
stars[i].update();
circles[r].setCenterX(stars[i].x - stars[i].z);
circles[r].setCenterY(stars[i].y - stars[i].z);
}
}
}
} .start();
Scene sim = new Scene(layout,800,800,Color.BLACK);
primaryStage.setScene(sim);
primaryStage.show();
}
}
对于解决此问题的任何帮助或对其他方法的建议或对我的代码的总体建议,我将不胜感激。
JavaFX 使用的默认相机是 ParallelCamera。如果在使用平行相机时更新 z 坐标,用户将无法感知和移动。
- 对于深度感知,PerspectiveCamera 应该是 用过的。
- 您不需要在代码中定义 Canvas 不要使用一个。
- 您的 Star 继承自 Circle,因此您无需定义额外的圆形数组。
- 您正在使用嵌套循环为 100 个星星定义 100 个圆圈,创建 10 000 个圆圈,而每个星星只需要 1 个圆圈。
- 您不需要为星星定义 x、y、z 成员,因为它们是圆圈,并且圆圈已经有 translateX、translateY 和 translateZ 的成员。
- 您应该检查您的环境是否支持 SCENE3D。
- 您应该在使用 3D 时在场景中打开深度缓冲区(对于这个模拟不会真正产生影响,但对其他模拟会有影响)。
- 不要使用注释,而是将代码拆分为命名方法(只是一种风格建议)。
对于一般代码审查,http://codereview.stackexchange.com is better (make sure you read about asking 在发布之前)。
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Starfield extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
Group layout = new Group();
Star[] stars = createStars(layout);
animateStars(stars);
Scene sim = new Scene(layout, 800, 800, true);
sim.setFill(Color.BLACK);
sim.setCamera(new PerspectiveCamera());
stage.setScene(sim);
stage.show();
}
private void animateStars(final Star[] stars) {
new AnimationTimer() {
public void handle(long currentNanoTime) {
for (Star star : stars) {
star.update();
}
}
}.start();
}
private Star[] createStars(Group layout) {
Star[] stars = new Star[100];
for (int i = 0; i < stars.length; i++) {
stars[i] = new Star();
layout.getChildren().add(
stars[i]
);
}
return stars;
}
public class Star extends Circle {
public Star() {
super(5, Color.WHITE);
setTranslateX(Math.random() * 800);
setTranslateY(Math.random() * 800);
setTranslateZ(Math.random() * 800);
}
public void update() {
double newTranslateZ = getTranslateZ() - 10;
if (newTranslateZ < -2000) {
newTranslateZ = Math.random() * 800;
}
setTranslateZ(newTranslateZ);
}
}
}
我添加了一个 -2000 z 的模糊因子来回收星星,因为它们离相机越来越近。这不是很精确,可以使用一些数学 determine if the point remains within the field of view before it gets recycled. Some of the math for such calculations is documented in the Camera class. node.computeAreaInScreen()
应该能够帮助进行此类计算,但它没有像我预期的那样工作。
其他问题的答案
follow up question this might be a silly question but why did you make the animateStars method and createStars method private?
只是习惯,在这种情况下方法是否私有并不重要。对于较大的程序,它可以使代码更容易推理和分析,因为在检查 public 接口时可以忽略私有细节。 information hiding. Other principles such as immutable objects 的 OOP 原则还可以使事情更易于推理(尤其是在编写并发代码时)。
注意 Java 的默认值很差,默认情况下项目应该是私有的和最终的,这将使 Java 程序不那么冗长,也鼓励人们编写更容易推理的程序。 Ceylon 等较新的语言使用更合理的默认值。