Chris
Chris

Reputation: 29

Safely remove a sprite using Andengine

I am creating lots of ball sprites which bounce around the screen randomly. When touched, I want to the ball to be removed from the scene. (If more than one ball occupies the same space, that will be removed as well at the moment).

I realise the scene.detachChild must be run on the runOnUpdateThread, so within my Ball sprite subclass, I detachChild on touch by overriding onAreaTouched:

        @Override
    public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY)
    {
        ((BaseGameActivity) thisAct).runOnUpdateThread(new Runnable() {
            @Override
            public void run() {
                /* Now it is save to remove the entity! */


                    //scene.unregisterTouchArea(Ball.this);
                    scene.detachChild(Ball.this);

            }
        });
        return false;
    }

I have to pass in the main Activity to the constructor of the ball sprite and then remove the ball from the main Activities scene.

If I uncomment the scene.unregisterTouchArea(Ball.this) line, to stop the sprites acting on touches (this doesn't affect the removal, but thought it better to stop the touch being processed), I will receive the indexOutOfBoundsException that I think is related to not detaching sprites from within a runOnUpdateThread.

**java.lang.IndexOutOfBoundsException: Invalid index 90, size is 90
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
at java.util.ArrayList.get(ArrayList.java:311)
at org.anddev.andengine.entity.scene.Scene.onSceneTouchEvent(Scene.java:320)**

Two questions:

  1. Am I correct to process the removal of the sprite within the ball subclass, using the override onAreaTouched, or should I somehow take the removal back into the main activity (do I need a subclass in the first place)?

  2. Any idea why I get the IndexOutOfBoundsException if I include the unregisterTouchArea?

Thanks for any help.

Upvotes: 3

Views: 4755

Answers (2)

Pramod
Pramod

Reputation: 1133

/*
         * Removing entities can only be done safely on the UpdateThread. Doing
         * it while updating/drawing can cause an exception with a suddenly
         * missing entity. Alternatively, there is a possibility to run the
         * TouchEvents on the UpdateThread by default, by doing:
         * engineOptions.getTouchOptions().setRunOnUpdateThread(true); when
         * creating the Engine in onLoadEngine();
         */
        MainActivity.this.runOnUpdateThread(new Runnable() {
            @Override
            public void run() {
                /* Now it is safe to remove the entity! */
                mScene.detachChild(face);
            }
        });

Upvotes: 0

fyr
fyr

Reputation: 20869

Never do removal in the TouchListener. You should stick with a IUpdateHandler.

1.) It is not necessary to subclass you might do the removal everywhere where you have access to a scene.

2.) The IndexOutOfBoundException happens because you do the removal in the TouchListener. Probably some method adds new things to the scene while you are removing the sprite. Putting the removal in an UpdateHandler solves this.

Upvotes: 3

Related Questions