Skip to content

Instantly share code, notes, and snippets.

@james-d
Last active September 29, 2022 14:36
Show Gist options
  • Save james-d/572b42af033a26393074c3814cac7338 to your computer and use it in GitHub Desktop.
Save james-d/572b42af033a26393074c3814cac7338 to your computer and use it in GitHub Desktop.
package org.jamesd.examples.trajectories;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.*;
public class Trajectories extends Application {
private GraphicsContext gc ;
private final double radius = 3 ;
class Ball {
private double x ;
private double y ;
private final double xVel ;
private final double yVel ;
private final Color color ;
Ball(double x, double y, double xVel, double yVel, Color color) {
this.x = x ;
this.y = y ;
this.xVel = xVel ;
this.yVel = yVel ;
this.color = color ;
}
public double x() { return x ;}
public double y() { return y ;}
public Color color() { return color ;}
public void update(double time) {
x = x + xVel * time ;
y = y + yVel * time ;
if (x < -radius) x = gc.getCanvas().getWidth() + radius;
if (x > gc.getCanvas().getWidth() + radius) x = -radius;
if (y < -radius) y = gc.getCanvas().getHeight() + radius;
if (y > gc.getCanvas().getHeight() + radius) y = -radius;
}
}
private final List<Ball> balls = new ArrayList<>();
private final Random rng = new Random();
@Override
public void start(Stage stage) {
Canvas canvas = new Canvas(800, 800);
gc = canvas.getGraphicsContext2D();
Spinner<Integer> spinner = new Spinner<>(500, Integer.MAX_VALUE, 2000, 500);
spinner.valueProperty().addListener((obs, oldValue, newValue) -> createBalls(newValue));
spinner.setEditable(true);
createBalls(spinner.getValue());
Label fpsLabel = new Label();
AnimationTimer animation = new AnimationTimer() {
private long lastUpdate = System.nanoTime();
@Override
public void handle(long now) {
double elapsedSeconds = (now - lastUpdate) / 1_000_000_000.0;
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
for (Ball ball : balls) {
ball.update(elapsedSeconds);
gc.setFill(ball.color());
gc.fillOval(ball.x()-radius, ball.y()-radius, radius, radius);
}
lastUpdate = now ;
}
};
animation.start();
AnimationTimer fpsTimer = new AnimationTimer() {
private long lastUpdate = System.nanoTime();
private final Deque<Long> frameTimes = new LinkedList<>();
@Override
public void handle(long now) {
frameTimes.add(now);
if (frameTimes.size() > 101) frameTimes.removeFirst();
double elapsedSeconds = (now - lastUpdate) / 1_000_000_000.0;
if (elapsedSeconds > 0.1) {
double time = (now - frameTimes.peekFirst())/1_000_000_000.0;
double fps = (frameTimes.size()-1) / time ;
fpsLabel.setText(String.format("FPS: %.1f", fps));
lastUpdate = now ;
}
}
};
fpsTimer.start();
Pane canvasPane = new Pane(canvas) {
@Override
protected void layoutChildren() {
canvas.relocate(0, 0);
canvas.setWidth(getWidth());
canvas.setHeight(getHeight());
}
};
BorderPane root = new BorderPane(canvasPane);
root.setTop(new HBox(10, spinner, fpsLabel));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private void createBalls(int n) {
balls.clear();
for (int i = 0 ; i < n ; i++) {
double x = rng.nextDouble() * gc.getCanvas().getWidth();
double y = rng.nextDouble() * gc.getCanvas().getHeight();
double xVel = -200 + rng.nextDouble() * 500 ;
double yVel = -200 + rng.nextDouble() * 500 ;
balls.add(new Ball(x, y, xVel, yVel, randomColor()));
}
}
private Color randomColor() {
return Color.color(rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
}
public static void main(String[] args) {
launch();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment