6

私は、ff を含む単純な AndEngine ゲームに取り組んでいます。スプライト

a.) 戦車 b.) 兵士 c.) 爆弾

ここに同様の質問があります: Android AndEngine: Simple sprite collision

ゲームの外観:

ここに画像の説明を入力

ただし、最初の問題を修正すると、別の問題が発生しました。

爆弾 (飛行機が現在いる場所にスポーンし、マウス クリックによってターゲットまたは床に到達するまで垂直に下降する) がターゲット (たとえば兵士) に命中すると、兵士のスプライトは切り離され、その後ろに血しぶきのスプライトを残す必要があります。 1秒間だけでなく、爆弾からの爆発スプライト。ただし、ゲーム フォースは indexOutOfBoundError を出して終了します。これはおそらく爆弾とそのターゲットの間のスプライト数の不一致であり、範囲外の配列エラーを引き起こしている可能性があることを理解していますが、logCat はまったく役に立ちません。

09-22 11:13:37.585: E/AndroidRuntime(735): FATAL EXCEPTION: UpdateThread
09-22 11:13:37.585: E/AndroidRuntime(735): java.lang.IndexOutOfBoundsException: Invalid  index 5, size is 5
09-22 11:13:37.585: E/AndroidRuntime(735):  at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
09-22 11:13:37.585: E/AndroidRuntime(735):  at java.util.ArrayList.get(ArrayList.java:304)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.entity.Entity.onManagedUpdate(Entity.java:1402)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.entity.Entity.onUpdate(Entity.java:1167)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.entity.Entity.onManagedUpdate(Entity.java:1402)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.entity.scene.Scene.onManagedUpdate(Scene.java:284)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.entity.Entity.onUpdate(Entity.java:1167)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.engine.Engine.onUpdateScene(Engine.java:591)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.engine.Engine.onUpdate(Engine.java:586)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.engine.Engine.onTickUpdate(Engine.java:548)
09-22 11:13:37.585: E/AndroidRuntime(735):  at org.andengine.engine.Engine$UpdateThread.run(Engine.java:820)

ここで見られるように、logCat は私のコードではなく、AndEngine 自体でエラーを出しています。おそらくそうではないでしょう。

onCreateScene Update Handler で実行される新しいコード (上記のリンクされた前の問題のヘルプに従って):

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

    int numBombs = bombGroup.getChildCount();
    int numTroops = troopsGroup.getChildCount();
    final ArrayList<Sprite> toBeDetached = new ArrayList<Sprite>();
    for (int i = 0; i < numBombs; i++) {
        Sprite s = (Sprite) bombGroup.getChildByIndex(i);
        for (int j = 0; j < numTroops; j++) {
            Sprite s2 = (Sprite) troopsGroup.getChildByIndex(j);

            if (s.collidesWith(s2)) {

                /*Sprite splat = createSplat();
                splat.setPosition(s.getX(), s.getY());
                getEngine().getScene().attachChild(splat);*/

                Sprite splode = createExplosion();
                splode.setPosition(s.getX(), s.getY());
                getEngine().getScene().attachChild(splode);

                // 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();
                Sprite splode = createExplosion();
                splode.setPosition(s.getX(), s.getY());
                getEngine().getScene().attachChild(splode);

            }
            toBeDetached.clear();
        }
    });

}

エラーが発生しないためには、スプラットまたは爆発のいずれかであることに気付きました。スプラットと爆発の両方が衝突時にシーンに取り込まれた場合、エラーが発生します。

また、爆弾が兵士に当たらない場合でも (ただし、床にぶつかると分離して爆発雲に置き換えられます)、同様のエラーが発生します。

私の createBomb 関数:

    public Sprite createBomb(float x, float y) {
    Sprite bombSprite = new Sprite(x, y, this.mBombTextureRegion,
            getVertexBufferObjectManager());

    MoveYModifier downModBomb = new MoveYModifier(1, 60, FLOOR);

    downModBomb.addModifierListener(new IModifierListener<IEntity>() {

        @Override
        public void onModifierStarted(IModifier<IEntity> pModifier,
                IEntity pItem) {

        }

        @Override
        public void onModifierFinished(IModifier<IEntity> pModifier,
                final IEntity pItem) {
             pItem.detachSelf();
             AnimatedSprite explodeSprite = createExplosion();
             explodeSprite.setPosition(pItem.getX(), FLOOR);
             getEngine().getScene().attachChild(explodeSprite);
        }
    });

    bombSprite.registerEntityModifier(downModBomb); // register action
    return bombSprite;
}

