Why does not Thread.sleep() work in Action Performed? - java

public void actionPerformed(ActionEvent e) {
String sp1="Player 1's turn. ";
String sp2="Player 2's turn. ";
System.out.println("Mouse entered for rating " + index); //helps me track the cards
ori=new ImageIcon(getClass().getResource(index+1+".png")); //set the image to the card
ori.setDescription("ori"); //It's weird that I cannot directly flip the card, so I used this method to flip the cards.
tail.setDescription("tail");//http://stackoverflow.com/questions/13557561/the-method-about-imageicons-does-not-work
if (((ImageIcon) bt[index].getIcon()).getDescription()=="ori")
bt[index].setIcon(tail);
else
bt[index].setIcon(ori);
count++;
System.out.printf("Action Performed %d times \n",count);
if(count==1){ //if the card is clicked for once, the card should not flip and the index is stored in record.
record=index;
countS++;
}
String turnS=Integer.toString(countS);//parse the int and printout the turn
// text3.setText(sp1+"This is turn "+turnS);
if(count==2){
int match1=record/4; //Since every four cards have the same rank, I used this to get the rank very easily
int match2=index/4;
if(match1==match2&&record!=index){ //compare the two cards clicked
p1++;
score1=Integer.toString(p1);
text1.setText("Player 1: "+score1); //display the score
text3.setText(sp2+"This is turn "+turnS);
bt[index].setEnabled(false);//remove the cards that match
bt[record].setEnabled(false);
}
if(record==index){
text3.setText(sp2+"This is turn "+turnS);//designed for the situation that the user clicks the same card
}
if(match1!=match2){//designed for the situation that the two cards do not match
//time.schedule(taskFlip1,500);//delay the flip so that the user can see the cards
//time.schedule(taskFlip2,500);
try{ **//This part is problematic!**
Thread.currentThread().sleep(4000);
flip(index);
flip(record);
}
catch(Exception ie){
}
}
text3.setText(sp2+"This is turn "+turnS);
}
When I click on the button, the button is supposed to change the ImageIcon. It works fine without the sleep. But after I add sleep, when I click on the button, the program pauses without changing the ImageIcon! Can you tell me why? Thank you!

The actionPerformed() method runs in the event dispatching thread. So does the repaint system. If you sleep, you are deferring painting, and everything else. You should never sleep in this thread. If you want a deferred paint, use SwingWorker or javax.swing.Timer to start a deferred task.

The action is executed by the very thread which also does handle the drawing. You block this thread. You see nothing. Game over.
This is the reason why YOU SHALL NOT BLOCK NOR DELAY THE EVENT-DISPATCHER THREAD.
Searching for the term "Event Dispatcher Thread" and "blocking" you find plenty of stuff explaining the gory details.

ActionPerformed is run in the event-dispatcher thread. Sleeping in there will stop the UI from updating.
You can use a Swing Timer instead to delay an action.

Related

Pause listenning to mouse/ key events until a sound is finished

In my game, if I select the good answer I play an applause sound then I move to the next question. So after calling a method say validate()in setOnMousePressed, I play the wav and do this :
try {
Thread.sleep(1700);
} catch (InterruptedException e) {
e.printStackTrace();
}
To pause everything until the sound is finished, then I call a method reset() to move to the next question.
The problem occurs when I click more than one time before 1700ms passes. At the next questions even without clicking anymore, it takes in count all the excess previous clicks and procceed to validate()and reset()so the final result is a hot mess.
How can I pause listening to mouse/key events until the sound is finished?
As Yahya mentioned, simply declare a boolean for e.g.
boolean listenForMouseEvents = true;
Set an if condition such that validate() can only be invoked when listenForMouseEvents is true for e.g.
if (listenForMouseEvents) {
validate();
}
Then once you click, set the listenForMouseEvents to false.

how to pause the game to handle user input

I'm facing a problem since many days without finding an anwser.
In the code i will not put all my code because it will just complicate the question.
I have a game class which is rendering each frame.
public class MyGame implements ApplicationListener {
#Override
public void render() {
//handling event
handleEvent();
//update player position
updatePlayerPosition();
//rendering the player using a batch
renderPlayer();
}
public void handleEvent(){
//when the player prees on C i'm calling a method in another class
// when i do some processing
if (Gdx.input.isKeyPressed(Keys.C)) {
OtherClassForProcessing() ocp = new OtherClassForProcessing();
ocp.process();
}
}
//in this method i have to ask the user to choose an option
//i have to think to stop running this method until the
// user choose an option
//this method has to return a value
public static int displayChoice(List<Integer> ListOfInteger){
return 0;
}
}
public Class OtherClassForProcessing(){
public void process(){
int value= MyGame.displayChoice() ;
}
}
The question is how can i ask the user to choose an option in the displayChoice method.
What kind of widget will do this work.
I tried to use another screen for that , but the methode don't stop running .
How can i ask the program to stop until the user choose an option.
Thank you
what i tried is :
#Override
public static int displayChoice(List<Integer> ListOfInteger){
//i change the screen when i ask the user to choose from many options
setScreen(new PauseScreen());
a wile loop hwo run until the user choose an option from the other screen
while(PauseScreen.notYetChoosen){
Gdx.app.log("display message ", "the user not yet choose an ption");
}
return PauseScreenValue;
}
When i put the while loop:
the screen don't change from the game to the PauseScreen.
the loop run without stoping
the screen block
But when i remove the while loop the screen change to the PauseScreen but the method finish without waiting the user to choose an option.
EDIT
i tried to avoid using another screen unfortunantly even when i used a window the screen block
You can use a separate screen for this, I do not know your code structure exactly but here is how you can do it conceptually if you were trying to get input from a "pop up" or "pause screen" or something of that nature.
Inside of your Game Screen have a boolean which will be set when your "pop up" is displayed, for example isPaused, then you can use this boolean to skip over game logic while waiting for the screen to receive input.
For a more elegant approach you can use Game States which can represent which state your game is in. You can have a PLAYING state, GETTING_INPUT state, etc. Then you can run game logic depending on which state you are in.
EXAMPLE:
public void update (float deltaTime) {
if (deltaTime > 0.1f) deltaTime = 0.1f;
switch (state) {
case GAME_READY:
updateReady();
break;
case GAME_RUNNING:
updateRunning(deltaTime);
break;
case GAME_PAUSED:
updatePaused();
break;
case GAME_LEVEL_END:
updateLevelEnd();
break;
case GAME_OVER:
updateGameOver();
break;
}
}
EXAMPLE SOURCE AND MORE INFO:
LIBGDX SuperJumper Demo
https://github.com/libgdx/libgdx-demo-superjumper/blob/master/core/src/com/badlogicgames/superjumper/GameScreen.java
Response to your edit
The reason your code is not changing is because you have a while loop printing out to the Gdx Log until input is taken so your code is stuck in that while loop.
If you want to go this route, you can set a 'pause' variable inside your Game Screen to true and then set your screen to the pause screen. Inside of your Game Screens update logic, tell it not to update if paused.
public void update()
{
if(!paused)
{
//game logic
}
}

what is stopping my screen from rendering as planned?

#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
combattext.setText(combatstring);
stage.act();
stage.draw();
}
combatstring is a string that displays what happened in my game. when enemies attacks, it says what happened. when I attack, it says what happens. As of now my game has a loop when in combat that runs a turncounting instance. When it's time for a turn, it runs that participants turn, and when their turn is over it updates combatstring.
I have 2 combatstrings. One is for my characters, and one is for enemies. Here is an example of what happens when it's an enemies turn.
if(thisencounter.monster1turn){ //monster1's turn goes in here
thiscombat.getTarget(1); //get enemy's target
thiscombat.calculateVars(1); //calculate all combat variables for
// this turn
thiscombat.theyAttack();
combatstring = thisencounter.thisenemy.species+
" "+thiscombat.action+
" "+thiscombat.theirtarget.species+
" for "+thiscombat.effect;
thisencounter.monster1turn=false;
}
This works fine, my combattext label updates instantly when a monster goes.
For my characters, their turns make buttons visible on my screen. The buttons have listeners that determine actions, here is an example:
monster1.addListener(new ClickListener(){ //makes the first enemy's
//image clickable, but only
//when the attack button
//has been clicked
#Override
public void clicked(InputEvent event, float x, float y) {
thiscombat.ChooseTarget(1); //various methods that calculate damage,
//output what happened, and put us back in
thiscombat.calculateVars(4); //the loop to wait for next
//participant's turn
thiscombat.youAttack();
combatstring = thisencounter.thisspirit.species+
" "+thiscombat.action+
" "+thiscombat.yourtarget.species+
" for "+thiscombat.effect;
monster1.clear();
monster2.clear();
monster3.clear();
try {
combatloop();
} catch (InterruptedException ex) {
Logger.getLogger(map1field.class.getName()).
log(Level.SEVERE, null, ex);
}
}});
This also works fine, EXCEPT on the turn just before a monster goes. Since there is no wait between my turn and the monster's turn, the combattext just instantly displays what the monster does.
I assumed 'oh hey this is because there is no delay between the two turns'. So, I threw a thread.sleep(2000) just before where it updates the monsters combatstring.
But that does not fix it. It still does not show the text for my character that goes just before a monster. Also, since fighting starts right when you go to this screen in the game, it waits about 2 seconds before it displays anything on the screen.
For the life of me I don't understand why it behaves like this. Can someone explain what is happening to me? Is it because it isn't rendering before it gets to thread.sleep ?
If that's the case, how do I force it to render before it does thread.sleep, or what should I be using instead of thread.sleep ?

