空检查后的AS3空对象引用

时间:2015-04-23 22:33:25

标签: actionscript-3 null runtime-error

我一直在寻找解决方案一段时间,但找不到任何东西。

这个问题很奇怪,所以我会给出一些背景知识。我正在进行塔防游戏,并且在对敌人实施状态效果时(减速,着火等)我遇到了一个奇怪的问题。当塔用射弹杀死敌人时一切都很好,但由于某种原因当敌人被状态效应杀死时,我得到一个空对象引用错误(两者都用方法“Enemy.damage(damage:int)”处理“)。关于这一点的奇怪之处在于状态效果存储在一个仅在3个点中引用的数组中。在ENTER_FRAME事件中(一个ENTER_FRAME事件用于处理游戏中的每个方面),在构造函数(status = new Array();)和destroy方法中。

一个奇怪的部分是,如果“status”变量为null,则destroy方法中的其他变量会在很久以前给我错误。真正奇怪的部分是我在得到错误之前就进行了空检查。

这是我收到错误的地方:

        //STATUS EFFECTS
        if (status == null) {
            trace("test");
        }
        if (status != null && status.length != 0) {
            for (var i:int = 0; i < status.length; i++) {//LINE 101
                status[i].applyEffect();
            }
        }

这是错误:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at game.enemies::Enemy/update()[C:\flash\game\enemies\Enemy.as:101]

“test”永远不会打印出来,即使使用空检查我仍然会收到错误

编辑:这是敌人类:http://pastebin.com/LAyMMB1P

StatusEffect&amp; FireEffect类:http://pastebin.com/GTGDmjt8(我只能发布2个链接,每个链接都在自己的文件中)

状态变量在StatusEffect.destroy()和此处引用:

override public function onHit(e:Enemy) {

        if (upgradeLevel >= 1) {
            var onFire = false;
            for (var i:int = 0; i < e.status.length; i++) {
                if (e.status[i].name_ == "fire") {
                    onFire = true;
                }
            }
            if (!onFire) {
                e.status.push(new FireEffect(e));
            }
        }
        if (upgradeLevel >= 2) {
            if (enemiesHit.indexOf(e) == -1) {
                enemiesHit.push(e);
                e.damage(1);
            }
            if (upgradeLevel == 2 && enemiesHit.length == 2) {
                destroy();
            }
        } else {
            e.damage(super.damage);
            destroy();
            return;
        }
    }

1 个答案:

答案 0 :(得分:1)

这种情况正在发生,因为你可能会在第101行的for循环中间摧毁你的敌人。

销毁敌人会将状态数组设置为null,因此在下次迭代时检查i < status.length,状态是否为空,从而导致错误。

为了说明,单步执行代码,让我们假设第101行status数组中有两个项目:

  • 第一个循环,索引为0的项目会在其上调用applyEffect()

  • applyEffect()内{li>

    可以调用specificApplication()方法。

  • specificApplication()内调用super.enemy.damage(1);方法。

  • enemy.damage()方法中,您可以调用enemy.destroy方法

  • enemy.destroy方法中,您设置了status = null

  • 现在来自第101行的循环循环,但状态现在为空。

如果敌人被摧毁,可以通过打破你的循环来解决这个问题。

for (var i:int = 0; i < status.length; i++) {//LINE 101
    status[i].applyEffect();
    if(!status) break;
}

您还有一些拼接问题:

enemy.status.splice(enemy.status.indexOf(this), 1);

虽然它上面的那一行没有任何问题,但让我们逐步完成代码:

Enemy类的第101行

for (var i:int = 0; i < status.length; i++) {
  • 循环遍历状态数组。对于此示例,我们假设您在数组中有两个项目。

  • 项目A位于0位置。项目B位于数组中的1位置。

  • 第一个循环,i的值为0

  • 您致电status[i].applyEffect()i == 0,即项目A.

  • applyEffect内,请说明您的情况已经满足,因此请致电destroyStatusEffect班级)

  • StatusEffect.destroy()方法中,您拼接status数组。

  • 现在status只有一个项目B项,而项目B现在的索引为0(而不是1)。

  • 你的循环循环,现在是i == 1

  • 但是,索引1处不再有任何项目,因此循环退出,跳过项目B.

要解决这个问题,请反向迭代,然后当你拼接时你的指数不会出现问题:

var i:int = status.length
while(i--){
    status[i].applyEffect();
}

顺便说一句,如果您使用var status:Vector.<StatusEffect>而不是var status:Array,那将更加清晰。您可以通过这种方式检查编译时间并输入安全性。