0

如果要求太多,我很抱歉,但我现在太困惑了。我正在为我在 AS3 中的侄子制作这款非常简单的射击游戏。一切似乎都运行良好,除了一个非常烦人的错误,在游戏启动时每隔一秒或第三次就会弹出一个。

IT 是Error #1009: Cannot access a property or method of a null object reference.问题始终出parent.removeChild(this)在相关类(EnemyClassBulletClassMissileClass中的命令上。这发生在两种情况下:当调用checkFinishConditions方法 inMain并且需要删除 EnemyClass 实例时。因此,如果我收到 #1009 错误,这是否意味着该实例已被删除?第二种情况是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

有很多代码需要查看,但我看到的一个潜在问题是:

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

潜在的问题是您“假设”此循环的顺序是基于数组的实际索引顺序的顺序。您可能想在其中留下痕迹以验证实际发生的情况,因为我相信它们可能出现故障。

有关详细信息,请参阅此问题 - For-Each Loop AS3:方向是否有保证?

所以想象一下这样的场景,数组中的第 3 个项目是第一个,然后你在 0 索引处拼接项目。现在,数组中有一个项目已从显示列表中删除,但未从数组中删除。那么当你到达那个项目时会发生什么?由于父属性为空,您所描述的几乎都会发生,因为您已经从显示列表中删除了它。

解决这个问题的方法是做这样的事情:

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;                    
            }
        }

当你遍历一个数组并在循环索引处拼接一个项目时,你必须意识到数组的组成会发生什么。这是一个例子

假设enemy3因为碰撞需要拼接。给定您的代码,这就是发生的情况:

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.

因此,虽然这是一种解决方案,但这里要强调的要点是拼接后阵列组成的变化。

于 2013-10-20T01:57:22.923 回答
1

是的,你正在以一种奇怪的方式从数组中拼接你的对象。首先,您正在向前遍历数组并在循环中拼接。这可能会导致几个子弹在应该触发碰撞时不会触发碰撞,或者说不移动。看,如果你在 index 处为子弹运行循环i,一旦你调用bullets.splice(i,1);下一个要迭代的子弹在 position 处i,然后你增加i并且那个子弹保持未处理。

接下来,您有嵌套循环,并且在内部循环中,您正在从 OUTER 循环中删除一个对象。这意味着一旦你删除了外循环的对象,你的内循环现在就失效了,你必须抢先终止内循环。

        //loop through bullets
        for (var l:int = aBulletArray.length-1; l>=0; l--) {
            // first, traverse both arrays backwards
            //get the current missile
            var currentBullet:BulletClass = aBulletArray[l];
            //loop through enemies
            for (var k:int = aEnemyArray.length-1; k>=0; k--) {
                var currentEnemy:EnemyClass = aEnemyArray[k];                                       
                if (currentBullet.hitTestObject(currentEnemy)) {                        
                    currentBullet.destroyThis();
                    aBulletArray.splice(l, 1);                          
                    aDamageArray[k] -= 1;   
                    if (aDamageArray[k] < 1) {              
                        //create an explosion           
                        var thisExplode:ExplosionClass = new ExplosionClass(currentEnemy.x,currentEnemy.y);                     
                        addChild(thisExplode);                  
                        currentEnemy.deleteEnemy();
                        aEnemyArray.splice(k, 1);                           
                        aDamageArray.splice(k, 1);
                        scoreValueText += 1;                            
                    }
                    // and since we don't have "currentBullet" anymore, do this
                    break;
                }
            }
        }

修复所有其他通过您进行拼接的数组的迭代,就像我在这部分代码中所做的那样,您应该避免在这些循环中出现 1009 错误。

此外,您不应发布整个项目代码,而应仅发布相关部分,例如报告为引发错误的整个函数,并解释哪一行产生错误 - 它在错误的堆栈跟踪中以数字形式写入。

于 2013-10-20T05:48:43.533 回答