How do I only delay a specific method? - java

I am still a very early coder and still don't know everything about java so my code is still a bit messy, sorry about that. I am making a simple platformer game with the graphics g class and I'm trying to figure out how to delay a method without pausing the entire script.
I have tried Thread.sleep() and TimeUnit.SECONDS.sleep() but both of these freeze other methods running at the time, and the Timer that keeps the game running.
private static Timer timer;
private int delay = 10;
public Gameplay() {
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
timer = new Timer(delay, this);
timer.start();
}
public void moveDown() {
if (play == true) {
Playsound("drop");
dropping = true;
//pause here for 1 second without freezing timer or other running methods
dropping = false;
}
}
I want the program to continue running while waiting, but the things I have tried always freeze the entire program

One trick from my side
public void moveDown() {
if (play == true) {
Playsound("drop");
dropping = true;
//create a thread which will execute your method and set sleep on that thread
dropping = false;
}

try this
...
Thread thread = new Thread(() -> moveDown());
thread.run();
...
void moveDown() {
//do some work
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//continue your work
}
explanation
you need to stop thread , but you dont want to stop current thread :)
that means you need to run your work on background thred and stop only it,
this is not best solution , its just for explanation how you can do it.

Related

Java Thread.sleep() causing JFrame to flicker when resized

