Thread.sleep() not working - java

Whilst trying to make a gamecharacter jump in java, I tried to use Thread.sleep() to make an image move up 5 pixels, then wait for e.g. 100 miliseconds, then move up 5 pixels again, etc.
Instead, when the image needs to make 5 steps up of 5 pixels each, and wait 100 miliseconds everytime, it waits 500 miliseconds and moves up 25 pixels.
I can't explain this behaviour and there doesn't seem to be an answer online. Note that my program doesn't contain threads. Here is my code:
ImageIcon poppetje1 = new ImageIcon("img/poppetje1.jpg");
JLabel poppetje2 = new JLabel(poppetje1);
...
public void jump() {
try {
poppetje2.setBounds(poppetje2.getX(), (poppetje2.getY()-5), poppetje1.getIconWidth(), poppetje1.getIconHeight());
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
...
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W) {
for(int c = 0; c < 10; c++) {
jump();
repaint();
}
}
}
I hope this is enough of my code, if I should upload the complete code, please ask.
Thanks in advance for your time.

Does setBounds include a redraw/render step? If not, blocking within keyPressed is probably preventing the redraw from happening until the sleeps are all done and keyPressed returns.

Maybe you get an exception in this line of code poppetje2.setBounds(poppetje2.getX(), (poppetje2.getY()-5), poppetje1.getIconWidth(), poppetje1.getIconHeight()); and it's jumping directly on the catch statement.

Related

How to fix bug with endless writing of numbers using FileWriter with append argument

