Weird nested-if statement execution - java

I have this interesting problem with some code I wrote in Java. I am executing this code in in the latest version of eclipse with jdk-17.0.1. The purpose of the code is to take a screenshot of my screen every couple of milliseconds, but only if running is true. At the start, running is false. I can set running to be true by hitting a certain key. Here is the code
double timePerTick = 1_000_000_000/fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
while (true) {
now = System.nanoTime();
delta+= (now-lastTime)/timePerTick;
lastTime = now;
if (delta >= 1) {
//for some reason code only works if this print statement here
//System.out.println("WOWEE");
if (running) {
//Create rectangle screen-capture around cursor
BufferedImage image = robot.createScreenCapture(new Rectangle(0,0, width, height));
try {
output.write(("Capture taken \n").getBytes());
System.out.println("WRITTEN!");
} catch (IOException e1) {
// TODO Auto-generated catch block
System.out.println("BRUH!");
e1.printStackTrace();
}
}
delta--;
}
}
The problem is that the if (running) statement never runs, even when running is true. However, when I uncomment the System.out.println statement after the if(delta) code, it works perfectly well. Like this:
double timePerTick = 1_000_000_000/fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
while (true) {
now = System.nanoTime();
delta+= (now-lastTime)/timePerTick;
lastTime = now;
if (delta >= 1) {
//for some reason code only works if this print statement here
System.out.println("WOWEE");
if (running) {
//Create rectangle screen-capture around cursor
BufferedImage image = robot.createScreenCapture(new Rectangle(0,0, width, height));
try {
output.write(("Capture taken \n").getBytes());
System.out.println("WRITTEN!");
} catch (IOException e1) {
// TODO Auto-generated catch block
System.out.println("BRUH!");
e1.printStackTrace();
}
}
delta--;
}
}
In the first code, nothing gets printed, but in the second code, WOWEE gets printed over and over again. By the way, if running is true at the start, then both codes work fine. However, if you switch from running = false to running = true, the first code never prints anything, but the second code goes from printing nothing to printing WOWEE. Is there any reason for this?
By the way, output is a FileOutputStream instance if that is necessary info.

user16320675 found the answer to my problem in the comments, but for some reason they deleted their comments. I waited to see if they'd come back, but they didn't. So, I will post the information they gave me. The reason my program didn't work is because the variable "running" was being accessed by multiple threads, one thread being the main thread, and the other thread being the one that monitors keyboard input. When a piece of memory is being accessed by multiple threads, you must declare it as "volatile" to make sure synchronization issues don't happen. Like this
public static volatile boolean running;
More information here https://www.baeldung.com/java-volatile

Related

How to create a countdown timer in a Java Applet?

I'm working on a final project for school with a Java applet that counts down from a given interval to zero. When a Rectangle on screen experiences a mouse down event, it is supposed to execute the timer; however this does not occur; the program ends up crashing. I've seen a lot of examples of timers online, but many are using Java's built in timer class, which I am not using. I figured there must be a more basic way to do a simple timer. All variables have been declared at the top of the class.
public boolean mouseDown(Event e, int x, int y)
{
if(start.inside(x,y))
{
timerAct = true;
startTime = System.currentTimeMillis() / 1000;
endTime = startTime + interval;
while (System.currentTimeMillis() / 1000 < endTime) {
while (startTime != System.currentTimeMillis() / 1000) {
startTime += 1;
timeLeft = (endTime - startTime);
}
}
timerAct = false;
}
repaint();
return true;
}
The logic seems to workout okay because this began as System.out.println(), and it worked just fine. Then, it was converted to store the variable timeLeft. In the paint method, I have
g.drawString("Time: " + timeLeft, 420, 180);
to print the the time remaining. I also have the update method; but it doesn't seem to make a difference. And I know the issue isn't because I'm changing a variable. My mouse down method has an if statement with a different rectangle that tracks clicks (not shown), and it updates a counter of clicks on screen in the applet window without any issue. Any help is greatly appreciated.
Check this. It's pretty self explanatory.
Here's how you would code a simple countdown timer. This code needs to be run in a separate thread and not the Event Dispatch thread.
private void countdownTimer(int intervalSecs) {
long endTime = System.currentTimeMillis() + (intervalSecs * 1000L);
while (System.currentTimeMillis() < endTime) {
sleep();
repaint();
}
}
private void sleep() {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
panel.repaint();
}
});
}

Calculate FPS in Java Game [duplicate]