So I have a game that I'm trying to make and in the game loop, I call Thread.sleep(). Else where, I have code that maintains the aspect ratio of the window when resizing. This works great, except that I get weird flickering when I'm resizing. I've narrowed the problem down to Thread.sleep(), when I take this line out, my program works just as expected, but this causes the CPU to spike so high that on my Macbook, the Activity Monitor app says my game is using 170+%! Now this is problematic and exactly why I put the sleep line in there anyway. I've heard that sleeping on the event dispatch thread will cause this effect, but I am running this loop in a new thread, so I thought I was good. Do you guys know what could be going on? Here's part of the source code (you really need to look at the run() method):
package jeffrey_ryan.game2d;
public class GameLoop implements Runnable {
private boolean running = false;
private boolean paused = false;
private float gameHertz = 30.0f;
private long timeBetweenUpdates = (long) (1_000_000_000 / gameHertz);
private int maxUpdates = 5;
private LoopListener loopListener;
public void run() {
long lastUpdateTime = System.nanoTime();
running = true;
while (running) {
long now = System.nanoTime();
if (!paused) {
int updates = 0;
while (now - lastUpdateTime >= timeBetweenUpdates && updates < maxUpdates) {
if (loopListener != null) {
loopListener.update((double) timeBetweenUpdates / 1_000_000_000);
}
lastUpdateTime += timeBetweenUpdates;
updates++;
}
if (loopListener != null) {
float interpolation = Math.min(1.0f, (float) (now - lastUpdateTime) / timeBetweenUpdates);
loopListener.render(interpolation);
}
long timeRemaining = (timeBetweenUpdates - (now - lastUpdateTime)) / 1_000_000;
try {
Thread.sleep(Math.max(timeRemaining - 5, 0)); // HERE'S THE OFFENDING LINE ******************
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
else {
try {
Thread.sleep(25);
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
public void start() {
running = true;
}
public void stop() {
running = false;
}
public void pause() {
paused = true;
}
public void play() {
paused = false;
}
public float getSpeed() {
return gameHertz;
}
public void setSpeed(float hertz) {
gameHertz = hertz;
timeBetweenUpdates = (long) (1_000_000_000 / gameHertz);
}
public int getMaxUpdates() {
return maxUpdates;
}
public void setMaxUpdates(int updates) {
maxUpdates = updates;
}
public void setLoopListener(LoopListener listener) {
loopListener = listener;
}
}
In my subclass of JPanel, here's the code that runs this loop (Where the loop variable is an instance of the above class):
#Override
public void addNotify() {
super.addNotify();
addKeyListener(this);
addMouseListener(this);
Thread thread = new Thread(loop, "GameLoop");
thread.start();
}
If you guys could help me I would love it, I'm really stumped. Thanks!
You should use SwingWorker instead of a Thread to manipulate Swing components asynchronously. When I discovered this guy my life changed =). The SwingWorker gives you a method "process" which you can use to make actions gradually, and a "done" method to finish your processing, both of these methods are safe to handle the event dispatch thread. The background process you should make on "doInBackground".
Calling 'Thread.sleep(n)' causes the whole thread to become unresponsive, if this thread is tied to your JFrame thread then that thread will also become unresponsive and cause the whole frame and component to freeze and stop responding -- probably the reason for the flickering. So make sure the sleep is in game loop and not on the frame, one way to do this is create two threads at initialization, one for the frame and the other for the logic, then just let the game loop handle input and output while the display thread simply displays (i believe this how most game engines work). Also make sure neither thread is linked in any or the sleeping thread will affect the display thread.
I found the answer to my problem. The class that was calling the loop, which was a JPanel, didn't repaint when resized, only when the loop told it to, which caused some periods where the JPanel wasn't painted too. I fixed this by overriding paintComponent.

Update jProgressBar from another thread

I'm new in java. I'm trying to understand thraeads and timers in java. It was big problem for me to undate ProgressBar from another thread. I read many posts and found answers. So can you say is this the best way to resolw my task. So, what I want is to run second thread and when it's done, stop progress bar and change text on the button. So I creat Frame with button and progress bar in Test class:
After I realize action listener for Button to run second thread:
public class Test extends javax.swing.JFrame {
RunBg thread = new RunBg();
....
// declaration for button, progressbar and main() method
....
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
// needed to check is the thread running at first time else creat new object and rund hread again cause thread can be executed once
if(thread == null){
thread = new RunBg();
}
if (jProgressBar1.isIndeterminate()) {
jProgressBar1.setIndeterminate(false);
jButton1.setText("Run!");
thread.suspend();
} else {
jButton1.setText("Working...");
jProgressBar1.setIndeterminate(true);
// let us know is the second thread running or nope so we can know resume it or pause
if (thread.isAlive()) {
thread.resume();
} else {
thread.start();
}
timer.start();
}
}
/*
Then I creat timer to know is my thread still alive else change Progress bar and button
*/
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(!thread.isAlive()){
thread.stop();
jProgressBar1.setIndeterminate(false);
jButton1.setText("Запустить!");
timer.stop();
// thread.interrupt();
thread = null;
}
}
});
...
// end of class
}
And my second class for another thread named RunBG:
public class RunBg extends Thread{
int i = 0;
public void run(){
while(i<20000){
System.out.println(">>>"+i);
i++;
}
System.out.println("<<<Finished>>>");
}
}
Everythig works fine , but I have question. Is there a better way to realize my task or maybe I made some mistakes. Also I thik that my code will help another beginners who looking for help to understand how it's work.

Having Issues With Java Swing Timer and Infinite Loops

I am having an issue with a piece of my code in Java, it seems to be creating an endless loop.
public void progress(){
x = 3;
timer = new Timer(800, new ActionListener() {
public void actionPerformed(ActionEvent evt){
System.out.println(x);
x--;
if(x < 1){
UI();
timer.stop();
}
}
});
timer.start();
}
The method UI asks for input via SavitchIn, and it doesn't seem to run the line. I print before I ask for input in the UI method, and the print works just fine. When I remove this timer from my code, and keep the UI method the same, it works fine. Prints and then takes input. I've added a timer.stop() in UI method as well, and I am positive the timer is stopped, however after running the program I am forced to Reset the Virtual Machine the next time around otherwise it wont run. Any help is appreciated!
Your UI() method likely should be called on a background thread as it is likely tying up the Swing event thread (this we have to guess since you don't show it). So create a SwingWorker or a background thread and do this call in there. For more on this, please read Concurrency in Swing.
e.g.,
public void progress() {
x = 3;
timer = new Timer(800, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println(x);
x--;
if (x < 1) {
new Thread(new Runnable() {
public void run() {
UI();
}
}).start();
timer.stop();
}
}
});
timer.start();
}

How to destroy a thread?

