I'm wondering why still I couldn't to figure out a way to do this. Although it seems like very simple, I spent my entire day for this. But couldn't do that.
I have set of dice images. 1.png,2.png,.... and 6.png.
There is an ImageView in my layout. That is,
ImageView dice = (ImageView) findViewById(R.id.imageViewrollingdiceOne);
Here I want to change this imageView rapidly to see a some kind of a visual/animation using above 6 images. For that I wrote following piece of code.
Code 1:
for (int j=0;j<10;j++){
int randomNum = random.nextInt(6);
System.out.println("Random Value " + randomNum);
dice.setImageResource(images[randomNum]);
}
Output:
There is not a visual. imageView remains unchanged and suddenly changes at the loop last iteration.
I thought that it is because the loop is executing very fast.
Then I did the following.
Code 2:
for (int j=0;j<10;j++){
int randomNum = random.nextInt(6);
System.out.println("Random Value " + randomNum);
dice.setImageResource(images[randomNum]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Output:
Again there is not a visual. imageView remains unchanged and suddenly changes at the loop last iteration.
Then I did the following.
Code 3:
final Handler localHandler = new Handler();
Runnable runnableObject = new Runnable() {
public void run() {
final ImageView dice = (ImageView) findViewById(R.id.imageViewrollingdiceOne);
int randomNum = random.nextInt(6);
System.out.println("Random Value" + randomNum);
dice.setImageResource(images[randomNum]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
for (int j=0;j<10;j++){
localHandler.postDelayed(runnableObject, 1000);
}
Again there is not a visual. imageView remains unchanged and suddenly changes at the loop last iteration. There are no any errors in logcat in all three cases.
I found that threading also doesn't do the trick.
First of all there is already an animation set in android that can help you achive what you are after it is called FrameAnimation, here is an example on how to use it:
FrameAnimation Example
Your First, second and third code are running in the main thread, you should never use sleep in the main thread !.
If you still want to set the image resource manually you can use this code:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
int randomNum = random.nextInt(6);
dice.setImageResource(images[randomNum]);
handler.postDelayed(this, 500);
}
}, 500);
This is helpful when you're using list of items and changing according time interval one by one. Initially i value should be 0, size of list depends.
final Handler handler = new Handler();
handler.postDelayed(new Runnable(){
public void run(){
if(i<4) {
galleryImg.setImageResource(myImageList[i]);
i++;
} else {
i=0;
}
handler.postDelayed(this, 10000);
}
}, 500);
The reason you're probably not seeing changes is because the final callback to the main UI thread happens after your thread finishes its execution and you only see the final result. Now, this is my (probably poor) understanding and someone more versed in it can probably correct me.
That said you should probably look to using an AnimationDrawable object:
ImageView sImage = (ImageView)findViewById(R.id.imageViewrollingdiceOne);
AnimationDrawable anim = new AnimationDrawable();
for (int j=0;j<6;j++) {
anim.addFrame(new BitmapDrawable(images[j], 200);
}
sImage.setBackgroundDrawable(anim);
anim.setOneShot(false);
anim.start();
This assumes you've generated images[] with the images in random order already. If you want to change that up put whatever code you need in the for-loop.
What it does is creates an animation object much like how you'd see a gif work with a set delay interval between changes (in this code its 200ms). You can elect to change that number if you wish. The setOneShot call makes sure it loops instead of finishing the animation and stopping on the last image.
Related
I have a problem with a function I have made for a Whack a mole game in java fx.
In the function, I am trying to change the image of 1 to 3 buttons. The problem is that I am trying to set a delay between each image change. I tryed the Wait() function but it gives me a java.lang.IllegalMonitorStateExceptionstrong Exception
The function ChangeImageActive changes the image of a button to tell to the player that he needs to hit the button.
public void ActivateRandomButtons(ArrayList<MSButtons> btnList)
{
try
{
int n;
int numberOfButtons = rand.nextInt(3);
for (int i = 0; i < numberOfButtons; i++)
{
n = rand.nextInt(9);
btnList.get(n).ChangeImageActive();
// Wait 1 second before resuming for loop
wait(1000);
}
}
catch (java.lang.Exception e)
{
System.out.print(e.getMessage().toString());
}
}
I can show more of my code if needed.
Thanks
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.
i have a button in java that calls a function when clicked and that function works just fine but the for loop won't refresh the text area. Instead at the end of the function (after 10s) it only shows i = 10 in the text area. I just simply want the text area to refresh and show i at every second and replace the i. I do not want to show them all at once, just replace them;
int i;
for (i = 0; i<4; i++)
{
try
{
input.setText("i = " + i);
Thread.sleep(1000); // delay of 1.000 seconds
}
catch(InterruptedException e)
{
}
}
Assuming you're using Swing, you could attempt using append instead, since I know that works with adding to the textarea:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
input.append("i = " + i + "\n");
}
});
As Maroun suggested, use Timer after this to pace your appending.
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) {
I am having trouble understanding this java code. I want the image to twinkle a couple of times, with some delay. The image twinkle once and thats it. Can someone give me an explanation would be great!
private void RunAnimations(int[]melodiTakten) {
for (int i = 0; i < 4; i++) {
ImageView markeringspilen = (ImageView) findViewById(R.id.markeringspil);
markeringspilen.setVisibility(View.VISIBLE);
markeringspilen.postDelayed(new Runnable() {
public void run() {
ImageView markeringspilen = (ImageView) findViewById(R.id.markeringspil);
markeringspilen.setVisibility(View.INVISIBLE);
}
}, 2000);
}
If I understand your idea right, your implementation is wrong in that it sets delayed actions to take place all at the same time. You can space them out like this:
for (int i = 0; i < 4; i++) {
markeringspilen.postDelayed(new Runnable() {
public void run() {
ImageView markeringspilen = (ImageView) findViewById(R.id.markeringspil);
markeringspilen.setVisibility(View.VISIBLE);
}
}, 4000*i);
markeringspilen.postDelayed(new Runnable() {
public void run() {
ImageView markeringspilen = (ImageView) findViewById(R.id.markeringspil);
markeringspilen.setVisibility(View.INVISIBLE);
}
}, 4000*i+2000);
}
This loop sets up eight delayed visibility changes - a group of four pairs of set visible at 4000*i followed by set invisible at 4000*i+2000.
the loop is executed, but it's executed very fast and you can't see it. You should put some delay in the loop, not only in the runnable.
That's because you call setVisibility(View.VISIBLE) four times in a row and then, after a 2s delay, four times setVisibility(View.INVISIBLE).
What you need to do is add eight runnables with ever increasing delays that in turn toggle the visibility.