How to wait in java without stopping the entire program - java

I am making a game where the player can throw up to three projectiles at a time. I'm having trouble with the reloading. Here is the code:
public class AmmoManager {
public void tick(){
if(Player.ammo <= 0){
for(int t = 0; t < 10; t ++){
}
Player.ammo = 3;
}
}
}
It's supposed to wait a bit and then set the ammo to 3, but as soon as the ammo becomes 0, it is set to 3 instantly. What am I doing wrong?
I've tried using sleep, but the entire application would stop.

The problem is that your main program waits for tick() to return something.
Think about it like this; if you have this method
public boolean isOne(int num){
Thread.sleep(1000);
if(num==1){return true;}
return false;
}
and
boolean result = isOne(1);
if(result){ //can't be ran until isOne(1) returns the boolean
//do something
}
You can't continue with you main class when you call isOne() because you dont have the value of the boolean it returns. you have to wait for it to return the value, and then you can continue with the main method
The solution is threading. I'm not an expert on it, so you will need to consult someone else or an online resource, but I think it would look something like this:
public void tick(){
new Thread({ new Runnable(){
#Override
public void run(){
if(Player.ammo <= 0){
Thread.sleep(*seconds* times 1000);
Player.ammo = 3;
}
}).start();
}

There are two problems here.
as soon as the ammo becomes 0, it is set to 3 instantly. What am I doing wrong?
That's because the for loop does nothing. When you enter tick() and Player.ammo is 0, you instantly set it to 3.
I've tried using sleep, but the entire application would stop.
If you only have one thread, that is what Thread.sleep does.

I suspect that what you are attempting is more difficult than you think...
You need a main loop that controls the pace of the game. I might sleep() to ensure that the game does not run too fast.
Each pass, it must instruct every player, or whatever constructs you use, to update themselves. As one of the comments noted, that might involve incrementing a counter to replenish ammo.

Related

How to set a delayed in Android

I'm aware or the Thread.sleep() and postDelayed() function in java/androidStudio.
But here is the issue, I'm creating a replicate of Simon says game.
I created a generateSequence() function that puts number of 1-9 randomly into an array called sequence. After that, I need to display these sequence, which basically changes the background of a textView for a second and then back to its original background using the postDelayed() function.
Here is my code:
private void displaySequence(){
for(int i = 0; i < sequence.size(); i++) {
if(sequence.get(i) == 1) {
viewCard11.setBackgroundResource(R.drawable.text_view_circle4);
proceed = false;
handler.postDelayed(() -> {
viewCard11.setBackgroundResource(R.drawable.text_view_circle3);
proceed = true;
}, 1000);
}
else if(sequence.get(i) == 2) {}
else if(sequence.get(i) == 3) {}
else if(sequence.get(i) == 4) {}
else if(sequence.get(i) == 5) {}
else if(sequence.get(i) == 6) {}
else if(sequence.get(i) == 7) {}
else if(sequence.get(i) == 8) {}
else if(sequence.get(i) == 9) {}
while(!proceed) {}
}
}
But the problem with postDelayed() is that only whatever is inside the function is delayed. Meaning if this sequence had 2 element, it will simultaneously blink the background. The for loop doesn't wait for the postDelayed to finish whatever it is suppose to do, but instead it increments and proceed to put the next postDelayed.
To solve this issue, I tried to use a proceed boolean variable as a delay. What I do is that, before we call the postDelayed, I set proceed as false. Since it will not wait for postDelayed(), it will go to the next line of code which is the while loop.
By setting the proceed as false, I use it to create a infinite loop. But this infinite loop will be broken by the completed postDelayed() as proceed will be set to true in it, then the code can continues the for loop.
But I not sure why it simply doesn't work. When I run the code, it just displayed a blank screen. It seemed like the problem resides within the infitine while loop and postDelayed() can't update the proceed variable.
I tried using Thread.sleep(1000) as a replacement of postDelayed, but during startup, the program simply shows a white background for however long the parameter is passed to Thread.sleep()
I have exhausted my option and I hope someone has a better idea.
Thank you.
The loop does not wait for the postDelayed because what's inside the postDelayed happens async. This means that it works independently from the UI thread, on a second thread. What you want to accomplish is to make the UIthread wait for a period of time, and not start another thread after a specific period.
You could try to use the handler in this way:
Handler handler=new Handler()
{
public void handleMessage(Message msg)
{
if(msg.what==0)
{
viewCard11.setBackgroundResource(R.drawable.text_view_circle3);
proceed = true;
}
}
};
and then you may use the handler like this:
handler.postDelayed(() ->
{
//does nothing just waits 1 second and then send empty message
handler.sendEmptyMessage(0)
}, 1000);

using a loop to invoke multiple methods

I am newish to Java and trying to building a small rocket program.
I have 3 distinct methods that change the size and colour of the rockets exhaust jet on the graphical display when invoked which work great individually.
public void pulse1()
{
jet.setDiameter(6);
jet.setColour(OUColour.RED);
jet.setXPos(58);
}
public void pulse2()
{
jet.setDiameter(12);
jet.setColour(OUColour.ORANGE);
jet.setXPos(55);
}
public void pulse3()
{
jet.setDiameter(24);
jet.setColour(OUColour.RED);
jet.setXPos(48);
}
However, what I am trying to do is code another method ignition() that uses some sort of loop to invoke each of the three pulse methods in that chronological order a maximum of 5 times with a 500 millisecond delay between each call. (the idea being to simulate on the graphical display the firing up of the rockets engines)
Thus far I have tried the following without success.
public void ignition()
{
pulse1();
delay(500); // uses the inbuilt delay method
pulse2();
delay(500);
pulse3();
}
In Java, a loop will execute the contents of a code block. A code block is anything between two curly braces.
{
statement1;
statement2;
} // statement2 and statement2 are both inside the code block
So, when you declare a loop (perhaps with for or while), the loop will act on the very next code block. You can simply call the delay function once each time within the loop block, and it will wait once per loop.
A way to achieve what you are talking about using a for loop might be like so
public void ignition() {
for(int i = 0; i < 5; i++) {
pulse1();
delay(500); // uses the inbuilt delay method
pulse2();
delay(500);
pulse3();
delay(500);
}
EDIT: Misinterpreted what OP wanted to loop through
As you are not definite on how many number of times you should traverse in a loop but have a maximum limit of 5, use a random no. generator.
int i = rand.nextInt(5) + 1; //1 is minimum and 5 is maximum
int a=0;
while(a<i){
pulse1();
delay(500); // uses the inbuilt delay method
pulse2();
delay(500);
pulse3();
a++;
}
You could also use Thread.sleep(500) if your delay method is giving you issues.

LibGDX Do Something One Time During Update Method

I'm a bit new to Java and LibGDX, and I'm working on a point based game. A problem I'm facing is that the update method constantly runs something that I want to run on a timely manner. In my update method, I have the code to increment the score if a point is earned, and to make a lose state come up when the player lost. Without going into much detail, here's the pseudo code I have:
protected void update(float dt){
for(Thing x : a list) {
x.update(dt);
//continue
if (you complete the objective of the game) {
score++;
//do other stuff
}
//lost
if (you fail to complete the objective){
make lose state come up
}
}
//I want something like this to run:
if(score >=0 && score <=10){
do something ONCE(ie. print to console once)
}
if(score >= 11 && score <=15){
do something once
}
if(ect...){
do something else once
}
.
.
.
The problem here is that, if the IF condition is met, I notice the IF block gets executed multiple times very quickly(ie. printing to the console a lot). I have enclosed the details of the code that relies on the score in a separate class, I just want to be able to call the method from this update method and have it run once depending on the score conditions (ie. run it again if the score satisfies another IF statement)
I had the same problem, but I solved it by using following method. In Libgdx the update method runs in 1/60 second. That is the reason the method is rendering continously and the if condition will be executing various times.
To solve this problem, just declare an integer variable, say count, in your create method.
public static int count;
public static void create()
{
count =0;
// do other stuffs
}
protected void update(float dt){
// just increment this count value in your update method
for(Thing x : a list) {
count++
x.update(dt);
//continue
if (you complete the objective of the game) {
score++;
//do other stuff
}
//lost
if (you fail to complete the objective){
make lose state come up
}
}
// and make a small condition to run the if condition only once by using the declared variable "count".
if(count%60==0){
// here the condition only executes when the count%60==0.that is only once in 1/60 frames.
if(score >=0 && score <=10){
}
if(score >= 11 && score <=15){
}
if(ect...){
}
}
.
.
. This is how I solved the same issue.
The update() method is called every frame, multiple times very quickly(usually 60 times per second) in an infinite loop. This is not only specific in libGDX, but in any game engine. And when some condition of your if block evaluates to true, that if block is executed every frame until that condition becomes false again. But you want to execute the block only once after the condition changed.
Just declare a variable named isLastScoreUnder10 or whatever, and update it after the if block. Like this:
private boolean isLastScoreUnder10 = false;
protected void update(float dt){
if(!isLastScoreUnder10 && score >=0 && score <=10){
isLastScoreUnder10 = true;
// ..do something
} else {
isLastScoreUnder10 = false;
}
}

Else statement being executed after if statement is satisfied

I am using AndEngine to develop my game, though I'm thinking this problem is unrelated to AndEngine.
I have two possible dialogs that fire if:
User touches down in an incorrect area or
Users lifts up from an incorrect area.
Unfortunately, if a user touches down in an incorrect area, when they lift up they are also satisfying error 2--lifting up from an incorrect area.
Here's my code in a nutshell:
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
float y = pSceneTouchEvent.getY();
int dialog_count = 0;
if (pSceneTouchEvent.isActionDown() && y < 1000) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
AlertDialog Code
..............
}
}
dialog_count ++;
Log.d("Dialog Count", "Count is " + dialog_count);
} else if (dialog_count < 1 && pSceneTouchEvent.isActionUp() && y > 105) {
Log.d("Dialog Count", "Count is still " + dialog_count);
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Second AlertDialog Code
.................
}
}
}
return false;
}
Now, my first log for dialog_count shows a value of 1. However when I lift up the second log shows a value of 0. Somehow this value is either getting reset or my Else statement just can't see the updated value of dialog_count because I get the second dialog popping on top of my first.
Any ideas?
Your code initializes
int dialog_count = 0;
each time it runs.
To keep the value you saw the last time, make dialog_count an instance variable in the class.
Notice that you will be seeing two events, one for "down" and one for "up".
If you want to show only one then you need to use a flag to check if the user has touched down and then if you want not to show the touch up dialog just check from the flag. But the Touch down will always follow the Touch Up. You can use the Touch Move method if you want to show the dialog when the user has moved a bit.
If I understand correctly, what you are trying to do
dialogCount is function local (garbage collected, after you exit the method). So it will be 0 on each new run of the method. (Make it private class variable).
If you are referring to your dialogCount in multiple threads, dialogCount must be thread safe, so use concurrent primitives - AtomicInteger

