Android AndEngine:簡單的精靈碰撞 (Android AndEngine: Simple sprite collision)


問題描述

Android AndEngine:簡單的精靈碰撞 (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:

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.


參考解法

方法 1:

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 :-)

方法 2:

I think you need to do the "detach" on the UpdateThread, so instead of this

            getEngine().getScene().postRunnable(new Runnable() {

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

try this

runOnUpdateThread(new Runnable() {

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

every time you detach something, you should reduce your numCompares value, Once you detach something the array that holds those entities is now smaller. Since you are pulling the array length at the beginning, you are eventually running past the end of the array - thus your IndexOutOfBounds error. The detaching still needs to be run on the UpdateThread.

(by ErasmusJohnEyejmroyalty)

參考文件

  1. Android AndEngine: Simple sprite collision (CC BY-SA 3.0/4.0)

#game-physics #andengine #Android #collision-detection #sprite






相關問題

Android AndEngine:簡單的精靈碰撞 (Android AndEngine: Simple sprite collision)

Box2D - 收集硬幣 (Box2D - collect a coin)

LibGDX - 只有可拖動的運動 (LibGDX - only draggable movement)

Swift 2 中的遊戲 - “touchesBegan”? (Game in Swift 2 - "touchesBegan"?)

SKCameraNode 跟不上移動節點 (SKCameraNode doesn't keep up with moving node)

2D 平台遊戲:為什麼讓物理依賴於幀率? (2D platformers: why make the physics dependent on the framerate?)

基於脈衝的物理 - 在輕物體上堆疊重物體 (Impulse based physics - Stacking heavy object on light object)

建造一堵提高速度統一的牆 (Make a wall that boost speed unity)

Unity Golf 遊戲物理和運動控制器 (Unity Golf game physics and movement controller)

在 2D 汽車遊戲中模擬下壓力 (Simulate Downforce in a 2D Car Game)

向前和橫向球員運動 (Forward and Sideways Player movement)

如何在 Unity 中進行沒有物理的碰撞檢測? (How to have collision detection without physics in Unity?)







留言討論