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) {
Related
I am making a roulette game type application, I have 10 rectangles that change color simulating a random choice, In addition to the color change, I want a sound to be played every time the roulette goes through a rectangle.
First a list of possible prizes is created awardList, then the winner is randomly selected positionAwardSelected
I tried to do the following:
final Handler handler = new Handler();
int count = 0;
private void playRoulette(){
List<Award> awardList = new ArrayList<>();
int positionAwardSelected;
// ... List filling and winner selection code (not necessary to include for the question) ...
int numberMovements = ThreadLocalRandom.current().nextInt(20, 60 + 1);
MediaPlayer mp = MediaPlayer.create(getApplicationContext(), R.raw.pin);
final Runnable runnable = new Runnable() {
public void run() {
if (count > numberMovements){
resetColors();
getConstrainLayoutRectangle(positionAwardSelected).setBackground(ContextCompat.getDrawable(Roulette.this, R.drawable.selected_rectangle));
} else {
resetColors();
int randomPosition = ThreadLocalRandom.current().nextInt(0, awardList.size());
getConstrainLayoutRectangle(randomPosition).setBackground(ContextCompat.getDrawable(Roulette.this, R.drawable.selected_rectangle));
}
mp.start();
if (count++ < numberMovements) {//Time it takes to change the rectangle, before the winner 70% of the time it takes 175ms and 30% of the time it takes 250ms, to change to the winner it takes 100ms
handler.postDelayed(this, timeDelay());
} else {
handler.postDelayed(this, 100);
}
}
};
handler.post(runnable);
}
private int timeDelay(){
int a = new Random().nextInt(100);
if (a >= 30){
return 175;
} else {
return 250;
}
}
Color changes, speed and award selection work fine, I have 2 sound issues unfortunately. The first problem is that the sound does not match the color change of the roulette wheel, it seems that the sound is slower, the second problem is that the sound seems to go into an infinite loop since it never finishes playing
I realize that the first problem happens because the duration of the sound is greater than the duration of timeDelay (), when timeDelay > duration of sound, it matches the change of the selected rectangle with sound, but I need timeDelay () to be shorter for a fluid motion.
Alternative 2
When I substitute mp.start(); for MediaPlayer.create(this, R.raw.pin).start(); everything matches perfectly regardless of the duration of timeDelay (), but only the first 5 positions of the wheel, then the following loop occurs: silence of about 4 seconds, the sound is played 5 times and it never ends.
Hope someone can help me, thanks
I'm trying to break a special case that makes this code recursive.
I have a Javafx game where there are human and computer players each play when it's his turn and there can be many rounds.
A computer is supposed to play automatically and move to the next player immediately and show no direct indication to the UI (but it's possible to review what it did afterwards).
The problem is in the case where there are only computer players, we will come here the moment the currentBoardPane was loaded, enter the condition since all players are computers, set the board of the next player, and then without finishing the call, call this same function again:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
gameManager.setNextPlayer(); // it does current player property = next player
//update board on scene
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
}
});
Instead of this, if I subscribe a listener to the currentPlayer property in GameManager then I still need to call setNextPlayer() from that listener which is again recursive.
I can make a special case if all players are a computer, then run the game from a while(true){} instead of listeners and binds but there has to be a better way to break this recursion.
Is there a way to not get into recursion while still having listeners and binds?
Notes:
currentBoardPane signifies the current game board on the screen and it's an ObjectProperty.
Making the following assumptions about your code:
Everything is currently running on the FX Application Thread
The currentBoardPane.setValue(...) causes the UI to update (so you update the UI each move)
then a "quick and dirty" way to do this is:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
//update board on scene
Platform.runLater(() -> {
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
}
});
This delegates the updates to a new Runnable, schedules that runnable to execute on the FX Application Thread, and exits the handler immediately. Thus the call to currentBoardPane.setValue(...) is executed later and is no longer recursive.
In fact, if you do just a little more work:
private final Executor aiExecutor = Executors.newSingleThreadExecutor();
// ...
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
Task<Void> makeMoveTask = new Task<Void>() {
#Override
protected Void call() {
gameManager.playAutoMovesForCurrentPlayer();
return null ;
}
};
makeMoveTask.setOnSucceeded(e -> {
//update board on scene
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
aiExecutor.execute(makeMoveTask);
}
});
then this is exactly the code you would use if computing the move took enough time that it would not be acceptable to block the UI while it was happening. (And if computing the move takes very little time, this will still work just fine.) This assumes that playAutoMovesForCurrentPlayer() doesn't update the UI.
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.
I'm trying to create a loop using Java Swing Timer to constantly cycle through a set of images (i1, i2, i3....in where n is total number of images).
Each of the images is exactly the same size and must be displayed on a Label (say, l1).
There must be a delay of ten seconds between each image being displayed.
Any idea how I can go about this without using the Java TumbleItem applet> It's seems much too complicated for a simple implementation such as mine. (Displaying special deals posters on an online storefront application for school).
I am open to this being achieved in any other way.
Help would be greatly appreciated. Thanks in advance!
I'm trying to create a loop using Java Swing Timer to constantly cycle through a set of images
When you use a Timer you don't use a loop. When the Timer fires you just change the image. So somewhere you would need to keep a List of the images to display and an index of the currently displayed image.
Any idea how I can go about this without using the Java TumbleItem applet> It's seems much too complicated for a simple implementation such as mine
How is it complicated? It displays a series of images, which is close to what you want.
Yes, there is some extra code that loads the images and doesn't start the animation until all the images are loaded. So you could easily simplify the code by not worry about that. Also, there is code that does animation from from left-to-right and then right-to-left. You also don't need that part of the code. Also, there is code that configures the animation speed. Again you can hard code that.
So if you start with that example and then simplify the code you will have a simple solution. Give it a try and then post your code when you encounter a problem.
This is very simple. Use a timer like this:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//codehere
}
}, 0, delayInMillis)
Use can use an integer to specify in image.
public int image = 1;
in the run() function, use this to switch between the image
if(image = 1) {
image = 2;
} else if(image = 2) {
image = 3;
} if(image = 3) {
image = 0;
}
Now, wherever you are drawing your images, use this:
if(image == 1) {
//draw first image
} else if(image == 2) {
//draw second image
} else if(image == 3) {
//draw third image
}
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()