【问题标题】:safely remove a child with enterframe running安全移除运行 enterframe 的孩子
【发布时间】:2011-10-21 20:06:21
【问题描述】:

每当我尝试在运行 enterframe 的情况下删除对象/子对象时,我总是会收到空引用错误。 在我的特殊情况下,设置是战场包含很多机器人:

  1. 子(机器人)dispatchEvent 被销毁
  2. 父容器接收到事件并开始通过 removeChild 移除子容器,并将子容器从机器人数组中移除。
  3. 在 enterframe 上,在循环移动机器人的过程中,有时我会得到空引用,所以我必须调用 if (robots[i] == null) continue;

如果机器人在我的整个框架上都是空的,你如何安全地移除孩子而不洒水?

我的一个想法是在 enterframe 中列出要删除的机器人,检查是否有要删除的机器人,如果有,则在此处进行删除,而不是在机器人爆炸事件上进行回调。

【问题讨论】:

  • 你能发布代码吗?你如何遍历你的机器人收藏?你是保留一个数组还是循环显示列表中的子项?
  • 您如何遍历您的机器人集合?它只是一个机器人数组你是保留一个数组还是循环显示列表中的孩子?我保留数组是因为在 Battlefield 容器中还有其他不是 Robot 的元素。我稍后会发布代码,我可能应该提到这是在 Haxe 中但是,我在其他基于 Flash 的框架中遇到这个问题,例如 Corona SDK(使用 lua)
  • 您创建名为 Robots 的机器人管理器类来管理所有机器人类实例。保持模块化并以良好的 OOP 方式封装。
  • @The_asMan 并不能解决每当有事件被派发时仍然会遇到空引用的问题
  • 如果管理器处理所有机器人实例,则不会。到那时,它变得微不足道。 enterFrame 循环永远不需要知道机器人是否为空,它只需要调用管理器类中的函数

标签: flash actionscript-3 actionscript haxe


【解决方案1】:

我通常会做的两件事:

1) 在要更新的对象中有一个active bool。当您调用 destroy() 函数或任何要清理的函数时,请将 active 设置为 false。在update() 函数中,在开始时进行检查。如果activefalse,退出。

2) 当您想删除对象时,将removeFromUpdate 属性设置为true。在您的 UpdateManager(或在您的对象上调用 update() 的任何一个)中执行以下操作:

private function _update():void
{
    // update our objects
    var remove:Boolean = false;
    var len:int = this.m_objects.length;
    for( var i:int = 0; i < len; i++ )
    {
        this.m_objects[i].update();
        if( this.m_objects[i].removeFromUpdate )
            remove = true;
    }

    // if we don't have anything to remove, quit
    if( !remove )
        return;

    // we have something to remove, so traverse the array
    // backwards (so we don't have index problems)
    for( i = len - 1; i >= 0; i-- )
    {
        if( this.m_objects[i].removeFromUpdate )
        {
            // you can optionally call the object's destroy() function
            // here

            // splice the array
            this.m_objects.splice( i, 1 );
        }
    }
}

这对我来说非常有用。如果要保存参数,则可以选择让对象的 update() 函数返回 true,如果应该删除它

【讨论】:

  • 我曾想过使用标志,但感觉很脏,因为这意味着所有移动的对象都需要拥有它,并且更新必须检查它。这是避免发生此类问题的常见做法吗?还是有更优雅的方式?
  • 您的问题是对象可能在更新期间被删除。仅当您在列表中更新大量对象时才真正常见。我认为我从来没有在该对象更新的过程中删除过一个对象,除非它被特别调用。这几乎是我见过的大多数引擎的做法(很可能还有另一种解决方案,这个是最简单的)
  • 拥有,例如,active 布尔值(您在调用 update() 之前检查)还可以让您在游戏中做其他事情,即更容易暂停整个组或特定对象.这很常见
【解决方案2】:

好吧,Array 实际上有一个remove 方法。您可以使用它来永久移除机器人。该方法还报告了它的成功,所以你的代码看起来像:

if (robotsArray.remove(explodedRobot)) 
    robotsLayer.removeChild(explodedRobot)

但是请注意,Array 上的 remove 调用不应在迭代时发生,否则您肯定会遇到奇怪的行为。

【讨论】:

    【解决方案3】:

    我还不能发布 cmets,所以必须这样做。

    我能想到的两件事: 你说你从机器人列表中删除了孩子。因此,您在列表中遇到空值似乎很奇怪;除非删除实现有错误?

    是否有可能在 ENTER_FRAME 内通过机器人时,机器人实例被删除?如果是这样,如果您从最后一个索引开始遍历列表可能会有所帮助。如果一个实例被删除,它不会改变较低索引的项目。

    类似:

    for(var index: int = list.length; index--; ) doSomething(list[index]);
    

    【讨论】:

    • 嗯,从结尾删除听起来很有趣,我回家后会试试。所以发生的情况是,在循环机器人时,如果调度事件,它将引入竞争条件,在该索引处的机器人被删除,因此在访问其索引时返回 null
    猜你喜欢
    • 2013-10-11
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 2015-08-04
    • 2017-08-19
    • 1970-01-01
    相关资源
    最近更新 更多