Reputation: 29
So I was inspired by one of Daniel Shiffmans coding challenge video (https://www.youtube.com/watch?v=17WoOqgXsRM&t=328s) and the new starwars to make a hyperspace simulation animation of sorts in java. I am a beginner to intermediate programmer and I did research the problem I am having but could not seem to find an answer to it but if someone else finds a similar question with an answer feel free to link to it. Anyway so I have set up a class known as star which is here.
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 ;
}
I am using this to create random starting positions for my stars which are in a 800X800 space and to change the values later. Also yes I do know I did not make my instance fields private this it so I can just easily refer to them when creating my stars as circles in my main without using methods I know this is not convention but I can change that later. Anyway so my problem is after I create my stars and create corresponding circles when I try to update their position by changing my z value with the update method I wrote and then taking the circles x value and subtracting the new z I thought they should all move but they dont. I am also aware that currently they if this was to work it would not create the same effect in the video but I am just trying to get them all to move right now. The code that I thought should do this is located in the anonymous inner class animation timer located in my main class bellow.
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();
}
}
I would appreciate any help with this problem or a suggestion of another way to do this or just overall suggestions for my code.
Upvotes: 0
Views: 1058
Reputation: 159406
The default camera used by JavaFX is a ParallelCamera. The user won't be able to perceive and movement if you update z co-ordinates when a parallel camera is used.
For general code review, http://codereview.stackexchange.com is better (make sure you read about asking before posting there).
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);
}
}
}
I added a fudge factor of -2000 z to recycle the stars as they get closer to the camera. This isn't very precise, some math could be used to 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()
should be able to aid in such calculations, but it didn't work as I expected.
Answers to additional questions
follow up question this might be a silly question but why did you make the animateStars method and createStars method private?
Just habit, it doesn't really matter in this case if the methods are private or not. For larger programs, it can make the code easier to reason about and analyze as private details can be ignored when examining public interface. It is a OOP principle of information hiding. Other principles such as immutable objects can also make things simpler to reason about (especially if writing concurrent code).
Note Java has poor defaults, items should be private and final by default, which would make Java programs less verbose and also encourage people to write programs that are easier to reason about. Newer languages such as Ceylon use more reasonable defaults.
Upvotes: 1