How to pause and resume game using the escape key? - java

How do I make my Escape key pause and resume a game when it is pressed twice? I have tried calling the key adapter class in my thread class but it only pauses the game; it does not resume it.
Here is the code that pauses the game:
//the thread class
class recMove extends Thread {
JFrame b;
public boolean running=true;
//public boolean gameover=false;
public recMove(JFrame b){
this.b=b;
pauseGame();
}
public void run(){
while(running){
b.repaint();
try {
Thread.sleep(100);
} catch(InterruptedException e){}
}
}
public void pauseGame(){
addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_ESCAPE) {
running=false;
System.out.println("escape pressed");
}
if(keyCode==KeyEvent.VK_END){
System.exit(0);
}
}
});
}
}

It doesn't resume because the thread is killed, when you press escape the running value is set to false therefore this loop:
while(running){
b.repaint();
try {
Thread.sleep(100);
} catch(InterruptedException e){}
}
Will end, which in turn will make the run() method exit. When a run() method of a class extending Thread (or implementing Runnable) exits that thread is being killed so there's nothing more listening for your keypresses.
You need to change your run() logic so it doesn't exit when running is set to false but instead wait for the next keypress or add the listener somewhere else (in a different thread) so it will create a new thread with the game again.
Furthermore in your logic esc only changes running to false, if you want it to then resume the game you should check the state of running and if it's false you should set it to true instead.

Related

Starting "asyncExec" in Mouse Down Event results in blocking behavior

