0

求めすぎて申し訳ありませんが、今では混乱しすぎています。私は AS3 で甥のためにこの本当にシンプルなシューティング ゲームを作っています。ゲームが起動されるたびに 2 回または 3 回ポップアップし続ける 1 つの本当に厄介なエラーを除いて、すべて正常に動作しているようです。

問題はError #1009: Cannot access a property or method of a null object reference.常にparent.removeChild(this)、関連するクラス ( EnemyClassBulletClassまたはMissileClass) のコマンドにあります。これは 2 つのケースで発生します。checkFinishConditionsメソッド inMainが呼び出され、EnemyClass インスタンスを削除する必要がある場合です。#1009 エラーが発生した場合、これはインスタンスが既に削除されていることを意味しますか? 2 番目の状況は、がクラスinst.hitTestObject(enemyInstance)でチェックインされたときです。Mainこれは、EnemyClass インスタンスが何らかの形で既に削除されているということですか? 正直なところ、私はここで完全に迷っています。

private function checkCollision():void 
        {
            //loop through missiles
            for (var i:int = 0; i < aMissileArray.length; i++) {
                //get the current missile
                var currentMissile:missileClass = aMissileArray[i];
                //loop through enemies
                for (var j:int = 0; j < aEnemyArray.length; j++) {
                    var thisEnemy:EnemyClass = aEnemyArray[j];                                      
                    if (currentMissile.hitTestObject(thisEnemy)) {                          
                        var thisExplode:ExplosionClass = new ExplosionClass(thisEnemy.x,thisEnemy.y);                       
                        addChild(thisExplode);
                        currentMissile.destroyThis();
                        aMissileArray.splice(i,1);
                        thisEnemy.deleteEnemy();
                        aEnemyArray.splice(j, 1);                       
                        aDamageArray.splice(j, 1);  
                        scoreValueText += 1;    
                        j--;
                        i--;
                    }
                    //break;
                }
            }
            //loop through bullets
            for (var l:int = 0; l < aBulletArray.length; l++) {
                //get the current missile
                var currentBullet:BulletClass = aBulletArray[l];
                //loop through enemies
                for (var k:int = 0; k < aEnemyArray.length; k++) {
                    var currentEnemy:EnemyClass = aEnemyArray[k];                                       
                    if (currentBullet.hitTestObject(currentEnemy)) {                        
                        currentBullet.destroyThis();
                        aBulletArray.splice(l, 1);                          
                        aDamageArray[k] -= 1;   
                        l--;
                        if (aDamageArray[k] < 1) {              
                            //create an explosion           
                            var thisBulletExplode:ExplosionClass = new ExplosionClass(currentEnemy.x,currentEnemy.y);                       
                            addChild(thisBulletExplode);                    
                            currentEnemy.deleteEnemy();
                            aEnemyArray.splice(k, 1);                           
                            aDamageArray.splice(k, 1);
                            scoreValueText += 1;    
                            k--;

                        }
                        break;
                    }
                }

            }

        }
4

2 に答える 2

1

確認すべきコードはたくさんありますが、潜在的な問題の 1 つは次のとおりです。

        for each(var currentDieEnemy:EnemyClass in aEnemyArray) {                                                                               
            aEnemyArray.splice(0, 1);
            currentDieEnemy.deleteEnemy();                                  
        }  

潜在的な問題は、このループの順序が配列の実際のインデックス順序に基づいて連続していると「想定」していることです。そこにトレースを貼り付けて、実際に起こっていることを確認することをお勧めします。それらが故障している可能性があると私は信じているからです。

詳細については、この質問を参照してください -- For-Each ループ AS3: 方向は保証されていますか?

したがって、配列の 3 番目の項目が最初で、その項目を 0 インデックスでスプライスするシナリオを想像してください。これで、表示リストからは削除されたが、配列からは削除されなかった項目が配列内にあります。では、そのアイテムに到達するとどうなりますか? 表示リストからすでに削除しているため、親プロパティが null であるため、説明していることのほとんどが発生します。

それを修正する方法は、次のようなことです:

while (aEnemyArray.length > 0)
{
   var currentDieEnemy:EnemyClass = aEnemyArray[0];
   currentDieEnemy.deleteEnemy();
   aEnemyArray.splice(0,1);
}

このコード ブロックに別の問題が見つかりました。

        for (var j:int = 0; j < aEnemyArray.length; j++) {
            var thisEnemy:EnemyClass = aEnemyArray[j];                                      
            if (currentMissile.hitTestObject(thisEnemy)) {                          
                var thisExplode:ExplosionClass = new ExplosionClass(thisEnemy.x,thisEnemy.y);                       
                addChild(thisExplode);
                currentMissile.destroyThis();
                aMissileArray.splice(i,1);
                thisEnemy.deleteEnemy();
                aEnemyArray.splice(j, 1); // now array composition is different.                       
                aDamageArray.splice(j, 1);  
                scoreValueText += 1;                    
            }
        }

配列をループし、ループ インデックスで項目をスプライスする場合、配列の構成に何が起こるかを理解する必要があります。これが例です

衝突のために敵 3 をスプライスする必要があるとします。あなたのコードを考えると、これが起こります:

Before (j == 2)
(0) enemy1
(1) enemy2
(2) enemy3
(3) enemy4
(4) enemy5

AFTER
(0) enemy1
(1) enemy2
(2) enemy4
(3) enemy5

したがって、ループが続くと、j がインクリメントされて 3 に等しくなります。

その結果、配列の構成がスプライスによって作成された穴を埋めるために崩壊し、ループ インデックス変数を調整しなかったため、enemy4 は評価されません。

したがって、その状況でできることは、次のようにブロックの最後でループ インデックス変数を単純にデクリメントすることです。

 aEnemyArray.splice(j, 1); // now array composition is different.                       
 aDamageArray.splice(j, 1);  
 scoreValueText += 1;   
 j--;   // decrement loop index variable.

したがって、これは 1 つの解決策ですが、ここで取り上げる主なポイントは、スプライス後のアレイの構成の変化です。

于 2013-10-20T01:57:22.923 に答える