This question already has answers here:
Calculating frames per second in a game
(21 answers)
Closed 9 years ago.
Yesterday I wrote a Thread addressing how my game loop ran (in java) and how it works.
My game loop works completely, and I know why, but now I just wan't to know how to calculate FPS (Frames Per Second) and print it out every second.
I got a response yesterday about this, but he/she explained it in words and I couldn't understand it.
If anyone could help me (with a code example? :D) that would be great.
Here is my game loop:
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();
}
}
ALSO:
In my JFrame when ever I call setName(string) it never works/updates on the Frame - Link me to a thread?
The easiest way to do this is to keep a variable whatTheLastTimeWas stored and doing this where you want to check your frame rate:
double fps = 1000000.0 / (lastTime - (lastTime = System.nanoTime())); //This way, lastTime is assigned and used at the same time.
Alternatively, you can make a FPS counter like so:
class FPSCounter extends Thread{
private long lastTime;
private double fps; //could be int or long for integer values
public void run(){
while (true){//lazy me, add a condition for an finishable thread
lastTime = System.nanoTime();
try{
Thread.sleep(1000); // longer than one frame
}
catch (InterruptedException e){
}
fps = 1000000000.0 / (System.nanoTime() - lastTime); //one second(nano) divided by amount of time it takes for one frame to finish
lastTime = System.nanoTime();
}
}
public double fps(){
return fps;
}
}
Then in your game, have an instance of FPSCounter and call nameOfInstance.interrupt(); when one frame is finished.
You can combine a simple counter and Timer.scheduleAtFixedRate for this.
Disclaimer: I don't know if this is the best method; it's just easy.
int totalFrameCount = 0;
TimerTask updateFPS = new TimerTask() {
public void run() {
// display current totalFrameCount - previous,
// OR
// display current totalFrameCount, then set
totalFrameCount = 0;
}
}
Timer t = new Timer();
t.scheduleAtFixedRate(updateFPS, 1000, 1000);
while (running) {
// your code
totalFrameCount++;
}

Java Timer Speeds Up Every Execution

Every time my timer is run, the code executed inside the timer is run faster. Why is this happening?
This code essentially moves a label (holding an image) across the frame.
Every run, the images moves faster.
if (Player.direction == "west") {
timerWest.start();
isCasting = true;
new Magic("westmagic.gif");
timerWest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int x = Frame.fireMagicLabel.getX();
int y = Frame.fireMagicLabel.getY();
Frame.fireMagicLabel.setLocation(x - 1, y);
LiveUpdating.updateSpell();
CheckHits.spellHit();
Frame.frame.repaint();
if (Frame.fireMagicLabel.getX() <= tempWest) {
timerWest.stop();
new Magic("");
Frame.frame.repaint();
Frame.fireMagicLabel.setLocation(
Frame.redHealthLabel.getX(),
Frame.redHealthLabel.getX());
isCasting = false;
}
}
});
Frame.frame.repaint();
}
On first run, the timer performs x speed. Then the the next run it performs faster, and faster, and faster.
i think you should add the action listener only once.
Ther actionlistener is only needed to be added once.
Also if this does not fix it, somewhere inside the code you haven't posted you apply the speed, this might not be reset and be added on it, which makes it double speed.

Java Applet, game loop runs fine the first time, and then when reset, updates at half the speed