controlling threads flow

I had a task to write simple game simulating two players picking up 1-3 matches one after another until the pile is gone. I managed to do it for computer choosing random value of matches but now I'd like to go further and allow humans to play the game. Here's what I already have : http://paste.pocoo.org/show/201761/
Class Player is a computer player, and PlayerMan should be human being. Problem is, that thread of PlayerMan should wait until proper value of matches is given but I cannot make it work this way. Logic is as follows: thread runs until matches equals to zero. If player number is correct at the moment function pickMatches() is called. After decreasing number of matches on table, thread should wait and another thread should be notified. I know I must use wait() and notify() but I can't place them right.
Class Shared keeps the value of current player, and also amount of matches.
public void suspendThread() {
suspended = true;
}
public void resumeThread() {
suspended = false;
}
#Override
public void run(){
int matches=1;
int which = 0;
int tmp=0;
Shared data = this.selectData();
String name = this.returnName();
int number = this.getNumber();
while(data.getMatches() != 0){
while(!suspended){
try{
which = data.getCurrent();
if(number == which){
matches = pickMatches();
tmp = data.getMatches() - matches;
data.setMatches(tmp, number);
if(data.getMatches() == 0){
System.out.println(" "+
name+" takes "+matches+" matches.");
System.out.println("Winner is player: "+name);
stop();
}
System.out.println(" "+
name+" takes "+matches+" matches.");
if(number != 0){
data.setCurrent(0);
}
else{
data.setCurrent(1);
}
}
this.suspendThread();
notifyAll();
wait();
}catch(InterruptedException exc) {}
}
}
}
#Override
synchronized public int pickMatches(){
Scanner scanner = new Scanner(System.in);
int n = 0;
Shared data = this.selectData();
System.out.println("Choose amount of matches (from 1 to 3): ");
if(data.getMatches() == 1){
System.out.println("There's only 1 match left !");
while(n != 1){
n = scanner.nextInt();
}
}
else{
do{
n = scanner.nextInt();
}
while(n <= 1 && n >= 3);
}
return n;
}
}
Well, let me first say that I think you are making this hardier than you need to. If it were me, I would create a 'GameMaster' class whose job it is to loop and tell each player when their turn comes up. Your player classes wouldn't have loops, just a takeTurn method. This way you can remove the waiting/notifying behavior from your player classes.
If you wish to keep the design you have, I would still get rid of the wait/notify and use a Semaphore. Check the docs for proper usage, but the gist is that you would remove the suspend/resume methods and have a acquire() call at the top of your loop and release at the bottom. Just make sure fairness is set to true in the constructor, that way you won't have to worry about a player taking two turns in a row by acquiring the semaphore lock twice in a row.
Ok, so I managed to do it without wait() etc.
http://paste.pocoo.org/show/201966/
When you find yourself having to set up communication between threads to synchronize their execution, just so that a specified sequence of events takes place (such as taking turns playing a game), it's a good sign that you may have more threads than you need.
In this case, consider a single thread that executes a takeTurn() method on various extensions of a Player class might make life easier for you. You could make Player an abstract base class that mandates .takeTurn(), then have HumanPlayer and MachinePlayer classes encapsulate the code that makes sense for each type of player inside that method. This should make extension to larger numbers of players relatively trivial as compared to lots of wait() and notify().

Categories