0
votes

I have a group that has a Map that associates every entity with an actor; it has the method addEntity and removeEntity for adding and deleting entities to/from the Map and their respective actors to/from the group.

public final void addEntity(final Entity entity) {
    EntityActor entityActor = new EntityActor(entity, shapeRenderer);
    this.addActor(entityActor); //adding the actor to the group
    this.entitesActors.put(entity, entityActor); //adding the actor to the map
}

public final void addEntities(final Collection<Entity> entities) {
    entities.stream().forEach(this::addEntity);
}

public final void removeEntity(final Entity entity) {
    entitesActors.get(entity).addAction(Actions.removeActor()); //removes actor from group
    this.entitesActors.remove(entity); //removes actor from map
}

public final void removeEntities(final Collection<Entity> entities) {
    entities.forEach(this::removeEntity);
}

This group also has a reset method that deletes all his children and adds new ones.

 public final void reset(final Collection<Entity> entities) {
    Gdx.app.postRunnable(() -> {
        removeEntities(entitesActors.keySet());
        this.addEntities(entities);
    });
}

The first time reset is called (Map and group are empty) everything's fine, but the second time I call it (with Map and Group containing the entities of the first call) I got a cuncurrentModificationException from the removeEntity method.

I tried to edit it like this:

public final void removeEntities(final Collection<Entity> entities) {
    entitesActors.entrySet().stream().filter(e -> entities.contains(e.getKey())).map(e -> e.getValue())
            .forEach(a -> a.addAction(Actions.removeActor()));
    entitesActors.keySet().removeAll(entities);
}

Or bypassing removeEntities method and just calling:

this.clearChildren();
this.entitesActors.clear();

In both cases no exception is fired, the actors are successfully removed and added in both Map and Group but they are not drawn onto the stage. (the method draw in each actor is called but I can't see them on screen, all I got is a black screen).

Somebody know the correct way to do it or maybe telling me where I make a mistake? Thanks very much for the help.

EDIT: I tried @luis-fernando-frontanilla solution but it didn't worked out. Now my reset method looks like this

public final void reset(final Collection<Entity> entities) {
    this.clearChildren();
    this.entitesActors.clear();
    this.addEntities(entities);
}

And I tried to wrap the whole reset method inside a Gdx.app.postRunnable

//EntityCrew is my Group object which has the reset method
Gdx.app.postRunnable(() -> this.entityCrew.reset(level.getEntities()));

And I noticed that with this setup the first time too I can't see the actors of the group. They are in the group, they are drawn by the render thread but they are not displayed on screen and this thing is driving me mad.

1

1 Answers

1
votes

The first time reset is called (Map and group are empty) everything's fine, but the second time I call it (with Map and Group containing the entities of the first call) I got a cuncurrentModificationException from the removeEntity method.

This exception happens because when you're iterating through the Collection in the render() method one element in that collection is removed confusing the iterator on what it should do.

Luckily for us, LibGDX has a DelayedRemovalArray class that is made exactly for these kind of cases. It works like this:

  • Tell the DelayedRemovalArray you want to delete one or many of its elements
  • Put a flag on the elements you want to remove
  • Tell the DelayedRemovalArray you finished setting the flags
  • The DelayedRemovalArray waits for the iteration to finish and deletes the flagged elements
DelayedRemovalArray<Entity> array;
// Prepare to flag elements
array.begin();
// Flag some elements
array.removeIndex(index);
// Finished flagging elements
array.end();

From the LibGDX API:
DelayedRemovalArray is an array that queues removal during iteration until the iteration has completed.