私の onCreateScene 爆弾関数と衝突 updateHandler:

    scene.setOnSceneTouchListener(new IOnSceneTouchListener() {

        @Override
        public boolean onSceneTouchEvent(Scene pScene,
                TouchEvent pSceneTouchEvent) {
            if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Sprite bomb = createBomb(f16Sprite.getX(),
                                f16Sprite.getY());
                        bombGroup.attachChild(bomb);
                    }
                });

                return true;
            }
            return false;
        }
    });

    // periodic checks
    scene.registerUpdateHandler(new IUpdateHandler() {

        @Override
        public void onUpdate(float pSecondsElapsed) {
            // checkTankCollision();
            // checkSoldierBackCollision();
            checkSoldierCollision();
        }

        @Override
        public void reset() {
        }
    });

私の createExplosion メソッド:

            public AnimatedSprite createExplosion() {
    AnimatedSprite boomSprite = new AnimatedSprite(0, 0,
            this.mExplodeTextureRegion, getVertexBufferObjectManager());

    DelayModifier delay = new DelayModifier(.3f); // delay in seconds, can
                                                    // take float numbers .5
                                                    // seconds
    delay.addModifierListener(new IModifierListener<IEntity>() {

        @Override
        public void onModifierStarted(IModifier<IEntity> pModifier,
                IEntity pItem) {
            ((AnimatedSprite) pItem).animate(new long[] { 100, 100, 100 }, // durations/frame
                    new int[] { 1, 2, 3 }, // which frames
                    true); // loop
        }

        @Override
        public void onModifierFinished(IModifier<IEntity> pModifier,
                final IEntity pItem) {
            ((AnimatedSprite) pItem).detachSelf();
        }
    });

    boomSprite.registerEntityModifier(delay); // register action
    return boomSprite;
}

これを解決するにはどうすればよいですか?ループ ロジックは、完全に私の強みというわけではありません。これを別の方法で実装する方法についてもオープンです。

更新: 衝突の結果がスプラットまたは爆発のいずれであっても、プレーヤーが爆弾を連発し続ければ (たとえば 4 ~ 5 回)、ゲーム全体の力が閉じられることに気付きました。

- はんだ/タンクのインスタンスを作成するたびに許容される爆撃回数があるようです。爆弾が兵士に命中するたびに、最初に爆発の作成をオフにしました (そのため、両方ではなく、ブラッドスプラットがその場所に残ります)。問題なく動作しますが、爆弾が 4 ~ 6 個を超えるとゲームが終了します。新しい兵士インスタンスがスポーンすると (つまり、古いものが画面から消えて切り離されると)、ゲーム フォースが終了する前にプレイヤーに 4 ~ 6 個の爆弾が与えられます。

4

3 に答える 3

4

この問題は、runOnUiThread を呼び出して UI スレッドに爆弾をアタッチし、更新スレッドで衝突をチェックしたことが原因である可能性があります。runOnUpdateThread 内に爆弾を追加してみてください。

一般に、物事を操作するために使用するスレッドについて一貫性を保つ必要があります。そうしないと、奇妙なバグが発生し、デバッグが困難になります。

余談ですが、UI スレッドはトーストを表示するのに最適です。次の例を参照してください。

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(GameActivity.this, "Hello!", Toast.LENGTH_SHORT).show();
    }
});
于 2012-09-24T12:21:32.270 に答える
1

これをデバッグするには、出力(おそらくログを介して)によって、実際に追加された数とを監視する必要があります。これは、追加されたbombGroup数とtroopsGroup一致している必要があります。getChildCount()また、iおよびjパラメータの値を出力してみてください。

大げさな推測のために、これを試してください:

for (int i = 0; i < toBeDetached.size(); i++) {

     toBeDetached.get(i).detachSelf();

  }
于 2012-09-24T11:15:52.787 に答える
1