Trying to animate a die roll in Java

I'm attempting to "animate" a die roll in Java. I currently have an icon (called "diceImage") set up that, when a button is clicked (called "diceRoll"), updates to a new random image of a die face. What I would like to do is have it change image (to a random die face) numerous times over a couple of seconds before stopping on a final image.
The problem I have is not with generating a random number, or rolling it numerous times, it's with the updating the image numerous times within a loop. The code below, which rolls the die 10 times is what I have so far:
private void diceRollActionPerformed(java.awt.event.ActionEvent evt) {
for (int i = 1; i <= 10; i++) {
rollDice();
pause(100);
}
}
This links to the following two methods (the first of which generates the random number, and sets the icon image):
private void rollDice() {
Random r = new Random();
int randomNumber = r.nextInt(6) + 1;
diceImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Game/Images/Dice " + randomNumber + ".png")));
}
The method below is "supposed" to pause the programme briefly between updating the image (this was taken from a programming course I was on where we had to animate an image of a car moving across the screen):
private void pause(int sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
System.exit(-1);
}
}
All this programme seems to do is pause and then print the final dice roll. It doesn't show any of the "intermediate" faces. Does anyone have any ideas on why this isn't working?
Any help is greatly appreciated.
This question is asked several times a day. If you sleep in the event dispatch thread, you're preventing it from doing its job: react to events and repaint the screen.
Your animation should be done in another thread. Read the tutorial about concurrency in Swing, and use a Swing Timer.
The pause() you are using is when u need to animate moving stuff like a car for example , but just changing the icon of a JLabel which is the dice here doesn't need pause ( unless you just want it to be delayed a bit) ...
but anyways , to solve your issue , you need to call repaint() on that JLabel or updateGraphics(). Setting the Icon for the JLabel doesn't make the new Icon get displayed , you just need to repaint() it .
of course like JB Nizet said , for the app not to hang you need to call repaint on a new Thread .Thought you have to learn how to use Thread well cuz it can be very tricky at times .
good luck

Java: time delay on a specific position - works in the wrong place

I don't know if the title actually makes my problem clear. I'm making a card game application. When the user and the computer both have played their cards off they should remain on the screen there for a certain until the computer plays the next card off.
I tried to solve this problem using thread.sleep() in try catch. And it's basically doing what it's supposed to do but it's not what I want it to do. The delay isn't between the computer playing one card and then the second one off. It is between the user pushing the button (for a card) and the appearance of this card on screen.
Here is the relevant code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
jLabel1.setIcon(//new Icon of the card);
jPanel1.remove(jButton1);
jLabel2.setIcon(//new Icon of the card);
if(//proving whether the computer played the highest amount off)
{
disableButtons();
sleep();//waiting for a certain time...
playCard();//...until playing the next card off
}
}
public void sleep()
{
try
{
Thread.sleep(500);
} catch (InterruptedException e)
{
}
}
Welcome to StackOverflow. If you sleep in the UI thread, the UI will not reflect all your drawing commands until you enter the main loop again. Look into swing timers.

Categories