so for the game I'm creating I realized I mist have done something wrong with my gameLoop because the first time I play through my game it runs great, but the second time or anything after that, it slows down by about half. Even if I minimize the game (Because that stops the gameLoop, and then bringing it up again starts it back up) here is the gameLoop code:
public void gameLoop(){
new Thread(){
public void run() {
while(gameRunning){
try {
Thread.sleep(1000/60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (tutorial){
updateBullet();
updatePlayer();
repaint();
} else {
updateEnemies();
updateBullet();
createEnemies();
updateParticles();
updatePlayer();
repaint();
}
}
repaint();
}
}.start();
}
I start it for the first time in the init() just with
gameLoop();
And then I also have:
public void stop(){
bg.stop();
gameRunning = false;
}
public void start(){
bg.start();
gameRunning = true;
gameLoop();
}
And finally the playerUpdate also stops the loop with (The Thread inside of player is to allow for some effects to finish after the player dies):
public void updatePlayer(){
if (player.isMovingLeft){
player.x-=3;
}
if (player.isMovingRight){
player.x+=3;
}
for (int j=0; j < enemies.size(); j++){
if (player.isAlive){
if (enemies.get(j).x+19 > player.x && enemies.get(j).x < player.x+40 && enemies.get(j).y > player.y && enemies.get(j).y < player.y+40) {
enemies.remove(j);
j--;
explode.setFramePosition(0);
explode.start();
for (int k = 0; k <21; k++){
addParticle(player.x+20,player.y+20,2);
}
new Thread(){
public void run() {
try {
Thread.sleep(2000);
gameRunning = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
player.isAlive = false;
break;
}
}
}
}
And then it is restarted with in the keyPressed event:
if (!gameRunning){
if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
enemies.clear();
bullets.clear();
particles.clear();
score = 0;
player.x = 200;
player.isMovingLeft = false;
player.isMovingRight = false;
player.isAlive = (true);
gameRunning = true;
gameLoop();
}
}
So why is it that whenever the loop is stopped and started again, it runs at half the speed? Thanks!
It looks like you're starting a new thread for each gameloop; this means each time the gameloop runs, you've got another thread for the Java VM to handle. This is extremely inefficient, as eventually you'll have 1000 threads running, causing HUGE lag. Is there any way you could rewrite your code without threading there?
Also, what is this supposed to do?
try {
Thread.sleep(1000/60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Why would you do 1000/60? A: Why not just use 16? B: It seems like you meant something else here, not sure what though
Also, what is the bg variable your reference in your start() and stop() methods?
It looks like you are trying to stop the thread by using the gameRunning boolean. If this is not volatile, then the game loop may not notice changes from the GUI thread that sets it to false and will run forever. Even if it is volatile, you have a race condition if start is called again before the game thread notices the stop command.
You should instead store a reference the the created thread and interrupt it in your stop method.
Also are all your update methods thread safe with respect to the paint method. updatePlayer doesn't look thread safe, and you don't know when paint will be called so it could happen at the same time as your update method. Even if the paint method doesn't write to the shared data, it could still see inconsistent data due to lack of a memory barrier.
I'd suggest doing all the updates in the GUI thread unless it is very slow and you need the multithreading. Look at using a Timer from Swing to to initiate your update logic.

progressbar in a thread does not update its UI until the work was done in the main thread

i am cutting a big file into blocks, and want to display the rate of the progress.
when i click startCut Button, here is the code to execute:
FileInputStream in = new FileInputStream(sourceFile);
int blockSize = (int)(getSelectedBlockSize() * 1024);
int totalBlock = Integer.parseInt(txtNumberOfBlock.getText());
byte[] buffer = new byte[blockSize];
int readBytes = in.read(buffer);
int fileIndex = 1;
class PBThread extends Thread
{
#Override
public void run()
{
while(true)
{
pbCompleteness.setValue(value);
//value++; //place A
System.out.println(value);
if (value >= 100)
break;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
value = 0;
PBThread pbThread = new PBThread();
pbThread.start();
while(readBytes != -1)
{
File file = new File(targetFilePath + fileIndex);
FileOutputStream out = new FileOutputStream(file);
out.write(buffer, 0, readBytes);
out.close();
value = (int)(fileIndex / (double)totalBlock * 100);// place B
readBytes = in.read(buffer);
fileIndex++;
}
i change the value of the progressbar outside the run method at place B,the problem is that --the grogressbar only show two state: 0% and 100%.
but, if i take away the code in place B, and change the value of the progressbar inside the run method at place A, the problem will disappear.
i know maybe with SwingWorker it can be fixed easily, but i do want to know why this happen,although i change the value out the run method,when i print it out in the run method,it did changed.
how can i fix that problem while changing value outside the run method?
The crux of the problem is that you're updating the component: pbCompleteness on a thread other than the Event Dispatch Thread. You can remedy this using SwingUtilities.invokeLater from within your run() method; e.g.
AtomicInteger value = new AtomicInteger(0);
while (true) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pbCompleteness.setValue(value.get());
}
});
// Do some work and update value.
}
This will cause the JProgressBar to be updated (and repainted) on the Event Dispatch thread as your worker thread continues to run. Note that in order to refer to value within the "inner" anonymous Runnable instance I have changed it to be an AtomicInteger. This is also desirable as it makes it thread-safe.
You've got two problems here:
You're doing long-running work in the Swing dispatcher thread, which means you're stopping it from processing events. (Try moving windows around etc - it will fail.)
You're updating the UI from the wrong thread at point A. It sounds like you're getting away with this at the moment, but it's still a bug.
You should use SwingWorker or SwingUtilities to address both of these issues. Basically, you mustn't access the UI from a non-UI thread, and you mustn't do long-running work on a UI thread. See the Swing concurrency tutorial for more information.
i found a very simple way to this prob :D . you can use this code and very simlpe handel this error :).
int progress=0;
Random random = new Random();
while (progress < 100) {
//Sleep for up to one second.
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException ignore) {}
progress+=1;
progressBar.setValue(progress);
Rectangle progressRect = progressBar.getBounds();//important line
progressRect.x = 0;
progressRect.y = 0;
progressBar.paintImmediately(progressRect);//important line
}

Categories

Resources