I am currently trying to build a dice rolling app in Android.
I managed to build my basic layout and methods with ease but I am currently stuck with the following issue:
I have two ImageView's on my screen and I need to make them change simultaneously 3 times, a basic simulation of a dice rolling, before the final dice face is presented to the user.
So far I tried it this way:
public void rollDiceAnim() {
////// diceone anim
final android.os.Handler handler = new android.os.Handler();
Runnable runnable = new Runnable() {
int counter = 0;
#Override
public void run() {
if (counter<4) {
counter++;
Log.e("Counter value",counter+"!");
int diceOneAnim = (int) ((Math.random() * 6) + 1);
ImageView dice1_img = (ImageView) findViewById(R.id.dice1_img);
switch (diceOneAnim) {
case 1:
dice1_img.setImageResource(R.drawable.d1);
break;
case 2:
dice1_img.setImageResource(R.drawable.d2);
break;
case 3:
dice1_img.setImageResource(R.drawable.d3);
break;
case 4:
dice1_img.setImageResource(R.drawable.d4);
break;
case 5:
dice1_img.setImageResource(R.drawable.d5);
break;
case 6:
dice1_img.setImageResource(R.drawable.d6);
break;
}
handler.postDelayed(this, 150);
} else {
rollDice();
}
}
};
/////////
///// dice two anim
final android.os.Handler handler2 = new android.os.Handler();
Runnable runnable2 = new Runnable() {
int counter2 = 0;
#Override
public void run() {
if (counter2<4) {
counter2++;
Log.e("Counter value",counter2+"!");
int diceTwoAnim = (int) ((Math.random() * 6) + 1);
ImageView dice2_img = (ImageView) findViewById(R.id.dice2_img);
switch (diceTwoAnim) {
case 1:
dice2_img.setImageResource(R.drawable.d1);
break;
case 2:
dice2_img.setImageResource(R.drawable.d2);
break;
case 3:
dice2_img.setImageResource(R.drawable.d3);
break;
case 4:
dice2_img.setImageResource(R.drawable.d4);
break;
case 5:
dice2_img.setImageResource(R.drawable.d5);
break;
case 6:
dice2_img.setImageResource(R.drawable.d6);
break;
}
handler2.postDelayed(this, 500);
} else {
rollDice();
}
}
};
////////////////////////
handler.postDelayed(runnable, 100);
handler2.postDelayed(runnable2, 100);
}
I have made two runnable objects, each iterating randomly, changing a set of dice faces before presenting the final one.
The problem is when running the two:
handler.postDelayed(runnable, 100);
handler2.postDelayed(runnable2, 100);
They do not run at the same time. After the first handler is finished, the second handler still has some work to do.
I've tried using threads instead of handlers, but my app just crashes.
I think you can try combining that two jobs into a same Runnable.
I would highly suggest checking out the Android API about AsyncTask. It a better way to work with asynchronous request especially if you have more than one.
Related
I am creating a poker dice game and I am having trouble obtaining the value of a List that is an instance variable.
public class ThrowDice {
List<String> result = new CopyOnWriteArrayList<>();
The value of this List is changed concurrently in a Thread run() method whose function is to set the five dice "rolling" at the same time. I am adding the resulting value (that is, the value of the die when it stops rolling) in the instance List with add(), however when I attempt to retrieve the value of the List later on, (for example, at the end of the rollDice method itself), the array is empty.
The code:
void rollDice(JLabel k, JLabel q, JLabel j, JLabel n, JLabel t, JLabel a) throws InterruptedException {
new Thread() {
#Override
public void run() {
String res = "";
try {
int times = 8;
for (int i = 0; i <= times; i++) {
int random = (int) (Math.random() * 6) + 1;
switch (random) {
case 1:
k.setVisible(true);
res = "k";
break;
case 2:
q.setVisible(true);
res = "q";
break;
case 3:
j.setVisible(true);
res = "j";
break;
case 4:
t.setVisible(true);
res = "t";
break;
case 5:
n.setVisible(true);
res = "n";
break;
case 6:
a.setVisible(true);
res = "a";
break;
}
Thread.sleep(300);
if (i == times) {
result.add(res);
System.out.println("The result is " + result);// **this works, List has values**
} else {
setToFalse(k, q, j, t, a, n);
}
} // end for
} catch (InterruptedException e) {
}
} //end run
}.start(); //end thread
System.out.println("The result is " + result);// **--------------- List is empty (why?)**
}//end rolldice
}
It is as if the values of the List get deleted after Run() ends, and I need to be able to retrieve the ArrayList value so that it can be passed to other methods.
The second println() call almost certainly happens while the rollDice() function still is sleeping in its first call to sleep(300). (I.e., before anything has been added to the list.)
Johannes Kuhn suggested that you "Try to .join the thread." What he meant was:
Thread t = new Thread() {
#Override
public void run() {
...
} //end run
};
t.start();
t.join(); // This _waits_ until the thread has finished its work.
System.out.println(...);
But there's a problem with that suggestion: That is, it never makes any sense to .join() a thread in the very next statement after .start()ing it. The whole point of threads is that they can work concurrently with each other.
This makes sense:
t.start();
DoSomethingElseConcurrentlyWithThread_t(...);
t.join();
This question already has answers here:
Java random always returns the same number when I set the seed?
(7 answers)
Closed 3 years ago.
I am trying to set the background color of a view using a timer to change the color every few seconds, but often a color is set twice in a row due to the fact that the random number referring to a specific color is generated twice. How can I change the code to avoid generating the same random number twice in a row?
final Runnable runnable = new Runnable() {
#Override
public void run() {
Random rand = new Random();
int n = rand.nextInt(3);
n += 1;
switch (n){
case 1:
colorView.setBackgroundColor(Color.GREEN);
break;
case 2:
colorView.setBackgroundColor(Color.MAGENTA);
break;
case 3:
colorView.setBackgroundColor(Color.CYAN);
break;
}
}
};
The only way is to make a test if the old number equals to the newest generated.
Random rand = new Random();
int n = rand.nextInt(3);
n += 1;
while (n == oldValue) {
n = rand.nextInt(3);
n += 1;
}
switch (n){
...
}
oldValue = n; //The oldValue should be global
Try this:
Set<Integer> generated = new HashSet<>();
int randomMax = 3;
final Runnable runnable = new Runnable() {
#Override
public void run() {
Random rand = new Random();
int n = rand.nextInt(randomMax);
while (generated.contains(n) && generated.size() < randomMax) {
n = rand.nextInt(randomMax);
}
if (generated.size() == randomMax) {
throw new Exception("all numbers already generated")
}
generated.add(n);
n += 1;
switch (n){
case 1:
colorView.setBackgroundColor(Color.GREEN);
break;
case 2:
colorView.setBackgroundColor(Color.MAGENTA);
break;
case 3:
colorView.setBackgroundColor(Color.CYAN);
break;
}
}
};
You can store the integer that was created the last time in a variable 'temp' and compare it to the integer that is created in the current step:
final Runnable runnable = new Runnable() {
#Override
public void run() {
if(tempInt == null){
int tempInt = 0;
int n = 0;
}
Random rand = new Random();
while(n == tempInt){
n = rand.nextInt(3);
n += 1;
}
tempInt = n;
switch (n){
case 1:
colorView.setBackgroundColor(Color.GREEN);
break;
case 2:
colorView.setBackgroundColor(Color.MAGENTA);
break;
case 3:
colorView.setBackgroundColor(Color.CYAN);
break;
}
}
You can do something like this
//set it as a global variable
int previousRandomNumber=0; //set it as 0 for first time
final Runnable runnable = new Runnable() {
#Override
public void run() {
int currentRandomNumber=new Random.nextInt(3);
currentRandomNumber+=1;
while(currentRandomNumber == previousRandomNumber){
currentRandomNumber = new Random.nextInt(3);
currentRandomNumber+=1;
}
/*store the current number as the previous number to check with next the generated number is the same or not*/
previousRandomNumber=currentRandomNumber;
switch (n){
case 1:
colorView.setBackgroundColor(Color.GREEN);
break;
case 2:
colorView.setBackgroundColor(Color.MAGENTA);
break;
case 3:
colorView.setBackgroundColor(Color.CYAN);
break;
}
}
};
I need to make an image bounce on the screen. I am trying to do this by shifting the image up 5 units, then taking a one second break, then shifting another 5 units up, etc. I am trying to shift up 5 times and then shifting down 5 times, with a one second break between each shift. I need help making the timer for one second so it acts like a break between each shift. I need to write the time() method.
public void moveIt(KeyEvent evt) throws InterruptedException {
switch (evt.getKeyCode()) {
case KeyEvent.VK_DOWN:
myY += 0;
break;
case KeyEvent.VK_UP:
for (int i = 1; i <= 10; i++) {
if (i <= 5) {
bounceUp();
} else {
bounceDown();
}
time();
}
break;
case KeyEvent.VK_LEFT:
myX -= 5;
break;
case KeyEvent.VK_RIGHT:
myX += 5;
break;
}
repaint();
}
Timer timer = new Timer();
public void bounceUp() throws InterruptedException {
myY -= 10;
}
public void bounceDown() throws InterruptedException {
myY += 10;
}
public void time() {
}
Try this:
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
}
TimerTask task = new TimerTask()
{
#Override
public void run()
{
time();//executed each second
}
}
timer.schedule(TimerTask task,1000,1000)
That should help
Welcome to SO!
Try using the schedule in Timer, like this:
Timer timer = new Timer();
timer.schedule(new YourClass(), 0, 1000);
Also, here's a great answer on the same issue:
https://stackoverflow.com/a/12908477/10713658
i am creating an app, that in the class i have this random:
public class Ejemplo extends Activity implements OnClickListener {
int ran=(int)(1*Math.random()) +1;
and also have this counter
int contador= 0; // this is just to know how many time i won
then i have 2 buttons a1 and a2
and in my onClick
switch (v.getId()) {
case R.id.a1:
if(ran == 1){
a1.setText("WIN");
contador= contador + 1;
}
else{
a1.setText("0");
}
a1.setClickable(false);
break;
case R.id.a2:
if(ran == 2){
a2.setText("WIN");
contador= contador + 1;
}
else{
a2.setText("0");
}
a2.setClickable(false);
break;
so the problem is that when i press the button: New Game the random is going to have the same number of the random, and i cant just call again the activity bc i dont want to reset my counter: contador.
How i can just reset my random, so it doesnt always select the same button?
just use a Random instead of Math.random it's easier to use, you can have like this:
Random random = new Random(); // random generator
// then inside your onClick this code
if(random.nextBoolean()){
// win
} else {
// lose
}
https://developer.android.com/reference/java/util/Random.html
edit:
it's really much simpler than what you trying to do:
public class Ejemplo extends Activity implements OnClickListener {
Random random = new Random(); // random generator
// then inside the click listener:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.a1:
if(random.nextBoolean()){
a1.setText("WIN");
contador= contador + 1;
gano();
}
else{
a1.setText("0");
}
a1.setClickable(false);
break;
Put int ran=(int)(1*Math.random()) +1; in the onClick rather than declaring it as an instance variable in the activity. So everytime a click happens, your ran variable will have a different value.
I'm trying to make a "Zelda-like" game in Java with Libgdx. As it will be lot of other things that my player, i'm trying to use Threads (example : for ennemies).
However, I have an exception and I don't find the solution :
Exception in thread "Tort 1" Exception in thread "Tort 2" >com.badlogic.gdx.utils.GdxRuntimeException: #iterator() cannot be used nested.
at com.badlogic.gdx.utils.Array$ArrayIterator.hasNext(Array.java:523)
at com.defel.game.entite.ennemi.Ennemi.deplacementAleatoire(Ennemi.java:368)
at com.defel.game.entite.ennemi.Ennemi.run(Ennemi.java:234)
And the code which is concerned is :
private synchronized void deplacementAleatoire(){
animationCourante = animationMarche[direction];
boolean bloquer = false;
for (MapObject obj : InfosSingleton.getInstance().getCollisionObjects()) {
RectangleMapObject rectMapObject = (RectangleMapObject) obj;
Rectangle rectObject = rectMapObject.getRectangle();
if(Intersector.overlaps(rectObject, rectangleColl)){
bloquer = true;
}
}
if(bloquer){
switch (direction) {
case 0:
direction = 2;
break;
case 1:
direction = 3;
break;
case 2:
direction = 0;
break;
case 3:
direction = 1;
break;
default:
break;
}
}
switch (direction) {
case 0:
rectangle.setY(rectangle.getY() + 2);
rectangleColl.setY(rectangleColl.getY() + 2);
break;
case 1:
rectangle.setX(rectangle.getX() - 2);
rectangleColl.setX(rectangleColl.getX() - 2);
break;
case 2:
rectangle.setY(rectangle.getY() - 2);
rectangleColl.setY(rectangleColl.getY() - 2);
break;
case 3:
rectangle.setX(rectangle.getX() + 2);
rectangleColl.setX(rectangleColl.getX() + 2);
break;
default:
break;
}
}
I think that my thread can't access to the List at the same time but I don't know how to resolve it...
Do you have an idea ? Thanks =D