Sorry if this is a very closed question that won't be useful to others, but I'm just stumped by this bug and I haven't been able to solve it for weeks!
I am working on a wave based survival game and am currently working on a spawning mechanism.
The code I wrote works perfectly for one wave, but somehow doesn't restart for further waves.
I have written the code below:
public void run() {
while (ingame) {
if (enemyList.isEmpty()) {
stopSpawn = false;
try {
Thread.sleep(500);
spawnNewEnemy();
} catch (InterruptedException ex) {
System.out.println("Interrupted");
}
} else {
if (!enemyList.isEmpty() && !stopSpawn) {
// getEnemyAmount returns the amount of enemies that should be spawned this wave
for (int enemiesSpawned = 0; enemiesSpawned < getEnemyAmount(); enemiesSpawned++) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
System.out.println(currentWave);
spawnNewEnemy();
}
stopSpawn = true;
}
}
}
}
Here is the spawnNewEnemy method
public void spawnNewEnemy() {
Random spawn = new Random();
int spawnX = spawn.nextInt(500);
int spawnXTest = b.bX - spawnX;
if (spawnXTest < 20) {
spawnX = spawnX + 20;
} else {
}
int spawnY = spawn.nextInt(500);
int spawnYTest = b.bX - spawnY;
if (spawnYTest < 20) {
spawnY = spawnY + 20;
} else {
}
spawnY = spawnY + 20;
spawnX = spawnX + 20;
enemyList.add(new Enemy(spawnX, spawnY));
}
I can read the following in your code:
If the list of enemies is empty, you set stopSpawn to false and spawn an enemy.
That triggers your else-statement.
There, you spawn enemies based on the enemy count.
stopSpawn is set to true, thus your else-statement doesn't get triggered anymore.
Nothing happens anymore untill your enemylist is empty.
If your enemylist is empty again, you start over.
The logics seems ok, so I'm thinking either the way you spawn enemies through spawnNewEnemy() is faulty, or the way you remove enemies from the enemyList is faulty. I see neither of that code so that is as far as I can go in this answer.
I guess your problem with a loop is in stopSpawn value.
You set it to true after the first wave and likely not setting to `false' before starting the next wave.
Related
I would like to break a while loop only when all of the "bots" are upright. (*These bots being referred to are mini USB robots).
.upRight() returns true when a bot is standing and false when not.
public static boolean checkSomething() throws ... {
while (true) {
for (i = 0; i < bots; i++) { // bots = 2
if (!theMainBots[i].isUpright()) {
...
Thread.sleep(1000);
}
else {
return true;
}
}
}
The issue I'm facing, is that if the isUpright() method returns true for the first "bot", then all other bots are left unchecked and may return false. The intention is to wait for the user to place the bot in an upright position before proceeding.
You should check all the bots first, then act on the result. Don't try to act on the result inside the check loop.
Also, since the code doesn't return until all bots are upright, the method is misnamed and shouldn't return a value.
public static void waitUntilAllUpright() throws InterruptedException {
for (;;) { // forever loop
boolean allUpright = true;
for (i = 0; i < bots; i++) {
if (! theBots[i].isUpright()) {
allUpright = false;
break;
}
}
if (allUpright)
return;
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
} // loop back to check all bots again
}
If you want to wait until the user makes the bot upright you could change the if to a while:
while (true) {
for (i = 0; i < bots; i++) { // bots = 2
while(!theBots[i].isUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
}
}
return true;
}
This will loop through each element in the Array and while any given bot is not upright, it will loop and sleep until the bot is turned upright. In which case, you do not need to while(true) loop:
public static boolean checkUpright() throws InterruptedException {
for (i = 0; i < bots; i++) { // bots = 2
while(!theBots[i].isUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
}
}
return true;
}
One way to achieve this, is using a variable that will determine when to leave the loop. Your problem here, is that you also need to change your for loop for a while loop. Why is that? Because you don't know if the bot you just checked was moved or not. Also, the outer loop is unnecessarily, unless you wanted to recheck again. So the code would end looking something like this.
public static boolean checkUpright() throws InterruptedException {
int counter = 0;
while (counter <= theBots.length) { // bots = 2
if (!theBots[i].isUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
} else {
counter ++;
}
}
}
The context is not completely clear, but mixing logical control with user interaction might be the problem. Perhaps this approach might work:
public static boolean checkUpright() throws InterruptedException {
while (!areAllBotsUpright()) {
System.out.println("Please ensure I'm upright");
Thread.sleep(500);
}
}
public static boolean areAllBotsUpright() {
for (i = 0; i < bots; i++) {
if (!theBots[i].isUpright()) {
return false;
}
}
return true;
}
you can create a list from array of bots , iterate over this list using iterator
if a particular bot is upright , remove it from this list using iterator.remove.
outer while will run until list is not empty.
public static boolean checkUpright() {
ArrayList<Bot> notUprightBots= (ArrayList<Bot>) Arrays.asList(theBots);
while (!notUprightBots.isEmpty()) {
Iterator<Bot> iterator=notUprightBots.iterator();
while(iterator.hasNext()){
Bot bot=iterator.next();
if (!bot.isUpright()) {
System.out.println("Please ensure I'm upright");
try{
Thread.sleep(500);
}catch(InterruptedException e){
}
}else {
iterator.remove();
}
}
}
return true;
}
I've been working with SikuliX to get some try some ATDD. The code works well when only I am the one working with it. However transferring the below code to anyone else is simply counter-productive irrespective of how well I comment the code.
int numOfTries;
while (!isFinishStage && numOfTries != 3) {
numOfTries++;
try {
temp = new Pattern("imgs/img1.png").similar(0.9f);
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
isFinishStage = true;
break;
}catch (FindFailed ff1) {
try {
temp = new Pattern("imgs/img2").similar(0.5f);
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
isFinishStage = true;
break;
} catch (FindFailed ff2) {
try{
temp = new Pattern("imgs/img3");
s.wait(temp, 1);
s.find(temp);
s.click(temp);
} catch (FindFailed ff3) {
continue;
}
}
}
}
A FindFailed exception is thrown once a pattern/image cannot be matched against anything on the screen (similarity simply adjusts the tolerance level). For the current GUI that it is automating, there are three possible scenarios (where this piece of code comes to play)
Screen A pops up
Screen B pops up
Neither 1 or 2, instead 'Next' pops up
Thus we check for Screen A, if not we check for Screen B, if not we check for Next, if not, repeat the cycle until we exceed the number of tries — meaning that the test has failed.
With the way Sikuli works or atleast how I've been interpreting it, you would have to perform various loops through multiple try-catch statements which seems a little off putting.
PS: The idea behind the above code is to just get it to work. If there is any ambiguity let me know so that I can clarify.
The following code is (I think) equivalent to your code:
int numOfTries;
while (!isFinishStage && numOfTries < 3) {
numOfTries++;
if (tryPattern(s, "imgs/img1.png", 0.9f) ||
tryPattern(s, "imgs/img2", 0.5f)) {
isFinishStage = true;
} else {
// Note that the third "attempt" is inconsistent with
// the others because you don't set isFinishedStage.
tryPattern(s, "imgs/img3", 1.0f)
}
}
private boolean tryPattern(SomeClass s, String path, float similarity) {
try {
Pattern temp = new Pattern(path);
if (similarity != 1.0f) {
temp = temp.similar(similarity);
}
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
return true;
} catch (FindFailed ff) {
return false;
}
}
I would like you to read software principles and make your code clean after lecture:
10 Object Oriented Design Principles
After this you should know basics like DRY and KISS principles that should emplace pretty well in your posted code.
Here's how:
String [] patterns = {
"imgs/img1",
"imgs/img2",
"imgs/img3"
};
float [] similarities = {
0.9f,
0.5f,
0.1f
};
for(int i=0; i<patterns.length; i++) {
String str = patterns[i];
try {
float sim = 0.1; // default
try {
sim = similarities[i];
} catch (IndexOutofBoundsException e) {;}
temp = new Pattern(str).similar(sim);
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
if(i != patterns.length - 1){ // Different last case
isFinishStage = true;
break;
}
} catch (FindFailed ff) {
continue;
}
}
i have a problem with one thing. I have a map of 10 cities and a civilian. I want the civilian to be walking from city to city randomly. But the problem is that the city is beeing chosen on and on so the civilian is changing the destination before he reachs it. This is my part of a code of a Jpanel where everything is drawn:
#Override
public void run() {
while (running) {
update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
}
}
}
private void update() {
if (game != null && running == true) {
c.goTo(cities); // c is civilian
}
}
and this is part of code for civilian
private boolean set = true;
public void move(int x, int y) {
if (this.location.x != x || this.location.y != y) {
if (this.location.x > x) {
this.location.x -= 1;
} else {
this.location.x += 1;
}
if (this.location.y > y) {
this.location.y -= 1;
} else {
this.location.y += 1;
}
}
}
public void goTo(ArrayList<City> cities) {
City city;
if (set) {
city = cities.get(rand());
move(city.location.x, city.location.y);
set = false;
} else {
set = true;
}
}
public int rand() {
int i;
Random rand = new Random();
i = rand.nextInt(10);
return i;
}
How to solve it ?
So, your problem is here:
while (running) {
update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
}
}
You're calling update every 17 milliseconds which in turn is causing your civilian to move to a new city every 17 milliseconds. You could make a separate statement that calls update while another boolean statement is false so that you travel only when he is in a city.
For example:
boolean travelling = //whatever you go about to configure this
while(travelling == false){
update();
}
This will cause him to only travel when he is not in a city. Here is some very rough code (you will have to configure it to your liking):
//civilian x //civilian y
if(this.location.x == //randomed city.x && this.location.y == //randomed city.y){
travelling = false;
}
This will most likely need to be within the run() method in your first set of code, so it can be checked over and over. But let me explain what the above code is doing:
First, you have a thread or something keeping it running checking if your civilian's x and y correspond to the most recently randomed city's x and y, obviously when they're the same, the civilian is at the city.
Second, when the x and y's are the same, the statement makes travelling false
Third, When travelling is false, your custom update method is called, picking a new city, at random and putting your civilian back on the move.
I am working on an app that counts the number of questions marks in a few paragraphs of text.
After the scanning is done (which takes no time at all) I would love to have the total presented after the number goes from 0 to TOTAL. So, for 10: 0,1,2,3,4,5,6,7,8,9 10 and then STOP.
I have tried a couple of different techniques:
TextView sentScore = (TextView) findViewById(R.id.sentScore);
long freezeTime = SystemClock.uptimeMillis();
for (int i = 0; i < sent; i++) {
if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
sentScore.setText(sent.toString());
}
}
Also I tried this:
for (int i = 0; i < sent; i++) {
// try {
Thread.sleep(500);
} catch (InterruptedException ie) {
sentScore.setText(i.toString());
}
}
I am sure these are both completely amateur attempts. Any help would be much-appreciated.
Thanks,
Richard
I've used a more conventional Android-style animation for this:
ValueAnimator animator = new ValueAnimator();
animator.setObjectValues(0, count);
animator.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
view.setText(String.valueOf(animation.getAnimatedValue()));
}
});
animator.setEvaluator(new TypeEvaluator<Integer>() {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
return Math.round(startValue + (endValue - startValue) * fraction);
}
});
animator.setDuration(1000);
animator.start();
You can play with the 0 and count values to make the counter go from any number to any number, and play with the 1000 to set the duration of the entire animation.
Note that this supports Android API level 11 and above, but you can use the awesome nineoldandroids project to make it backward compatible easily.
Try this:
private int counter = 0;
private int total = 30; // the total number
//...
//when you want to start the counting start the thread bellow.
new Thread(new Runnable() {
public void run() {
while (counter < total) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.post(new Runnable() {
public void run() {
t.setText("" + counter);
}
});
counter++;
}
}
}).start();
The question is very old, but I am posting this so that it would help someone else.
I have used these 2 amazing libraries.
Try them
https://github.com/MasayukiSuda/CountAnimationTextView
Or
2. https://github.com/robinhood/ticker
Hope this helps :) Happy Coding!!!
Use TextSitcher
for the best effects. It will transform the text softly.
When coming to the change of the text use the below Code.
> int number = 0;
> Timer obj = new Timer();
> TimerTask tt = new TimerTask() {
> #Override public void run() {
> // TODO Auto-generated method stub
> textView.setText(number++);
> if(number < score)
> obj.schedule(tt, 200); } };
> obj.schedule(tt, 200);
Use a worker thread to do the waiting and update your UI thread.
You could use an AsyncTask, though it might be an overkill for this job. If you use this, In the doInBackground() loop over the number of sleep periods and after every sleep period, update the count in the UIthread.
There you go! Slukain just gave you the working code :P
Maybe try changing the for loop to something like:
int count = 0;
while (count != sent) {
if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
count++;
sentScore.setText("" + count);
freezeTime = SystemClock.uptimeMillis();
}
}
I am coding Oregon Trail for a school project and I am implementing the hunting mini game. We are using model view presenter with a card layout. When the HuntingPanel gets switched to it calls run, and the JOptionPane comes up, but then the whole application freezes and I have to force quit. I coded the entire hunting game in a separate project, and just now brought the files over to the Oregon Trail game. It works fine in its own project with its own JFrame. I'm not sure what to do.
I call this to initialize the panel, switch to it, and run the game.
public void initialize(int ammo) {
player.setBullets(ammo);
bulletLabel.setText("Bullets: "+player.getBullets());
presenter.switchToPanel(OregonTrailPresenter.HUNTING_PANEL);
run();
}
This is my run method.
public void run() {
// starting message
JOptionPane.showMessageDialog(null, "You have reached a nearby field to hunt. You will stay\nhere until " +
"you run out of ammunition or click Return to Trail.");
// while the player has bullets or doesn't click return to trail
while (player.getBullets() > 0 && stillHunting) {
// creates random animals
checkForAnimal();
// moves and updates screen
repaint();
update();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
endHunting();
}
And here are other method used.
private void checkForAnimal() {
int x = 0;
int y = rand.nextInt(MAX_Y)-40;
int rand1 = rand.nextInt(100);
String str = null;
if (rand1 < 50) {
str = "left";
x = MAX_X-40;
}
else if (rand1 >= 50) {
str = "right";
x = 0;
}
double gen = rand.nextGaussian(); // gen is a number from -inf to +inf
gen = Math.abs(gen); // gen is now a number from 0 to inf
if (gen >= 1.9 && gen < 2.1) { //1.19%
animalList.add(new Bunny(x,y,str));
}
if(gen >= 2.1 && gen < 2.2) { //0.9%
animalList.add(new Bear(x,y,str));
}
if (gen >= 2.2 && gen < 2.3) {
animalList.add(new Deer(x,y,str));
}
}
public void update() {
for (int i = 0; i < animalList.size(); i++) {
animalList.get(i).move();
}
}
You have to implement javax.swing.Timer instead of Thread.sleep(int), because this code line freezes all GUI during EDT until Thread.sleep(int) ends. Here is demonstrations what happens if the GUI is delayed during EDT by Thread.sleep(int)
Your program "freezes" because you did not start a new thread for the while loop. Since the panel updates and redraws are handled in the main thread, you are preventing them from happening. To fix this problem you have to start a new thread. You can do this by making your class implement runnable and use new Thread(this).start() to run your loop.
class HuntingGame extends JPanel implements Runnable {
public void initialize(int x) {
//...
new thread(this).start();// This will run your 'run()' method in a new thread.
}
}