javafx animation looping - java

in c++ or c programming language, we know to change the cordinate we use gotoxy(x,y) and we can use looping and sleep to change the cordinate and making animation. like this;
for(x = 20; x < 25; x++){
gotoxy(x,20); cout << "*"
}
but my queston is how about in JAVAFX 2.0 programming? i'm using netbeans 7.2.
thanks for your any help.

Use the JavaFX Animation Package.
There are numerous examples in the JavaFX Animation Tutorial, as Andy pointed out in his comment.
And there is a cute example of a running horse animation loop.
The key is that you don't sleep the JavaFX application thread and you have to release control of the JavaFX thread back to the JavaFX system each time you update something and want it rendered. The JavaFX animation classes take care of these things for you so that you don't have to worry about it. If you just loop like you do in the sample code from your question, JavaFX will just render the scene once after your loop has completed and you will never see anything happen.
Here is a fairly boring example which uses a Timeline to emulate the c++ code in your question to move a dot a pixel every 400 milliseconds.
import java.util.Date;
import javafx.animation.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
/** Simple JavaFX Animation Sample. */
public class AnimationSample extends Application {
private int x = 20;
private String status = "";
private final Circle dot = new Circle(20, 20, 3);
private final TimeCounter counter = new TimeCounter();
public static void main(String[] args) throws Exception { launch(args); }
#Override public void start(final Stage stage) throws Exception {
final Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new EventHandler() {
#Override public void handle(Event event) {
refreshScene();
}
}),
new KeyFrame(Duration.millis(400))
);
timeline.setCycleCount(Timeline.INDEFINITE);
stage.setScene(new Scene(new Group(dot), 50, 50));
stage.show();
counter.reset();
timeline.play();
}
private void refreshScene() {
gotoxy(x, 20);
status = "*****".equals(status) ? "*" : status + "*";
System.out.println(String.format("%7d", counter.elapsed()) + " ms " + x + " " + status);
if (x == 24) {
x = 20;
} else {
x++;
}
}
private void gotoxy(int x, int y) {
dot.setCenterX(x);
dot.setCenterY(y);
}
class TimeCounter {
private long start = new Date().getTime();
void reset() { start = new Date().getTime(); }
long elapsed() { return new Date().getTime() - start; }
}
}

There are three different options in JavaFX, depending on your needs.
The most basic one is AnimationTimer. It's equivalent to Swing's Timer. It simply contains a handle method which is called on every frame, and passed current time as argument. You probably want some internal bookkeeping so that you do not do expensive calculations every time handle is called.
Transition has an interpolate(frac) method, which gets called with values of frac between 0.0 and 1.0. It's up to you to do all UI changes you want to, based on the frac value. Both Transition and Timeline extend Animation, so you can set stuff like cycle duration, whether the Transition is reversed at end, etc.
Timeline is the most complex one. You define arbitrary amount of KeyFrames (think of states) that contain wanted properties of different Nodes, and the Timeline will do all the work for you interpolating how to animate the change between the provided values. For example, you can give a keyframe where x property of a Node is 0, and another where it's 100, and Timeline will do the animating for you.

Have look at using a Timeline Animation. It is a key component of animation in JavaFX and
is used to establish when, and in what sequence, key parts of an animation occur.
Here is an example

Related

JavaFX circular progressindicator not working as expected

So I'd like to make a circular progress indicator that runs smoothly from start to end, although I haven't found exactly what I'm looking for, I found a workaround using the class "ProgressIndicator" and grouping it in a way that is shown as I want it to.
I tried running this code that creates a timeline for it to do such smooth result I was looking for (this code isn't mine at all, took it from https://asgteach.com/2011/10/javafx-animation-and-binding-using-the-progressbar/) but it doesn't work as intended at all. The end result should be looking like this from start to end:
expectation
Although it takes some time to load showing this animation:
reality
Is there any way to make that starting animation not appear and make it so it starts instantly? If you have better options for what I'm trying to achieve or a solution using the existing progressIndicator I'm trying to use, I'll gladly hear them out.
The code I'm trying to run right now:
private static final Integer STARTTIME = 30;
private Timeline timeline;
private IntegerProperty timeSeconds = new SimpleIntegerProperty(STARTTIME*100);
public void testProgressIndicator() {
myProgressIndicator.progressProperty().bind(
timeSeconds.divide(STARTTIME*100.0).subtract(1).multiply(-1));
btnTest.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
if (timeline != null) {
timeline.stop();
}
timeSeconds.set((STARTTIME+1)*100);
timeline = new Timeline();
timeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(STARTTIME+1),
new KeyValue(timeSeconds, 0)));
timeline.playFromStart();
}
});

