Ok, so i have a problem with javafx, the netbeans 6.9.1 version that is (i know it's a bit old but i have to do this for a final assignement for school). So for the assignement i have to code a memory game (concentration). Now i want to program a delay so when i flip a card the function waits for like 1.5 seconds so that you can see the turned card. however, when i make a while loop to wait for the 1.5 second mark the program just freezes and the variable "time02" won't update. i then have to manually shut the program down via task manager because it just freezes. Here's a snippet of the code with the timeline and a small piece of the function. i also included the timeline for the clock which weirdly enough updates the variable "time01" just fine. I also put the code for delay in a comment.
clock = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: KeyFrame {
time: 0.1s
action: function() {
updateclock();
}
}
}
function updateclock() {
time01 = time01 + 1;
text2.content = "Tijd: {time01 / 10}";
}
/*
delay = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: KeyFrame {
time: 0.1s
action: function() {
updatedelay();
}
}
}
function updatedelay() {
time02 = time02 + 0.1;
}
*/
function control() {
if (counter == 2) {
/*
while (time02 < 1.2) {
delay.play();
}
delay.stop();
time02 = 0;
*/
..............................
Any type of help would be very much appreciated!
It's treading issue. You can't wait for something which is calculated on the same thread.
You can put code which flips card back into the Timeline to make JavaFX care about threading instead of you.
backflip : Timeline {
repeatCount: 1
keyFrames: KeyFrame {
time: 1.5s
action: function() {
// here is code which flips card back
}
}
}
Related
I'm trying to create something like an info screen that just scrolls through images (and maybe one day pdfs) that are uploaded with a small managment app I wrote.
After some reading I think I understand why I should NOT have Thread.sleep in my for loop. I read some posts on stackoverflow and other pages that teached me not to do it.
Apparently I'm supposed to use ExecutorService for something like this, but I can't wrap my head around it.
So after preparing my GUI and everything else I finally call my showImages and stay in this while loop.
After each loop I reload the records from the file systems, so any changes are represented on the screen.
I created a metafile containing the preferred delay for each image and just sleep for the amount of time.
private void showImages() {
//noinspection InfiniteLoopStatement
while (true) {
loadRecords();
for (ImageRecord record : records) {
System.out.println("Showing: " + record.getFilename());
imageLabel.setIcon(record.getIconForInfoScreen(screenWidth, screenHeight));
int delay = record.getDurationAsInt();
System.out.println("Waiting for " + delay + " milliseconds");
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
So if I understand correctly I could use something like
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(showImage(),0, delay, TimeUnit.MILLISECONDS);
But this would trigger the showImage() every "delay" millisecond and I still need to increment some counter, to get to the next image in my records.
Could someone push me in the right direction? I'm kinda lost at the moment.
All the comments on my question can be considered good ideas an and one of them also lead me to my final result. But it in the end, the matter was, that I did not understand how to implement a timer into my loop.
Or in other words, the loops had to be gone and instead use a counter and set the delay for the follow up record inside the timer loop.
private void loopImages() {
loadRecords();
recordSize = records.size();
int delay = records.get(1).getDurationAsInt();
timer = new Timer(delay, e -> showImages());
timer.start();
}
private void showImages() {
if (recordIndex == recordSize) {
loadRecords();
recordSize = records.size();
recordIndex = 0;
}
ImageRecord record = records.get(recordIndex);
imageLabel.setIcon(record.getIconForInfoScreen(screenWidth, screenHeight));
recordIndex++;
if (recordIndex < recordSize) {
record = records.get(recordIndex);
int delay = record.getDurationAsInt();
timer.setDelay(delay);
}
}
I am trying to build an analog stopwatch. There is a button that when I click, the stopwatch starts counting in seconds.
Note that this code runs okay (technically) but there is something wrong in terms of my "java language"-based logic or/and my thinking-based logic. Also I know that my stop watch would have some marginal error within milli seconds. There are two print out statements that can check my logic. Note that I have some C coding experience but new to this. EDIT: The platform is javaFX
Now, I am facing 3 problems with this code.
The three problems technically written:
1- The second print out statement's output is same as the first one's. i.e, my IF statement is not working since temp + 1 is still equal to the current number of seconds although this is impossible if we consider the fact that the lines of codes, between them, are executed faster. UPDATE: THIS, (1), IS SOLVED.
2- Ignoring problem (1), my image does not rotate although it should have since the IF statement is executed. Note that I am using stackpane and I added that image to my layout but it just sticks at 0 degrees and is not doing any thing.
3- The While loop itself is not working either even if I wait too much of time. I am not sure if it is "okay" or not to use a while loop inside an event handling method.
The three problems structurally written:
1- N/A
2- Would it be possible for me to update my layout elements continuously in an event method from inside the even method using loops and not by using the button or something else?
3- Same as (2)
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
int temp = 0;
Calendar calendar = Calendar.getInstance();
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
temp = calendar.get(Calendar.SECOND);
int temp2 = temp + 60;
int counter = 1;
do {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
if ((temp + 1) == calendar.get(Calendar.SECOND)) {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
imageHolder2.rotateProperty().set(6.0 * counter);
counter++;
temp = calendar.get(Calendar.SECOND);
}
} while (temp2 != (calendar.get(Calendar.SECOND) + 60));
}
});
1) I think you are just seeing the first System.out.println(...) (from before the loop) and the first one in the loop, which will produce the same output (except in the very rare (a few occurrences per million runs?) circumstance that the seconds "tick over" during execution of the three lines of code in between).
2) This is the real issue. Your loop is running (busily) in the FX Application Thread (because it is invoked by an event handler). This is the same thread that is used to update the UI and process events. Because you are keeping this thread busy, it will not have any opportunity to update the UI until your loop finishes. You need to either execute this loop in a background thread, and schedule the UI updates on the FX Application Thread, or (much much easier) use the animation API to do this.
3) You have a bunch of bugs in your logic. (1) You assign calendar before you start the loop, and never update it; so it will always represent the instant the handler starts. (2) You assign temp2 to be seconds + 60 and then your loop condition is temp2 != seconds + 60, which obviously is false, so the loop exits. Even if you update calendar on the loop iteration, it is extremely unlikely the seconds field changes in during the first iteration of the loop, so you will almost certainly exit the loop immediately. (3) If you update calendar, the seconds field will always be a value between 0 and 59 (inclusive), i.e. it will "wrap" at 60. temp2 will always be at least 60, so once you fix bugs (1) and (2) your loop will never exit... (4) if (temp + 1 == calendar.get(Calendar.SECONDS)) will fail when the minutes tick over, because 60 != 0, so your iteration will stop as soon as that happens.
You can use a Timeline to do this:
#Override
public void handle(ActionEvent event) {
Timeline timeline = new Timeline(
// key frame that updates rotation on each second:
new KeyFrame(Duration.seconds(1), e -> {
imageHolder2.setRotate(imageHolder2.getRotate() + 6);
System.out.println("Seconds in current minute = " + Calendar.getInstance().get(Calendar.SECOND));
})
);
// repeat 60 times:
timeline.setCycleCount(60);
timeline.play();
}
If you want to use your original code, you need to wrap it in a background thread, and schedule the UI updates on the FX Application Thread. As noted above, there are multiple other bugs in your code. Here is a version with the logic fixed:
#Override
public void handle(ActionEvent event) {
Thread thread = new Thread(() -> {
int temp = 0;
Calendar calendar = Calendar.getInstance();
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
temp = calendar.get(Calendar.SECOND);
int counter = 1;
do {
calendar = Calendar.getInstance() ;
if (temp != calendar.get(Calendar.SECOND)) {
System.out.println("Seconds in current minute = " + calendar.get(Calendar.SECOND));
double rotation = 6.0 * counter ;
Platform.runLater(() -> imageHolder2.rotateProperty().set(rotation) );
counter++;
temp = calendar.get(Calendar.SECOND);
}
} while (counter <= 60);
});
thread.setDaemon(true);
thread.start();
}
Finally, note you can also just do this:
#Override
public void handle(ActionEvent event) {
RotateTransition animation = new RotateTransition(Duration.seconds(60), imageHolder2);
animation.setByAngle(360);
animation.play();
}
I need to add time delay between cycle flow like this:
public boolean timeDelay(int seconds) {
// 1000000000 ns = 1 s
if (/* some system method to start calculate time in seconds*/ == seconds) {
return true;
} else {
return false;
}
}
public void renderEnemies() {
for (int w = 0; w < wave.size(); w++) {
while(timeDelay(2)){
(wave.get(w)).render();
}
}
}
Maybe my thinking isn't good, but I need to do like this...
wave --> ArrayList of enemies in my game
Render enemies is in game loop after pressing button "NextWave" and I need to spawn them with delay between them like a --> 2s * 2s * 2s * 2s * 2s *
where * is enemy...
Can you help me?
Try:
Thread.sleep(1000);
and use a try-catch.
You should probably thread it and use sleep as #curiosu mentions.
However, if you don't want to use sleeps/multiple threads but do want it to be pseudo real time (not turn based) you'll need a driving loop at the top of your game like so:
boolean keepPlaying = true;
while(keepPlaying) {
doNpcStep()
doPlayerStep()
keepPlaying = !isGameOver()
}
Each of these steps needs to run in a very small time slice, then in the doNpcStep function you get the current time, find the offset from a start time and run any action that should happen by now.
You could, for example, do this by keeping a min priority queue where priority is equal to the time they should execute by (in ms since start of java epoch). Then take all elements off the queue that are less than or equal to current time and run them, placing new occurrences onto the queue as necessary.
In essence this is a simulation of running a player and npc thread, where you are in charge of how much time each gets to run for.
try putting an infinite while loop
while(1)
{
if(/*method to calc time*/ == seconds)
return true;
}
return false;
I'm assuming that you want to start spawning enemies after 'seconds' time, so always a 'true' should be returned after 'seconds' time has passed. Your method should keep track from what time it has to start counting the seconds. You can call that function when 'NextWave' button is pressed where a variable can increment itself in multiples of 'seconds' so that you can keep track of elapsed time.
Hope this helps.
Recently, I've been getting into Java Game programming. I have learned Java before, but this is my first time with Graphics, Game Loops etc.
I followed this tutorial for a Game Loop, and it's working pretty well.
There is nothing wrong with it, but I just can't figure out why I am thread.sleeping the code, and whats the point of it.
If anyone could explain what start, elapsed and running do, and why I am doing thread.sleep(wait) then I would be super appreciative!
GAME LOOP (Remember, it works, I just don't know why):
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (Exception e) {
Game.logger.log("ERROR! Printing Stacktrace...");
e.printStackTrace();
}
}
}
Well, running is a flag that can be set to false to terminate the game.
start and elapsed are used to measure the time one round in the loop took. You are waiting to not make the game run too fast. If you are moving elements with a set speed, then having the game loop run too fast makes them also move too fast. That can lead to a bad user experience, since the user might not be fast enough to play the game.
Additionally, any animation doesn't run smooth anymore without the waiting. It will speed up and slow down depending on how fast your code executes.
Just continue with the tutorial, and when are at the point where you make something move, remove the waiting and see what happens.
EDIT
The code makes a round in the loop take about targetTime. It's unit is milliseconds. So to calculate the frame rate, just divide 1000 / targetTime.
start is the time before the game logic runs. elapsed is the amount of time that it takes for the game logic to run. running is a boolean (true/false) variable that determines whether the game should continue. Thread.sleep(wait) is a method that delays for a certain amount of time.
The goal is to keep the amount of time between frames roughly constant by delaying, so that the animations don't run faster or slower depending on how fast your computer processor is running.
It appears the code aims to be executed targetTime seconds. So you count how much time has already passed (elapsed), and then calculate how much to wait (divide it to get your remaining time in miliseconds, required for methon sleep(wait)).
One purpose of such waiting is often forcing some time between repainting to the screen.
To get your FPS, one way would be to slightly change your code:
long prevStart = 0; //just initialize. First FPS is of course wrong, next get fine.
double FPS = 0;
while (running) {
start = System.nanoTime();
FPS = 1 / double(start - prevStart);
prevStart = start;
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (Exception e) {
Game.logger.log("ERROR! Printing Stacktrace...");
e.printStackTrace();
}
}
Below I have a Runnable "updater" ...and an OnClick function that uses Handler.PostDelayed function to run the runnable after a delay...
After a little editing, cutting of useless parts here are the functions:
(passtog = Toggle Button)
final Runnable updater = new Runnable() {
#Override
public void run() {
if (passTog.isChecked()) {
now = System.currentTimeMillis();
time = now - init;
if (time > 5000) {
Toast.makeText(getApplicationContext(), "WAKE UP !",
Toast.LENGTH_SHORT).show();
}
handler.postDelayed(this, 25);
}
}
};
passTog.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
init = System.currentTimeMillis();
flag = true;
handler.postDelayed(updater,
(new Random().nextInt(4000) + 3000));
}
});
}
Explaination
Basically, The user toggles the Toggle button. Now it's on: The runnable can run completely (Everything is in the if block).
If the user doesn't press the button again, and switches it off The app sends a Toast "Wake Up!" ..It runs and checks every 25 millisecs to update the time...
Pretty straightforward... Yet I'm having a problem.
Before the program actually gets to the runnable, I absolutely NEED there to be a minimum time delay of 3 seconds + Some Random value ... So it varies between 3 sec - 7 sec. It SHOULD vary between 3-7 , but it doesn't.
When I run it: The problem
I notice that the first time, it works great... I get atleast a 3 sec delay + a random value= Perfect
The second time, that is after the switch goes on ->off-> on : Now It acts like it doesn't see the +3000 ...and just the ~randInt(4000) function... So it may give 0 sec or it may give 4 sec delay...
In all my experience, I've never really come across this.. I've rewritten the entire code, My other apps use this function in exactly the same sytax and seem to do pretty great.. Why is this creating a problem ? Could the Toast's time possibly be causing a problem..
How to solve this ?
(I'm open to other methods, preferably quick to implement. I want a minimum 3 sec delay which I'm not getting for some reason... I need the UI to be responsive though So no thread sleeping.)
You probably should call Handler.removeCallbacksAndMessages(null) when the switch goes off.