My Sprite are spawned at a random time, after being spawned the the move upward until they get on a certain position then they should be removed. That's what I've been trying to do but I always get an error.
//this method is called at random time
public void newEnemy(){
Sprite enemy= Pools.obtain(Sprite.class);
enemy.set(enemySpr);
enemy.setPosition(200,150);
enemies.add(enemy);
}
//removing the enemy
while (enemyIterator.hasNext()){
Sprite nextEnemy=enemyIterator.next();//<--error here,this is line 66
if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
removeEnemy(nextEnemy);
}
}
//removeEnemy method
public void removeEnemy(Sprite sprite){
enemies.remove(sprite);
Pools.free(sprite);
}
//this is the error there I get:
Exception in thread "LWJGL Application" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at com.dreamroad.savethetree.EnemyClass.update(EnemyClass.java:66)
at com.dreamroad.savethetree.MyGdxGame.render(MyGdxGame.java:51)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Process finished with exit code 0
I think this is the reason why I get the error, but I'm not sure:
public void draw(SpriteBatch batch){
for(Sprite drawEnemy:enemies) { //enemies is the ArrayList
drawEnemy.draw(batch);
drawEnemy.translateY(deltaTime * movement);
}
}
As Subler says, the problem here is that you're trying to remove something from a list at the same time as iterating over it.
However, there's an easier solution. Simply call remove() on the iterator. This will remove the iterator's current element.
//removing the enemy
while (enemyIterator.hasNext()) {
Sprite nextEnemy = enemyIterator.next();
if(enemySpr.getY() + enemySpr.getHeight() >= treeObj.treeSpr.getY()) {
enemyIterator.remove();
Pools.free(nextEnemy);
}
}
The problem is that youre trying to remove something in a list you're currently iterating over, the thing i've always done in a situation like this is create an extra list which holds the Sprites that should be deleted, and then delete them after iterating over the list (or, at the end of your update method, or something like that)
A short code sample that illustrates my idea:
//removing the enemy
//Initialize a list to store the sprites to be removed
List<Sprite> toBeRemovedSprites = new ArrayList<Sprite>();
while (enemyIterator.hasNext()){
Sprite nextEnemy=enemyIterator.next(); //I get the error here..<--
if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
removeEnemy(nextEnemy);
toBeRemovedSprites.add(nextEnemy);
}
}
//Remove the sprites that should be deleted, after iterating over the list
for(Sprite s : toBeRemovedSprites){
enemies.remove(s);
}
//removeEnemy method
public void removeEnemy(Sprite sprite){
//Remove this line that removes the sprite from the list
//enemies.remove(sprite);
Pools.free(sprite);
}
Another thing you could do is just to use the remove function of the iterator,
imagine it could look something like this:
//removing the enemy
while (enemyIterator.hasNext()){
Sprite nextEnemy=enemyIterator.next(); //I get the error here..<--
if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
removeEnemy(nextEnemy, enemyIterator);
}
}
//removeEnemy method
public void removeEnemy(Sprite sprite, Iterator<Sprite> enemyIterator){
//Change the line to remove using the iterator
//enemies.remove(sprite);
enemyIterator.remove();
Pools.free(sprite);
}
Related
short description of what I am trying to do: I'm building a simple game where the user controls a vehicle and after some time more and more ghosts begin following the player, they follow the same trajectory as the player did with a delay.
To accomplish this I create an Array that contains the history of the player's location as a sequence of points. The problem, however, is that when I look at the data stored in this array I see that on all indices only the most recent location is stored.
First I create the array in a botManager class:
public class BotManager {
private ArrayList<Bots> bots;
private List<Point> history;
BotManager() {
history = new ArrayList<>();
bots = new ArrayList<>();
}
Then in the update method of the manager class I add the current location of the player to the array
public void update(Point currLoc) {
history.add(currLoc);
for (Bots bot : bots) {
bot.setLocationData(history);
bot.update();
}
}
A look at the update method in the main GameView class, in case I forgot something here
public void update() {
player.update(playerPoint);
botManager.update(playerPoint);
}
In the bots class' constructor I pass the history list (locationData) and determine its length to find out the delay in positioning. After which the following code handles the position of the bot.
#Override
public void update() {
loc = locationData.get(delay - 1);
this.rectangle = new Rect(loc.x - Constants.BOTSIZE/2, loc.y - Constants.BOTSIZE/2,
loc.x + Constants.BOTSIZE/2, loc.y + Constants.BOTSIZE/2);
}
To get back to the problem, whenever I check the contents of the history array, I find that it only contains one point on all indices, and its the most recent even when I moved the player, causing the ghost to always remain on top of me.
So my question here is, what am I doing wrong here?
Not clear from your posted code, but could it be, that you are just modifying the Point which you are adding instead renewing your object's Point objects?
Try
public void update(Point currLoc) {
history.add(new Point(currLoc)); // new Point object added here
for (Bots bot : bots) {
bot.setLocationData(history);
bot.update();
}
}
public class Player {
private Sprite enemy;
public Rectangle bounds;
private SpriteBatch batch;
private float deltaTime;
private float timer;
private ArrayList<Sprite> enemies;
private Iterator<Sprite> enemyIterator;
private ArrayList<Vector2> posCoordinate;
Sprite newEnemy;
public void create(){
batch=new SpriteBatch();
timer=0;
enemy=new Sprite(new Texture(Gdx.files.internal("spr_player.png")));
bounds=new Rectangle(200,700,82,80);
enemies=new ArrayList<Sprite>();
posCoordinate=new ArrayList<Vector2>();
newEnemy=Pools.obtain(Sprite.class);
}
public void update(){
deltaTime=Gdx.graphics.getDeltaTime();
enemyIterator=enemies.iterator();
timer+=1*deltaTime;
if(timer>=1f){
newEnemy(); //method called every second
timer-=1;
}
}
public void newEnemy(){
Vector2 position=Pools.obtain(Vector2.class); //vector2 is created for each enemy every second.
position.set(200,700);
posCoordinate.add(position);
newEnemy=Pools.obtain(Sprite.class); //enemy created every second
newEnemy.set(enemy);
enemies.add(newEnemy);
}
public void draw(SpriteBatch batch){
//this is where the enemy position is set and movement
for(Sprite enemy:enemies){
enemy.draw(batch);
}for(Vector2 position:posCoordinate){
newEnemy.setPosition(position.x,position.y);
position.y-=2;
}
}
}
newEnemy() method is being called every second that's why a new sprite is being rendered every second.
Basically what I'm trying to do is that when a new enemy is spawned, it must move downward until it goes outside the screen.But what is happening is that the enemy will only move for one second.
I think you've confused things by introducing the member variable newEnemy. You have a method that creates a new enemy and adds it to your enemies list, and after that, there should not be a reason to reference it separately from the list, so you should just allow the newEnemy reference to be discarded.
Therefore, you should remove the Sprite newEnemy line from your class, and just declare it within the newEnemy() method.
Also, there's no need for your list of Vector2's for positions, because the Sprite class already stores a position. You just need to move the individual sprites. So remove everything related to posCoordinate as well. Your newEnemy() method should just look like this:
private void newEnemy(){
Sprite newEnemy = Pools.obtain(Sprite.class);
newEnemy.set(enemy); //I recommend renaming your `enemy` variable to something like `prototypeEnemy` for clarity
newEnemy.setPosition(200, 700); //need to start it at correct location.
enemies.add(newEnemy);
}
Finally, in your draw method (which is the wrong place for updates) you're trying to move only the most recent enemy created, instead of moving all of them. Note that every iteration of the loop is affecting the same instance: newEnemy, which is only the last enemy you created.
Here's how I would revise your class.
1) The movement speed should be a constant, measured in world units per second, so declare something like this at the top of your class:
private static final float ENEMY_SPEED = -120f;
2) At the bottom of your update() method, you can add this to cause all of your enemies to move:
for (Sprite sprite : enemies){
sprite.translateY(deltaTime * ENEMY_SPEED);
}
3) Under that, you can add a check for when they are off screen, so you can remove them. The iterator instance must be used to avoid a ConcurrentModificationException.
Iterator<Sprite> enemyIterator = enemies.iterator();
while (enemyIterator.hasNext()){
Sprite sprite = enemyIterator.next();
if (sprite.getY() + sprite.getHeight() < screenBottom) //screenBottom is something you can calculate from your camera like camera.getPosition().y - camera.getHeight()/2
removeEnemy(sprite);
}
4) And to remove them, since you're using pooling, you should put them back in the pool when you finish with them
private void removeEnemy(Sprite sprite){
enemies.remove(sprite);
Pools.free(sprite);
}
5) In your draw method, remove the second for loop, now that we're handling the position update in the update method.
I am working on a game project. So far so good, but i just stuck on ome basic thing and i cant find a solution and make it work properly. I decided to come here and ask you ppl of suggestions.
PROBLEM:
When the player comes to contact with a diamond, i suppose to remove the diamond from the level and from the arraylist containing all the objects in the world. What always happens i get an exception error message after remove() method called.
CODES:
1.Class with the list: EDIT_1
private ArrayList<AbstractObject> objects = new ArrayList<AbstractObject>();
public void removeObject(String name){
ArrayList<AbstractObject> newest = new ArrayList<AbstractObject>();
ListIterator<AbstractObject> delete=objects.listIterator();
while(delete.hasNext()){
if(name.equals(delete.next().getName())){
delete.remove();
}
else{
delete.previous();
newest.add(delete.next());
}
}
objects=newest;
}
2.Player class calling the removeObject method: EDIT_1
public void playerLogic(){
fallingDown();
for(AbstractObject object : this.getWorld().getListOfObjects()){ <--------ERROR HERE
if(this.intersects(object)){
if(object instanceof FinishZone && points>=getWorld().getDiamondCount()){
if(!(getWorld().getManager().isMoreLevels())){
getWorld().getMenu().openMenu(true);
}
else{
this.getWorld().getManager().nextLevel();
}
}
if(object instanceof Diamond){
points++;
this.getWorld().removeObject(object.getName());
}
}
}
}
ERROR:
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at project.objects.characters.Player.playerLogic(Player.java:77)
at project.objects.characters.Player.update(Player.java:70)
at project.world.World.update(World.java:110)
at project.Main.update(Main.java:122)
at project.Main.run(Main.java:65)
at java.lang.Thread.run(Thread.java:745)
I checked up some examples of removing items from arraylist but i havent find the difference.
EDIT_1:
So i figured out how to do it but i always get the error. I edited the removeobject code block. This worked good with a neutral list that i created for testing. I put all the items which i dont want to delete into a new list than ovewritten the old arraylist with the newest one. It worked with no exception error. When i made the same with the game list i want to edit it thrown the same error.
Ill put there the render code too if maybe there is the problem...
public void render(Graphics g) {
if(menu.getChoice()==-1){
menu.render(g);
}
else if(menu.getChoice()==0){
g.setColor(Color.white);
for(AbstractObject tempObj : objects){
tempObj.render(g);
}
}
}
FIXED:
Ill changed the starting list is ListIterator instead of putting items in arrayList before adding it to ListIterator. All methods changed to iterate. Working fine :)
You can't remove object while iterating over a list.
One option - use iterator.remove() - if you iterate with iterator, not the "enhanced for loop". You'll need to slightly modify your loop code, but the functionality will be the same.
Another: Store all objects to remove in an auxiliary list, and remove them all at the end of the loop.
So I've been working on a small tanks program, but whenever I try to run it I get an ArrayIndexOutOf BoundsException on line 477 (http://pastebin.com/k4WNXE6Q).
void placeStations(int Number) {
for (int i = 0; i<Number; i++) {
stations.add(new RefillStation(int(random(0, width)), int(random(0, height))));
// This line of code refuses to work. I get an 'ArrayIndexOutOfBoundsException: -3'
RefillStation station = stations.get(i);
for (Tank tank : tanks) {
if (station.getRectangle().intersects(tank.getRectangle())) {
station.kill();
i=i-1;
}
}
for (Obstacle obstacle : obstacles) {
if (station.getRectangle().intersects(obstacle.getRectangle())) {
station.kill();
i=i-1;
}
}
}
}
I have tried for hours to find an error, but I can see nothing different from the method above, which seems to work fine. I am using the 'i' type for loops in some places because whenever I try to remove something from an index in a modern for loop, it gives me a size change exception. Any Ideas on what I could do to remedy this?
Multiple overlaps with Tanks and Obstacles will cause i to be reduced repeatedly. But you want to kill the station only once: break out of the loop.
for (Tank tank : tanks) {
if (station.getRectangle().intersects(tank.getRectangle())) {
station.kill();
i=i-1;
break;
}
}
for(each) style loops use iterators under the hood and most of the time you can't edit a collection that you're iterating over other than through the remove() method of the iterator object. To do that you'll have to use the iterator explicitly. see this answer
btw variable names with an upper case first character work, but makes it harder for people to read and understand your code.
I am not sure if this is the issue but isn't ArrayList is supposed to have 1st argument for index and second one for the element:
public void add(int index,
E element)
And your code is :
stations.add(new RefillStation(int(random(0, width)), int(random(0, height))));
It is adding element first and then specifying the index.
Short introduction:
I'm building a game, where monsters spawn at the top, and moves through a path, to the reach a point where they need to be removed/destroyed/deleted. But I can't seem to get the Monster Object deleted.
for (Monster i : Monstre)
{
this.add(i); //adds monster to JPanel
if(i.monstery > 50 && i.monsterx > 50){ //check if monster have reached end point
this.remove(i); //Should remove Object from the JPanel ?
i = null; //Sets object too null
Monstre.remove(i); //Removes object from arrayList "Monstre".
}else{
//Update the monsters bounds
The above removes the object from the JPanel, and it seems to be all good. But when i call System.out.println(Monstre.size()); I get an increasing amount of monsters spawned, and if increasing the monster spawn rate, the program starts to eventually slow down, because amount of monsters in the Monstre arraylist is over 9000, and never decreasing.
What I'm looking for, is a way to remove these objects while the game is running.
Remove the i = null; line. This is not C and you don't have to assign your variables to null. JVM will do that for you (google "java garbage collection"). Because of that line, you practically call Monstre.remove(null) which does not work.
Also, you cannot iterate over the collection in that manner and modify it (remove values). Save the monsters you want to delete in an array outside of the scope of the loop, and remove them after the loop finishes. Otherwise, use an iterator:
Iterator<Monster> it= Monstre.iterator();
while (it.hasNext()) {
Monster i= it.next();
//code code code
if (shouldDelete) {
this.remove(i);
it.remove();
}
}
In addition to the suggestion in the first answer, you should change your loop. Removing items from the Monstre list while using the for-each loop will cause problems.
Instead try :
Iterator<Monster> iter = Monstre.iterator ();
while (iter.hasNext())
{
i = iter.next();
this.add(i); //adds monster to JPanel
if(i.monstery > 50 && i.monsterx > 50){ //check if monster have reached end point
this.remove(i);
iter.remove();
}else{
EDIT :
Here's an explanation where you can't use the for-each loop :
So when should you use the for-each loop? Any time you can. It really
beautifies your code. Unfortunately, you cannot use it everywhere.
Consider, for example, the expurgate method. The program needs access
to the iterator in order to remove the current element. The for-each
loop hides the iterator, so you cannot call remove. Therefore, the
for-each loop is not usable for filtering. Similarly it is not usable
for loops where you need to replace elements in a list or array as you
traverse it. Finally, it is not usable for loops that must iterate
over multiple collections in parallel. These shortcomings were known
by the designers, who made a conscious decision to go with a clean,
simple construct that would cover the great majority of cases.
i = null; //Sets object too null
Monstre.remove(i); //Removes object from arrayList "Monstre".
Here you set the variable i to null then you request that i (i.e. null) is removed from your arraylist, the arraylist does not contain null so nothing happens. Setting things equal to null is very rarely nessissary.
As you have correctly said removing the i=null upsets the program, this is because you are iterating through the list and then changing the list while iterating, you have two options;
1) go through the Arraylist in a manor similar to an array
import java.util.*;
public class Test{
public static void main(String [] args){
ArrayList<Double> doubles=new ArrayList<Double>();
for(double i=0;i<10;i++){
doubles.add(i);
}
//remove 7.0s from doubles
for(int i=doubles.size()-1;i>=0;i--){
//must go through backwards - see http://stackoverflow.com/questions/12111210/java-arraylist-search-and-remove for why
if (doubles.get(i).equals(7.0)){
doubles.remove(i);
}
}
}
}
2) use an iterator and its remove method
import java.util.*;
public class Test{
public static void main(String [] args){
ArrayList<Double> doubles=new ArrayList<Double>();
for(double i=0;i<10;i++){
doubles.add(i);
}
//remove 7.0s from doubles
Iterator<Double> iterator=doubles.iterator();
while(iterator.hasNext()){
Double testDouble=iterator.next();
if (testDouble.equals(7.0)){
iterator.remove();
}
}
}
}
You cannot remove this element in a for-loop.
You need to use listIterator() method to retrieve an iterator that can be modified and loop with iterator-style. Otherwise you would always get java.util.ConcurrentModificationException