JavaFX graphics: How to change Paint settings?

Nearly a month ago I was testing JavaFX graphics API, however I was worried about performance. The performance problem is that I had to pass a Paint object for colorizing shapes.
Issue: it's impossible to change settings of an existing Paint
I just need to update a Paint, for example, Color, but there are no methods like Color#setRed, Color#setGreen, Color#setBlue and Color#setOpacity. There are no fields, too (javafx.scene.paint.Color).
Performance
The unique way I can try to change settings of a Paint is to construct another Paint instead, however this will involve on running the garbage collector. Is that correct?
The compiler should optimize these objects automatically depending on how they're entirely used. But Oracle said nothing about that on its compiler, at least for me, so far.
If they say garbage collection is good, the fault isn't mine. I didn't mention anything about garbage collection being helpful.
So is it a good solution to re-construct a Paint? Do you guys also know of JavaFX alternatives that handle what I want?
The issue you are concerned with doesn't really exist. Since Paint is an immutable class (which is a good design choice for a number of reasons), the correct way to update the color of something in JavaFX is to create a new Paint instance and set it as a property where needed. Previously-used instances which no longer have references to them will be cleaned up - efficiently - by the garbage collector at some point in the future.
Here is a simple demo which creates new Paint instances every time the scene is rendered (also new Background and BackgroundFill instances). It prints warnings if the frame rendering takes more than 25ms (an arbitrary threshold). On my system, it warns for the first couple of frames, and sometimes warns when the window is hidden and completely reshown.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class UpdateColorContinuously extends Application {
#Override
public void start(Stage primaryStage) {
Pane root = new Pane();
root.setMinSize(600, 600);
new AnimationTimer() {
private long start = -1 ;
private long lastUpdate ;
#Override
public void handle(long now) {
if (start < 0) {
start = now ;
lastUpdate = now ;
}
long elapsed = now - start ;
double elapsedSeconds = elapsed / 1_000_000_000.0 ;
Color newColor = Color.hsb(elapsedSeconds * 5, 1.0, 1.0);
BackgroundFill fill = new BackgroundFill(newColor, CornerRadii.EMPTY, Insets.EMPTY);
Background bg = new Background(fill);
root.setBackground(bg);
if (now - lastUpdate > 25_000_000) {
System.err.println("Warning: frame rendering took "+ (now-lastUpdate)/1_000_000 + " ms");
}
lastUpdate = now ;
}
}.start();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
It's possible I haven't run this long enough for the GC to need to run; a conservative estimate of the amount of memory a Paint instance needs is 50 bytes, so you would need to create of the order of 10^7 such instances to use 500MB (a reasonably small amount of RAM on a modern desktop system, which would likely be equivalent to one GC sweep). So, ballpark figures, this would generate one GC sweep in two days.

Live-Update LineChart in JavaFX

I have problem with updating JavaFX UI - I want to update line chart and some labels on my scene when it's already shown.
My task is to do some calculations (calling function in other class which returns dataseries) and add updated series to the chart.
The following code (which is in a loop) may present what i want to do:
//double x - x value of the point i want to add to my chart
//double y - y value of the point i want to add to my chart
//string s - some result from function
mySeries.getData().add(new XYChart.Data(x, y));
someLabel.setText(s);
My program freezes and give only final solution after some time, but i want to see the points on the chart exactly after they're added, not at the end of the execution. If the process is too quick, i would like to add Thread.sleep(1000) before adding the next point to the chart.
I know it has something to do with threads, concurrency and tasks, but i wasn't able to find a solution yet. I tried to use some code I found here but still I don't know the correct answer.
Every user action, e.g. click a button, will notify your action listener within the UI thread. Logic in the UI thread should be as fast as possible. I think you are reacting on a user event and then execute a long running task in the UI thread. Try to put your code in a background thread. Further you need to put the UI updates back again in the UI thread. You can do this with "Platform.runLater(...)".
Something like this:
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createChart());
primaryStage.setScene(scene);
primaryStage.setHeight(800);
primaryStage.setWidth(1200);
primaryStage.show();
}
private Parent createChart() {
LineChart<Number, Number> lc = new LineChart<>(new NumberAxis(), new NumberAxis());
XYChart.Series<Number, Number> series = new XYChart.Series<>();
lc.getData().add(series);
new Thread(() -> {
try {
Thread.sleep(5000);
for (int i = 0; i < 15; i++) {
int finalI = i;
Platform.runLater(() -> series.getData().add(new XYChart.Data<>(1 + finalI, 1 + finalI)));
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
return lc;
}
}

Java game keeps crashing after about 2 minutes of runtime (Intellij)

I am using Intellij to program Java.
I am currently trying to make a top down tile based shooter.
My issue is that my game, after approximately 2 minutes, crashes with a popup saying "Java(TM) Platform SE Binary has stopped working. I recorded the time it took for it to crash 3 times: 1m57s, 1m59s, 1m58s.
The game is in a very simple state right now and I am not sure what could be causing the crash. All of the relevant code is in just two classes: GameFrame.java (extends JFrame) and GamePanel.java (which extends JPanel).
GameFrame.java:
package net.magnusfrater.tds.game;
import javax.swing.*;
public class GameFrame extends JFrame {
public static final int width = 1000;
public static final int height = width / 16 * 10;
private GamePanel gp;
public GameFrame () {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
setResizable(false);
setLocationRelativeTo(null);
setTitle("Time Based Fast Paced Top Down Shooter Demo");
gp = new GamePanel();
add(gp);
setVisible(true);
}
public static void main (String[] args) {
GameFrame gf = new GameFrame();
}
}
GamePanel.java
package net.magnusfrater.tds.game;
import net.magnusfrater.tds.input.Keyboard;
import javax.swing.*;
import java.awt.*;
public class GamePanel extends JPanel implements Runnable {
//panel
private Thread thread;
private static boolean running;
private boolean fpsLock;
//input
private Keyboard kb;
//game
private Game game;
public GamePanel () {
//panel
thread = new Thread(this, "Time Based Fast Paced Top Down Shooter Demo");
running = true;
fpsLock = true;
//input
//kb = new Keyboard();
//addKeyListener(kb);
//game
//game = new Game(1);
thread.start();
}
public void run () {
long iTimeNS = System.nanoTime();
int tickRate = 60;
long ns = 1000000000 / tickRate;
int ups = 0;
int fps = 0;
long iTimeS = System.nanoTime();
long s = 1000000000;
while (running) {
long fTimeNS = System.nanoTime();
if (fTimeNS - iTimeNS >= ns){
iTimeNS = System.nanoTime();
tick();
ups++;
if (fpsLock){
repaint();
fps++;
}
}
if (!fpsLock){
repaint();
fps++;
}
long fTimeS = System.nanoTime();
if (fTimeS - iTimeS >= s){
iTimeS = System.nanoTime();
System.out.println("ups: " + ups + "\tfps: " + fps);
ups = 0;
fps = 0;
}
}
System.exit(0);
}
public void tick () {
if (kb != null)
kb.tick();
if (game != null)
game.tick();
}
#Override
public void update (Graphics g) {
paint(g);
}
#Override
public void paint (Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0,0,GameFrame.width, GameFrame.height);
//if (game != null)
//game.paint(g);
}
public static void quitGame () {
running = false;
}
}
I originally thought that the issue was because of the way that I was loading images for spritesheets or maybe the way I was loading text files for the level design but after reworking both of those, the issue remained.
That left me curious and a little bit fed up so I tried finding out more about the explanation for the crash. First I read more from the popup but it didn't say anything useful: (See below)
Second I looked at the exit code given by Intellij: (See below)
I looked up what exit code 255 was but there wasn't anything useful. The best explanation I could find was that exit code 255 meant that the real exit code was out of range: (See below)
I was out of ideas at this point so I just started plain old googling everything I could think of. The problem with googling "Java(TM) Platform SE Binary has stopped working" is that almost every suggested link is a question about Minecraft. Limiting my search to Stack Overflow yielded me some results, but nothing conclusive. Some of the fixes I found were stuff I already tried (such as not handling input streams properly, not handling buffered reader properly, not disposing of elements, etc). I found these links but none of them were truly related to my issue:
(See below)
(See below)
(See below)
(See below)
(See below)
(See below)
The last fix I tried was to re-install Java SE Development Kit 8u101 AND Java SE Development Kit 8u102. I then restarted Intellij. I then restarted my computer.
Nothing worked.
At this point I think I'm just dumb. I've overlooked something easy I can tell. What am I missing?
(ps~ This is a possibly related issue. So if I run my game with almost no content in it with the fps not locked to 60, I get really absurd numbers of frames per second. I didn't think that fps as high as 7,000,000 was possible. I think. I don't know. Have I programmed that wrong as well? Here is a related picture of my ups/fps output: [see below])
(SEE HERE) So Stack Overflow doesn't allow members with a score within a certain threshold post more than 2 links and allows absolutely no posting of images. So here is a link to a google doc with all of the links and images I mentioned above:
https://docs.google.com/document/d/1XrBuVio19GmkFz0EfRzXVp5AJmM5zPfVO6vK3oS3Eaw/edit?usp=sharing
Try and set your -Xmx to something like 2G and see if it runs longer. If so, something is allocating memory and maybe you have that other setting set that exits instead of garbage collecting for some reason.
Also, try changing your code to limit things using Guava's RateLimiter.
…
// class level
final RateLimiter frameLimiter = RateLimiter.create(60.0);
final RateLimiter outputLimiter = RateLimiter.create(1.0);
…
// in run method
while (running) {
frameLimiter.acquire();
repaint();
fps++;
if (outputLimiter.tryAcquire()){
System.out.println("fps: " + fps);
fps = 0;
}
}
I've removed ups and tick(). You should do your work after repainting and I don't think you want to do more work than needed for the next frame, which at the soonest should be at your max rate. Later you'll need to add logic to handle skipping work when frames are being skipped. I might make more sense to increment the fps within repaint.
You could put the output in its own thread and only acquire that limiter if you synchronized the increments and resetting of fps.

JavaFX refresh Progress Bar within a method

I have a javafx Progressbar in my UI and then I have a for loop.
In every iteration of the for loop this happens:
progressVal += 5.0;
progress.setProgress(progressVal);
And after the whole loop, this happens:
progress.setProgress(100);
I now have recognized that the UI controls are only refreshed after the method has finished, so the progress bar wont update until the end and than would be set to 100 imidiatly.
So is it possible so somehow force the UI update, even when the method isn`t finished completly? Or how else could I do this?
If what you do in your loop takes a long time and should not be executed on the JavaFX application thread, (which it probably does or you probably wouldn't have this question), then you should probably run the loop in a Task, on a different thread, updating the task's progress as the loop progresses and binding the progress bar's value to the task's progress.
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ProgressFeedback extends Application {
private static final double EPSILON = 0.0000005;
#Override
public void start(Stage stage) throws Exception {
final Task<Void> task = new Task<Void>() {
final int N_ITERATIONS = 100;
#Override
protected Void call() throws Exception {
for (int i = 0; i < N_ITERATIONS; i++) {
updateProgress(i + 1, N_ITERATIONS);
// sleep is used to simulate doing some work which takes some time....
Thread.sleep(10);
}
return null;
}
};
final ProgressBar progress = new ProgressBar();
progress.progressProperty().bind(
task.progressProperty()
);
// color the bar green when the work is complete.
progress.progressProperty().addListener(observable -> {
if (progress.getProgress() >= 1 - EPSILON) {
progress.setStyle("-fx-accent: forestgreen;");
}
});
// layout the app
final StackPane layout = new StackPane(progress);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
final Thread thread = new Thread(task, "task-thread");
thread.setDaemon(true);
thread.start();
}
public static void main(String[] args) {
launch(args);
}
}
what if the task makes call to a method that does only a single job , and do not want it to be called again and again?
Then remove the loop and invoke updateProgress through multiple calls within the job as the job progresses. The loop is only present in this sample for demonstration purposes and because this is what the original question specifically asked about.
For example lets say your job has 3 stages: fetch from database, perform calculation and accumulate results. Each stage taking an estimated 30 percent, 60 percent and 10 percent of total time respectively, then you can do something like this within the call() body of your task:
updateProgress(0, 1.0);
Data data = db.fetchData(query);
updateProgress(0.3, 1.0);
ProcessedData processed = calculator.process(data);
updateProgress(0.9, 1.0);
Result result = accumulator.reduce(processed);
updateProgress(1.0, 1.0);
Quotation from Java Doc:
The actual progress of the ProgressIndicator. A negative value for progress indicates that the progress is indeterminate. A positive value between 0 and 1 indicates the percentage of progress where 0 is 0% and 1 is 100%. Any value greater than 1 is interpreted as 100%.
That means in simple words, you must divide you value with 100, or you just increment the value by 0.05 instead of 0.5.
Happy Coding,
Kalasch
My friend show me example of using that. You could do this:
Platform.runLater(new Runnable() {
#Override public void run() {
bar.setProgress(counter/1000000.0);
}
});
And the refresh progress bar is in other Thread

Categories

Resources