Search code examples
androidcollision-detectionspriteandenginegame-physics

Android AndEngine: Simple sprite collision


I am new to AndEngine game development (or game development in general) and I am working on a very simple game. The setting is that I have 4 main sprites in the game:

a.) Fighter Plane b.) Tank c.) Foot soldiers d.) Bomb

The game is in a current infinite loop. The fighter plane comes out from the left, zooms across the screen and comes out the right again continuously every second. The Tank comes out from the left side of the screen, makes its way to the middle of the screen, drops off some foot soldiers who make their way to the right side of the screen. The tank will then face left and go back to where it came from.

The player can tap the screen to launch a bomb that goes straight downwards. When it hits either the tank or the soldiers, the bomb explodes (leaving an explosion sprite) and the bomb, as well as the object it collides with (tank or soldier) detaches from the scene.

My dilemma is that, I can't seem to solve the logic involving the collision. I mean sure, I get the functions, but I'm stumped logic wise. Here is a snapshot of the game itself:

enter image description here

Here is my snippet (this function is called from the onCreateScene update handler:

    protected void checkTankCollision() {
    // TODO Auto-generated method stub

    int numCompares = bombGroup.getChildCount();
    for (int i = 0; i < numCompares; i++) {
        Sprite s = (Sprite) bombGroup.getChildByIndex(i);
        for (int j = 0; j < numCompares; j++) {
            Sprite s2 = (Sprite) tankGroup.getChildByIndex(j);
            if (s.collidesWith(s2)) {
                // boom
                AnimatedSprite boom = createExplosion();
                boom.setPosition(s.getX(), s.getY());
                getEngine().getScene().attachChild(boom);

                // WARNING: cannot detach from the list
                // while looping through the list
                final Sprite a = s;
                final Sprite b = s2;

                // this will do the action after the scene is done updating
                getEngine().getScene().postRunnable(new Runnable() {

                    @Override
                    public void run() {
                        a.detachSelf();
                        b.detachSelf();
                    }
                });
            }
        }
    }

}

The game force closes after some bomb launches. It gives an indexOutOfBoundsException error.

Here's the logCat:

    09-22 00:12:14.565: E/AndroidRuntime(924): FATAL EXCEPTION: UpdateThread
    09-22 00:12:14.565: E/AndroidRuntime(924): java.lang.IndexOutOfBoundsException:  Invalid index 1, size is 1
    09-22 00:12:14.565: E/AndroidRuntime(924):  at  java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at java.util.ArrayList.get(ArrayList.java:304)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at  org.andengine.entity.Entity.getChildByIndex(Entity.java:612)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at com.cs119.bombthetank2.BombTankActivity.checkTankCollision(BombTankActivity.java:660)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at com.cs119.bombthetank2.BombTankActivity$4.onUpdate(BombTankActivity.java:194)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.engine.handler.UpdateHandlerList.onUpdate(UpdateHandlerList.java:47)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.entity.Entity.onManagedUpdate(Entity.java:1395)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.entity.scene.Scene.onManagedUpdate(Scene.java:284)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.entity.Entity.onUpdate(Entity.java:1167)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.engine.Engine.onUpdateScene(Engine.java:591)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.engine.Engine.onUpdate(Engine.java:586)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.engine.Engine.onTickUpdate(Engine.java:548)
    09-22 00:12:14.565: E/AndroidRuntime(924):  at org.andengine.engine.Engine$UpdateThread.run(Engine.java:820)

The Entity and Scene activities are part of the AndEngine, and there's really no way there could be an error there. BombTheTank2 is the name of my activity, so yeah, the error is there.


Solution

  • You seem to be detaching the Sprites before you stop iterating through the list of children. Let's do it the clean way. Try this:

    protected void checkTankCollision() {
        int numCompares = bombGroup.getChildCount();
        final ArrayList<Sprite> toBeDetached = new ArrayList<Sprite>();
        for (int i = 0; i < numCompares; i++) {
            Sprite s = (Sprite) bombGroup.getChildByIndex(i);
            for (int j = 0; j < numCompares; j++) {
                Sprite s2 = (Sprite) tankGroup.getChildByIndex(j);
                if (s.collidesWith(s2)) {
                    // boom
                    AnimatedSprite boom = createExplosion();
                    boom.setPosition(s.getX(), s.getY());
                    getEngine().getScene().attachChild(boom);
    
                    // WARNING: cannot detach from the list
                    // while looping through the list
                    toBeDetached.add(s);
                    toBeDetached.add(s2);
    
                }
            }
        }
        runOnUpdateThread(new Runnable() {
            @Override
            public void run() {
                for (Sprite s : toBeDetached) {
                    s.detachSelf();
                }
                toBeDetached.clear();
            }
        });
    }
    

    EDIT: The actual problem was somewhere else - Erasmus accidentally iterated over the Tank group the same number of times as over the Bomb group. The solution was to check the number of tanks and stop iterating sooner.

    I personally always use For-Each loops unless I really need to know the index, it saved me a lot of headaches :-)