JohnEye氏の助けを借りて、コードの問題を修正することができました。次のスニペットについて考えてみます。

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

    int numBombs = bombGroup.getChildCount();
    int numTroops = troopsGroup.getChildCount();
    final ArrayList<Sprite> toBeDetached = new ArrayList<Sprite>();
    for (int i = 0; i < numBombs; i++) {
        Sprite s = (Sprite) bombGroup.getChildByIndex(i);
        for (int j = 0; j < numTroops; j++) {
            Sprite s2 = (Sprite) troopsGroup.getChildByIndex(j);

            if (s.collidesWith(s2)) {

                Sprite splat = createSplat();
                splat.setPosition(s.getX(), s.getY());
                getEngine().getScene().attachChild(splat);

                Sprite splode = createExplosion();
                splode.setPosition(s.getX(), s.getY());
                explodeGroup.attachChild(splode);
                // getEngine().getScene().attachChild(splode);

                // 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();
                Sprite splat = createSplat();
                splat.setPosition(s.getX(), s.getY());
                getEngine().getScene().attachChild(splat);

                Sprite splode = createExplosion();
                splode.setPosition(s.getX(), s.getY());
                explodeGroup.attachChild(splode);
                // getEngine().getScene().attachChild(splode);

            }
            toBeDetached.clear();
        }
    });

}

すでに述べたように、衝突する2つのオブジェクト間のカウントの不一致が原因で、ゲームがクラッシュします。この状況は、JohnEye氏が指摘しているように、スプライトがUIスレッドで生成されたが、更新スレッドでは生成されなかった場合に発生します。さらに、私のcreateExplosion、createBomb、createSplat関数について考えてみましょう。

爆弾を作成する

    public Sprite createBomb(float x, float y) {
    Sprite bombSprite = new Sprite(x, y, this.mBombTextureRegion,
            getVertexBufferObjectManager());

    MoveYModifier downModBomb = new MoveYModifier(1, 60, FLOOR);

    downModBomb.addModifierListener(new IModifierListener<IEntity>() {

        @Override
        public void onModifierStarted(IModifier<IEntity> pModifier,
                IEntity pItem) {

        }

        @Override
        public void onModifierFinished(IModifier<IEntity> pModifier,
                final IEntity pItem) {
            runOnUpdateThread(new Runnable() {
                @Override
                public void run() {
                    pItem.detachSelf();
                }
            });
            AnimatedSprite explodeSprite = createExplosion();
            explodeSprite.setPosition(pItem.getX(), FLOOR);
            explodeGroup.attachChild(explodeSprite);
            // getEngine().getScene().attachChild(explodeGroup);
        }
    });
    bombSprite.registerEntityModifier(downModBomb);
    return bombSprite;
}

爆発を作成する

public AnimatedSprite createExplosion() {
    AnimatedSprite boomSprite = new AnimatedSprite(0, 0,
            this.mExplodeTextureRegion, getVertexBufferObjectManager());

    DelayModifier delay = new DelayModifier(.3f); // delay in seconds, can
                                                    // take float numbers .5
                                                    // seconds
    delay.addModifierListener(new IModifierListener<IEntity>() {

        @Override
        public void onModifierStarted(IModifier<IEntity> pModifier,
                IEntity pItem) {
            ((AnimatedSprite) pItem).animate(new long[] { 100, 100, 100 }, // durations/frame
                    new int[] { 1, 2, 3 }, // which frames
                    true); // loop
        }

        @Override
        public void onModifierFinished(IModifier<IEntity> pModifier,
                final IEntity pItem) {
            runOnUpdateThread(new Runnable() {
                @Override
                public void run() {
                    ((AnimatedSprite) pItem).detachSelf();
                }
            });
        }
    });

    boomSprite.registerEntityModifier(delay); // register action
    return boomSprite;
}

スプラットの作成

public Sprite createSplat() {
    Sprite splatSprite = new Sprite(0, 0, this.mSplatTextureRegion,
            getVertexBufferObjectManager());

    DelayModifier delay = new DelayModifier(.3f); // delay in seconds, can
                                                    // take float numbers .5
                                                    // seconds
    delay.addModifierListener(new IModifierListener<IEntity>() {

        @Override
        public void onModifierStarted(IModifier<IEntity> pModifier,
                IEntity pItem) {

        }

        @Override
        public void onModifierFinished(IModifier<IEntity> pModifier,
                final IEntity pItem) {
            runOnUpdateThread(new Runnable() {
                @Override
                public void run() {
                    pItem.detachSelf();
                }
            });
        }
    });

    splatSprite.registerEntityModifier(delay); // register action
    return splatSprite;
}

それらのすべてがrunOnUpdateスレッドで他のスプライトをデタッチ/生成することに注意してください。runOnUpdateクラスでこれらすべてのスプライトをデタッチ/生成しなかったため、以前のランスルーでゲームがクラッシュしました。

于 2012-09-24T15:50:51.217 に答える