Having a "next" Button, when I press keyboard enter key with the button selected, the widgetSelected event of the button is being repeatedly called once and once and doing a super fast next. It's exactly the behaviour I want, but only happens with keyboard enter key.
I want to have that behaviour with mouse click when holding the click. When trying to do the same with the mouse click, the behaviour is not the same, it only makes one event call, and when the click is end (UP). How to simulate the same behaviour with the mouse click?
I tried it doing this, but it blocks the UI (can't understand why) and mouseUp is never being called, it blocks forever in the while:
button.addMouseListener(new MouseAdapter() {
boolean mouseDown;
#Override
public void mouseDown(MouseEvent e) {
System.out.println("mouseDown");
mouseDown = true;
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
while (mouseDown) {
System.out.println("Doing next in mouseDown");
next(composite, label_1);
synchronized(this){
try {
wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
}
#Override
public void mouseUp(MouseEvent e) {
System.out.println("mouseUp");
mouseDown = false;
}
});
The Runnable you give to asyncExec runs in the UI thread. You must never do any sort of wait in the UI thread as that will block the UI until it completes.
So you cannot run a loop like this as it just blocks the UI. Since the loop never returns to the main SWT readAndDispatch loop no UI actions are done.
Instead use the timerExec method of Display to schedule a Runnable to run after a given interval. This runnable should do one step of the action and use timerExec to schedule the next step later.
I remember there was another question a few days ago regarding a long mouse click behaviour but I can't find it anymore. I put this code based on greg-449 solution to use timerExec method, after my failed attempts to use asyncExec in the UI thread. :)
button.addMouseListener(new MouseAdapter() {
boolean mouseDown;
#Override
public void mouseDown(MouseEvent e) {
mouseDown = true;
Display.getCurrent().timerExec(1000, () -> {
if (mouseDown) {
button.notifyListeners(SWT.Selection, new Event());
button.notifyListeners(SWT.MouseDown, new Event());
}
});
}
#Override
public void mouseUp(MouseEvent e) {
mouseDown = false;
}
});
button.addSelectionListener(SelectionListener.widgetSelectedAdapter(
e -> System.out.println("Do next")));

Why is my button not clickable? (Java)

I have a java swing gui program and when I click a toggle button a timer begins but I want to be able to click the same button and the timer stops and right now it won't let me click on it again.
This is in my timer class
public void runningClock(){
isPaused = false;
while(!isPaused){
incrementTime();
System.out.println("Timer Current Time " + getTime());
time.setText(""+ getTime());
try{Thread.sleep(1000);} catch(Exception e){}
}
}
public void pausedClock(){
isPaused=true;
System.out.println("Timer Current Time " + getTime());
time.setText(""+ getTime());
try{Thread.sleep(1000);} catch(Exception e){}
}
and this is in my main class
private void btnRunActionPerformed(java.awt.event.ActionEvent evt) {
if(btnRun.getText().equals("Run")){
System.out.println("Run Button Clicked");
btnRun.setText("Pause");
test.runningClock();
}
else if(btnRun.getText().equals("Pause")){
System.out.println("Pause Button Clicked");
btnRun.setText("Run");
test.pausedClock();
}
}
You're freezing the Swing event thread with your Thread.sleep(...) and while (something) loops. Solution: don't do that -- don't call code on the event thread that occupies the event thread and prevents it from doing its necessary tasks. Instead change the state of your program. And for your clock, use a Swing Timer. For example, please look at my answer and code here.
You are doing this in your program, try{Thread.sleep(1000);} catch(Exception e){}. As this statement is applied on the main thread itself, so the application itself hangs or you can say freezes. What you can do is apply a separate thread for the timer.
new Thread(new Runnable(){
public void run(){
//Do Stuff
}
}).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.

How to Interrupt in Java

In Java, let's say I have a GUI with 2 buttons, Go and Pause.
When I press Go, "Hello" gets printed out over and over again. When I press Pause, "Hello" no longer gets printed to the screen.
Example: User presses Go button. "Hello" gets printed out for 1 minute until the user presses "Pause."
What is the proper way to express this approach in Java? Is it equivalent to my commented pseudocode within the goButton source?
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
// while user has not pressed the pause button
printHello();
}
else if(e.getSource() == pauseButton)
{
pause();
}
}
Thanks
In order to get this to work, in reasonable fashion, you will need a Thread. This is executed in the background until such time as you decide to cancel/pause it.
This is an EXTREMELY basic example. Normally I'd wrap the task and the GUI up in appropriate classes rather then accessing static references, but it gives a basic idea
public class TestHello {
private static HelloTask task;
public static void main(String[] args) {
Thread thread = new Thread((task = new HelloTask()));
thread.setDaemon(true);
thread.start();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
JButton goButton = new JButton("Go");
JButton stopButton = new JButton("Stop");
goButton.setActionCommand("Go");
stopButton.setActionCommand("Stop");
ActionHandler handler = new ActionHandler();
goButton.addActionListener(handler);
stopButton.addActionListener(handler);
frame.add(goButton);
frame.add(stopButton);
frame.setVisible(true);
}
public static class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Go")) {
task.start();
} else if (e.getActionCommand().equals("Stop")) {
task.pause();
}
}
}
public static class HelloTask implements Runnable {
private static final Object WAIT_LOCK = new Object();
private boolean dump = false;
public void start() {
synchronized (WAIT_LOCK) {
dump = true;
WAIT_LOCK.notify();
}
}
public void pause() {
synchronized (WAIT_LOCK) {
dump = false;
WAIT_LOCK.notify();
}
}
#Override
public void run() {
while (true) {
while (dump) {
System.out.println("Hello");
}
try {
synchronized (WAIT_LOCK) {
WAIT_LOCK.wait();
}
} catch (Exception e) {
}
}
}
}
}
Some further read:
Java Concurrency
Concurrency in Swing
Caveats
NEVER try and modify the GUI from any thread other then the Event Dispatching Thread.
To have responsive UI you would usually have to run printHello() in separate thread. Then as you do processing in this thread, for example, after every print statement, you check some flag boolean isPaused; and stop execution if it is true. When pause button is clicked you set the value of this flag to true.
You need to implement your loop in a separate thread. Otherwise the GUI will become irresponsive and the user might not be able to click the Pause button at all.
With this threaded approach, you also need a flag which indicates whether or not to print out the message. The printing loop can simply stop executing the thread when the flag is set to no longer print.
what about htis:
boolean flag=true;
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
while(true)
{
printHello();
}
}
else if(e.getSource() == pauseButton)
{
pause();
}
}
You can do this in a few ways the simplest being:
You have a boolean flag, keepPrinting and you set it to true when you push the Go button, false when you push the Pause. Next you have a thread somewhere executing a while loop which will print nothing when keepPrinting is false.
The threading here is really important, without it you're going to have your GUI freeze once the user pushes a button as the program prints hello and happily ignores anything else.
Pseudo Code
//GUI
public ThreadedPrinter greeter;
void ButtonGoPushed(args){
greeter.keepPrinting = true;
}
void ButtonPausePushed(args){
greeter.keepPrinting = false;
}
//ThreadedPrinter
boolean keepPrinting
void run(){
while(true){
if(keepPrinting){
print("Hello");
}
sleep(5); //Make sure that this thread yields if the system doesn't do it automatically
}
The good news about java concurrency versus say C++ is that this will just work, you don't have to worry about the boolean being crazy and inconsistent because in java variable sets are atomic. If you want to do more than just set the variable, make a synchronized method that sets the variable and does anything else you want.
Basically to keep UI responsive such task need to be performed in other thread.
There can be various ways in which you can implement this mechanism in java.
I have used simple mechanism of Runnalbe and volatile flag which ensure that thread exists when you call cancelPrint() method
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
//start the thread here
}
else if(e.getSource() == pauseButton)
{
//call cancel here
}
}
public class HelloPrinter implements Runnable {
volatile boolean cancel = false;
#Override
public void run() {
while (!cancel) {
printHello();
}
}
public void cancelPrint() {
cancel = true;
}
}
I assume you want to do more than just printouts. Take a look at Swing Worker.
It allows you to pretty easily write your GUI-related code that gets executed in the AWT Event Thread and your long-executing code in other thread(s) and pass values back and forth. This will help prevent any GUI lockup issues you might experience.

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