I'm making simple game, here is the code:
public class Game extends Canvas implements Runnable {
public void start() {
t = new Thread(this);
t.start();
}
#Override
public void run() {
setVisible(true); // visibility of the thread turn on
while (!t.isInterrupted()) {
if(condition for end the game) {
t.interrupt(); //here i need to destroy the thread
setVisible(false); //visibility to off
}
update();
render();
try {
Thread.sleep(20);
} catch(InterruptedException e) {}
}
}
}
I have another class which extends JFrame and this class is introducing main menu, if my "condition for end the game" is true, the thread dissapears and the menu is visible again, its good, but if i want to start new game again, the behavior of the thread is strange- its seems like the Thread.sleep() method changed from 20 to 10 because all its going faster, probably i need to kill the thread, but i dont know how, thanks
Simple, break the loop:
if(condition for end the game) {
t.interrupt(); //here i need to destroy the thread
setVisible(false); //visibility to off
break;
}
You end the loop and the thread will end.
The easiest way to terminate a Thread is to exit the run function. There is no special handling required, a simple return does the trick.
For you game you might want to consider using a ScheduledExecutorService, which allows you to schedule a Runnable to run at a fixed rate:
executor.scheduleAtFixedRate(gameLoop, 0, 1000/TARGET_FPS, TimeUnit.MILLISECONDS);
Keep in mind that you then need to take out the actual looping of your gameLoop, because that is done by the fixed-rate calling, which will reduce it to:
public void run() {
if (pause == false) {
update();
render();
}
}
Where pause is a boolean should you for some reason want to put the rendering on pause for a while.
With this setup you can terminate the game simply by calling executor.shutdown() which will then suppress any further calls to the runnable.
Not really on-topic, but I'm making a game too, and for pacing I'm using Timer (from swingx):
public class MainGameLoop implements ActionListener{
Timer timer;
public static void main(...){
timer = new Timer(10, this);
timer.start();
}
public void actionPerformed(ActionEvent e) {
...
}
}
Working well to me.

java: stop thread on ESC

I am writing a simple game in Java, and I have a following issue:
I have a controlling class, called MainGameFrame, in which there is initialized gameThread. MainGameFrame has a key listener for Esc key, so that it pauses/resumes gameThread. However, this doesn't work:
public void keyPressed(KeyEvent e) {
// pause the game
synchronized(gameThread) {
if(e.getKeyCode() == e.VK_ESCAPE) {
try {
if(gameThread.getState() == Thread.State.WAITING) {
System.out.println("continue");
gameThread.notify();
System.out.println("after continue");
} else {
System.out.println("pause");
gameThread.wait();
System.out.println("after pause");
}
} catch (InterruptedException ex) {
Logger.getLogger(MainGameFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
It will pause on Esc and output "pause", but not "after pause".
gameThread.wait() doesn't make the gameThread thread to pause. It makes the current thread (i.e. the event dispatch thread) to wait. Since the EDT is waiting, it can't receive a keypressed event anymore: the entire GUI freezes
Read the Java tutorial on concurrency, and particularly the following page: http://download.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
You should probably change the value of an AtomicBoolean variable, which is regularly inspected by the game thread to know if it has to pause. The game thread would then wait on a shared lock object. When resuming, change the boolean variable again and notify the game thread.
It waits until another thread calls notify(). Your not doing that, so "after pause" is never printed.
What do you want to achieve with gameThread.wait()?
You have the idea of wait and notify backwards.
One thread can not directly pause, or kill another thread. You can, however, change a variable that is shared between threads. When the interested thread sees that the variable has changed it may "pause" itself.
private static volatile boolean paused = false;
private static ReentrantLock pauseLock = new ReentrantLock();
private static Condition unpaused = pauseLock.newCondition();
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (!paused)
paused = true;
else {
pauseLock.lock();
try {
paused = false;
unpaused.signal();
} finally {
pauseLock.unlock();
}
}
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200,200));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
Thread gameThread = new Thread() {
public void run() {
while (true) {
System.out.println("running");
// presumably the game rendering loop
if (paused) {
pauseLock.lock();
try {
try {
unpaused.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
pauseLock.unlock();
}
}
}
}
};
gameThread.start();
}
I would also avoid using wait and notify directly as there are some caveats you must be aware of when using wait & notify (such as your thread that is waiting actually has to wait inside a loop because it can be woken up without notify ever being called).
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4308396
You should also be sure to always acquire and release locks in the following pattern, if not using synchronized blocks:
l.lock();
try {
// code
} finally {
l.unlock();
}
http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
I'd also recommend reading:
http://www.javaconcurrencyinpractice.com/
There are more pitfalls than you would think when doing concurrent programming in Java.
The reason that one can not pause or kill a thread from another thread is that the thread doing the pausing or killing has no idea where in execution the other thread is and what resources the other thread might hold.
What would happen if Thread A paused Thread B and Thread B happened to hold several resources that Thread A will need later? What happens if Thread A kills Thread B while Thread B is using a resource that it is supposed to do some special clean up on?

Categories

Resources