I faced one problem which I’m struggling to solve.
Imagine simple game, where some object , lets call it car, remains motionless on X-axis ( x = 50 ) and is able to move only on Y-axis (up and down). At the same time, another objects are created beyond the screen at random point ( and move toward my first object ) , so their coordinates decrementing on X-axis. As soon as every object reaches my first object coordinates, some variable int scores; increments.
int scores;
if(cars.getX() == getCarPos_X() && cars.getY() != getCarPos_Y() )
scores++;
Basically this game looks like car which goes between other cars and avoid hitting, and counter scores increments every time my car pass next moving car.
So what is the problem?
I use timer which count time between repainting. All objects pass to the paintComponent where actually all graphic draw. In actionPerformed I call methods for all moves, and one method which checks if collision with another car occurred. In case of collision, game stops, and scores should be written in some txt file.
The problem is that while two objects have same coordinates, JVM write endless number of figures (scores) into the file ( I think it’s because coordinates stop decrementing and every timer interval it checks for collision and it’s == true , as game is stoped , and object remains where they are.)
So my scores in txt file looks like :
0
0
0
0
In one column.
Or it displays any score which I’ve got.
And so on...
Here is the crucial code snippet which I used
public void actionPerformed(ActionEvent e)
{
animate();
checkTouch();
}
private void animate()
{
//here code that creates obstacles and moves them
}
checkTouch()
{
//objects creating in some inner class Cars and add to ArrayList ( I don’t mention about it as it is beside the point )
for(Cars car : cars)
{
if((cars.getX() == getCarPos_X && cars. getY() == getCarPos_Y())
{
//boolean var which stops game
inGame = false;
writeScore();
}
}
}
public void writeScore()
{
File scoresTxt = new File("scores.txt");
FileWriter fw = null;
BufferedWriter bw = null;
try
{
fw = new FileWriter(scoresTxt, true);
bw = new BufferedWriter(fw);
bw.write(scores + "\n");
}catch (IOException e)
{
e.printStackTrace();
}finally
{
try
{
bw.flush();
bw.close();
fw.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
public void paintComponent (Graphics g)
{
if(inGame)
{
g.drawImage(myCar, 50, 100, this);
for(Cars car : cars)
{
g.drawImage(obstacleCar, car.getX(), car.getY(), this);
}
}
}
Should you need some extra code I used, write comment and I’ll add it.
And again I need to fix bug which write endless column of numbers instead of one final score from the moment of collision.
What’s wrong with my code , and how to solve this problem?
Give me advice for simplest decision, as I’m beginner.
Thanks in advance!
If your timer is started like this, or something similar, the you could cancel it when the inGame variable becomes false. Nice article on timers.
TimerTask task = new TimerTask() {
public void run() {
if (!inGame)
cancel();
else
// whatever it is that you are doing now
}
};
You might also want to stop processing events in the actionPerformed(e) method in a similar way.
if (!inGame)
return;

How can I make a smooth animation in java instead of a stuttering

I'm making a game for practice and when I hit enter a knife pops up and I want it to look like its flying through air. Right now each time I click enter it skips about an inch and stops.
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "onEnter");
am.put("onEnter", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// Enter pressed
throwKnife = true;
if(move)
{
for(int i = 0; i < 10; i++)
{
try
{
Thread.sleep(10);
knifeX += i;
repaint();
} catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if(knifeX > 1200)
{
throwKnife = false;
move = false;
knifeX = imageX+100;
knifeY = imageY+75;
}
}
throwKnife = true;
}
});
This is paired with the following code in my paint component method
if(throwKnife)
{
g.drawImage(knife, knifeX, knifeY, this);
repaint();
move = true;
}
Based on the use of the key bindings API and repaint, I'm guessing you're using Swing, in which case you're blocking the event dispatching thread with the Thread.sleep
See Concurrency in Swing for the reason why
Have a look at How to use Swing Timers for a simple solution
I should also point out that the ActionListener will be called repeatedly while the key is held down. A better solution would be to use a flag to indicate when the key is "active" and a "main loop" (like a Swing Timer) to update the state accordingly
Of course, this will require you to detect when the key is released, which can be achieved by binding the key again, but for release. See KeyStroke.getKeyStroke(int, int, boolean) for more details
For example, maybe have a look at
smooth animation in java for fast moving objects
How to make this java animation smooth?
How can I make a Java Swing animation smoother
How to make line animation smoother?
Smooth out Java paint animations
How do I make smoother movement?
Right now each time I click enter it skips about an inch and stops.
I believe that in the part you wrote if(move){...} you actually wanted while(move){...}.
With the while clause you can have it move until it satisfies certain condition (like knifeX > 1200).
So, your code should look like this:
while(move)
{
for(int i = 0; i < 10; i++)
{
try
{
Thread.sleep(10);
knifeX += i;
repaint();
} catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if(knifeX > 1200)
{
throwKnife = false;
move = false;
knifeX = imageX+100;
knifeY = imageY+75;
}
}
Hope it helps.

How to use Thread.sleep in a basic RPG game

I've been working on this really basic Java RPG game, and when I tried using Thread.sleep for my monster to move slower, it seems to affect the player as well, in other words, the movement of the player had slow down when the monster appears, but turns back to normal when I move to another part of the map where the monster is not there
Here's the code for the monster's movement
int wolfRandNum;
if (isKilled() == false){
wolfRandNum = (int) (Math.random()*4);
if (wolfRandNum == 1){ // up
System.out.println("up");
if (playerRow -1 <= 0){
setCurrentEnemySprite(3);
} else {
moveUp();
playerRow--;
}
} else if (wolfRandNum == 2){ // down
System.out.println("down");
if (playerRow +1 >= 8){
setCurrentEnemySprite(0);
} else {
moveDown();
playerRow++;
}
} else if (wolfRandNum == 3){ // left
System.out.println("left");
if (playerColumn -1 <= 0){
setCurrentEnemySprite(1);
} else {
moveLeft();
playerColumn--;
}
} else{ // right
System.out.println("right");
if (playerColumn + 1 >= 9){
setCurrentEnemySprite(2);
} else {
moveRight();
playerColumn++;
}
}
}
The code above is in a method called update, which is from an enemy class.
Here's the where I call the method:
public void paintComponent(Graphics g) {
super.paintComponent(g); //required to ensure the panel is correctly redrawn
map.draw(g);
player.draw(g);
for (Character character : characterList) {
character.draw(g);
}
for (Enemy enemy : enemyList){
enemy.draw(g);
try {
enemy.update();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (Item item : bagList) {
item.draw(g);
}
repaint();
}
Is there anyway to use thread.sleep without affecting the player's movement? If not, what other methods can I use to make the monster move slower but not the player?
I'm not really sure how to fix this problem, any advise would help a lot! Thank you :)
This is a event-driven Swing GUI, and so the answer to the question:
How to use Thread.sleep(...)
is that you don't.
You're coding this as if it were a linear console program, and this design won't work for event-driven non-linear programs. Calling Thread.sleep on the Swing event thread and especially in any painting method is a guarantee to put your entire GUI to sleep so that it becomes totally unresponsive. The proper solution is to create a non-GUI Model class to go with your GUI (your "View"), and to change how the view responds based on the state of the Model, i.e., the state of its key fields.
Also, if your game is being run in "real time", then you will need a game loop to drive your game. This can be done easily via a Swing Timer, although it does not provide absolute precision. If greater precision is required, then use the Swing Timer, but don't assume that each time slice is accurate, and instead measure each delta time and base your physics on the measured slice, not the assumed slice. Other ways to create a game loop include use of a background thread with a while loop and Thread.sleep within this thread.
All you are slowing down is the rendering (drawing) of your monster. As all drawing is done on the UI thread, this will, as you have rightly noticed, have a huge performance impact on your entire application. As a general rule, you should never call a blocking operation such as sleep in the UI thread.
Given you only have two characters, what I would consider trying is creating two threads, one for your character and one for your monster. You will do what you need to do in each of these threads, and then call repaint() when you need to redraw. If you want to slow down the monster, for example, you can call sleep in the monster thread.

when shooting constantly repeats and goes faster every key stroke

Ok so i'm going to try to explain this, well I created a shoot method in a class that contains my bluespell, and all of it's constructors, well the problem is when I press space once it constantly shoots without me pressing it again, and if I press it twice the speed at which it fires doubles and it starts to contain more than one x and y position on my grid I just want the spell to fire when fired and I only need one item because I don't want there to be more than one instance of it on the grid I want it to be that the player cannot fire until the spell has left the grid, here's my code thanks oh and I only have it called in my key released seeing as it should only do it once the key has been released, but if that should change please let me know thanks :)
public void shootSpell(){
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
ActionListener taskPerformed = new ActionListener(){
public void actionPerformed(ActionEvent e){
if(b.gety() != 19){
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety()+1)].setIcon(b.getIcon());
}
else{
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() +1);
}
}
};
new Timer(delay, taskPerformed).start();
else if(key == KeyEvent.VK_SPACE){
GoodSpell.shootSpell();
}
Do not use a Timer! Your task should not repeat every 100 milliseconds. If I understand your code, you should run the code from your ActionListener in a new thread.
// Something like this,
new Thread(new Runnable() {
public void run() {
if (b.gety() != 19) {
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety() + 1)].setIcon(b
.getIcon());
} else {
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() + 1);
}
}
}).start();
You also need to do a check if the spell is currently in view/activate prior to initiating a new spell in the shoot() method...
public void shootSpell(){
//do a check here if a spell is already running!
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
//......
So in your method that is updating the spell going accross the screen you either need to have a flag in there if its still active, or if you are running it in a new thread, save that thread to a global var and check to see if the thread is running prior instantiating a new BlueSpell()

change image of imagebutton

I'm begining on android and java.
I try to make a simon game but have some problems.
I wrote this to show the simon buttons sequence or the button pushed by the player:
if (but_num == 1) {
ib1.setImageResource(R.drawable.bullet_square_green);
MediaPlayer sound = MediaPlayer.create(this, R.raw.tone_green);
sound.start();
for (int x = 1; x < 10000000; x++) { };
ib1.setImageResource(R.drawable.bullet_ball_green);
} else if (but_num == 2) {
It should change the image of each imagebutton, play a sound, wait some time (for {}) and then
change the image again....
But it doesn't work well... it plays the sound and really changes the image by bullet_square_xxx, but the eye can't see the image change, the change is only visible if the image is not changed back again by the bullet_ball_xxx :-(
I think this is my fault because I wrote the code different than java really works... I'm a
beginner and don't think in java... I have the visual basic program structure on my mind yet.
Thank You and sorry for my English !
This is probably caused by a delay on the event dispatch thread and the fact that the empty loop might be even ignored by the compiler since it is static, it is easily predicted to have no effect on the program. My suggestion is first force a repaint/update on the GUI and use Thread.sleep. Something like this:
if (but_num == 1) {
ib1.setImageResource(R.drawable.bullet_square_green);
updateUI(); // if you are somewhere in a class extending any Frame/Panel
//If you are in other class use mainFrame.repaint();
MediaPlayer sound = MediaPlayer.create(this, R.raw.tone_green);
sound.start();
try{
Trhead.sleep(3000);
} catch (InterruptedException e) {}
ib1.setImageResource(R.drawable.bullet_ball_green);
updateUI(); //only if this effect is delayed too
} else if (but_num == 2) {
ok....I think delay is the problem in your code. Since nowadays there are highspeed processors available that can count to 10000000 in a few ms, mine does. So instead of using the old-school for loop to introduce a delay use
Thread.sleep(5000);
this causes a delay of 5 sec, the argument is the time in milliseconds.
there is another thread which talks about introducing a delay:
How to pause / sleep thread or process in Android?
you could try this [i have copied pasted from that thread]:
if (but_num == 1) {
ib1.setImageResource(R.drawable.bullet_square_green);
MediaPlayer sound = MediaPlayer.create(this, R.raw.tone_green);
sound.start();
// SLEEP 2 SECONDS HERE ...
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
ib1.setImageResource(R.drawable.bullet_ball_green);
}
}, 2000);
} else if (but_num == 2) {

Categories