【问题标题】:Trouble with addChild/removeChild and display list order in ActionScript3ActionScript3 中 addChild/removeChild 和显示列表顺序的问题
【发布时间】:2014-07-25 03:52:15
【问题描述】:

我正在做一个项目,其中包括一个湖符号,玩家可以将石头扔进湖中,这反过来会导致章鱼在每块石头击中湖的位置从湖中升起。

还有一个代表石头溅起的水花的符号,它会在石头击中之后,章鱼出现之前出现。

很可能同时屏幕上会有很多章鱼,需要在显示列表中排序,让应该出现在后面的章鱼排在后面。

这些符号的每个实例只应播放一次,然后将其删除。

我的代码使用了不同的添加/删除子方法以及我在各种教程和论坛的帮助下整理的 for 循环、条件和数组。

我遇到的问题是,当您快速连续单击湖两次或多次时,石头和飞溅符号没有被正确删除并且经常循环播放。

这是我正在使用的代码。有什么想法吗?

var stone:Stone;
var stoneSplash:StoneSplash;
var octopus1:Octopus1;
var octopus2:Octopus2;
var whichOctopus:Array = [addOctopus1, addOctopus2];
var octopusScale:Number;
var octopusContainer:MovieClip = new MovieClip;

lake.lakeHitArea.addEventListener(MouseEvent.CLICK, onClickLake);

//Add octopusContainer to the stage's display list just above the Lake
addChildAt(octopusContainer,getChildIndex(lake) + 1);
octopusContainer.x = 0;
octopusContainer.y = 0;

function onClickLake(e:MouseEvent):void
{
    trace("CLICK");
    throwStone(mouseX, mouseY);
}
function throwStone(stonePositionX:int, stonePositionY:int)
{
    stone = new Stone();
    stone.x = stonePositionX;
    stone.y = stonePositionY;
    addChild(stone);
    addEventListener(Event.ENTER_FRAME, removeStone);
}
function removeStone(e:Event):void
{
    var count:int = numChildren;
    var children:Array = [count];

    //load all the children of the component into an Array
    for (var i:int=0; i<count/* -1*/; i++)
    {
        children[i] = getChildAt(i/* + 1*/);
    }

    for (i=0; i<count/* - 1*/; i++)
    {
        if (children[i] is Stone)
        {
            if (children[i].currentFrameLabel == "Splash")
            {
                stoneSplash = new StoneSplash();
                octopusContainer.addChild(stoneSplash);
                stoneSplash.x = children[i].x;
                stoneSplash.y = children[i].y;
            }
            if (children[i].currentFrameLabel == "end")
            {
                octopusContainer.removeChild(stoneSplash);
                var positionX:int = children[i].x;
                var positionY:int = children[i].y;
                addOctopus(positionX, positionY);
                removeChild(children[i]);
            }
        }
    } 
}
function addOctopus(positionX, positionY)
{
    var o:int = Math.round(randomNumber(0,1));
    whichOctopus[o](positionX, positionY);   
    reorderDisplayList();
    addEventListener(Event.ENTER_FRAME, removeOctopus);
}
function addOctopus1(positionX: int, positionY:int):void
{
//  if (whichOctopus1 == true)
//  {
//      var octopus:* = octopus1_1;
//  }
//  else
//  {
//      octopus = octopus1_2;
//  }
    octopus1 = new Octopus1();
    var octopus:DisplayObject = octopus1;
    octopusContainer.addChild(octopus);
    octopus.x = positionX;
    octopus.y = positionY;
    octopusScale = randomNumber(0.5,0.85);
    octopus.scaleX = octopusScale;
    octopus.scaleY = octopusScale;
    trace("children = " + octopusContainer.numChildren);
    testPosition(octopus);
}
function addOctopus2(positionX: int, positionY:int):void
{
//  if (whichOctopus2 == true)
//  {
//      var octopus:* = octopus2_1;
//  }
//  else
//  {
//      octopus = octopus2_2;
//  }
    octopus2 = new Octopus2();
    var octopus:DisplayObject = octopus2;
    octopusContainer.addChild(octopus);
    octopus.x = positionX;
    octopus.y = positionY;
    octopusScale = randomNumber(0.25,0.5);
    octopus.scaleX = octopusScale;
    octopus.scaleY = octopusScale;
    trace("children = " + octopusContainer.numChildren);
    testPosition(octopus);
}
function testPosition(octopus:Object):void
{
    trace(octopus)
    for (var i:int = 0; i < 200; i++)
    {
        if (lake.hitTestPoint(octopus.x + octopus.hitTestBox1.x * octopus.scaleX,octopus.y + octopus.hitTestBox1.y * octopus.scaleY,true))
        {
            break;
        }
        else
        {
            octopus.x++;
        }
    }
    for (i = 0; i < 100; i++)
    {
        if (lake.hitTestPoint(octopus.x + octopus.hitTestBox2.x * octopus.scaleX,octopus.y + octopus.hitTestBox2.y * octopus.scaleY,true))
        {
            break;
        }
        else
        {
            octopus.y--;
        }
    }
    for (i = 0; i < 200; i++)
    {
        if (lake.hitTestPoint(octopus.x + octopus.hitTestBox3.x * octopus.scaleX,octopus.y + octopus.hitTestBox3.y * octopus.scaleY,true))
        {
            break;
        }
        else
        {
            trace(i);
            octopus.x--;
        }
    }
    for (i = 0; i < 100; i++)
    {
        if (lake.hitTestPoint(octopus.x + octopus.hitTestBox1.x * octopus.scaleX,octopus.y + octopus.hitTestBox1.y * octopus.scaleY,true))
        {
            break;
        }
        else
        {
            octopus.y--;
            trace(i);
        }
    }
}
function randomNumber(min:Number, max:Number):Number
{
    return Math.random() * (max - min) + min;
}
function reorderDisplayList():void
{
    //the number of children in our component
    var count:int = octopusContainer.numChildren;
    var children:Array = [count];

    //load all the children of the component into an Array
    for (var i:int=0; i<count; i++)
    {
        children[i] = octopusContainer.getChildAt(i);
    }

    //sort the Array children based on their 'y' property
    children.sortOn("y", Array.NUMERIC);
    //re-add the children to the component ;
    //in the order of the sorted Array we just created.
    //When we add the children using 'addChild' it will 
    //be added at the top of the component's displaylist
    //and will automatically be removed from its original position.
    for (i=0; i<count/* - 1*/; i++)
    {
        if (children[i] is Octopus1 || children[i] is Octopus2)
        {
//          trace("child = " + children[i] + " at i: " + i);
            octopusContainer.removeChild(children[i]);
            octopusContainer.addChild(children[i]);
        }
    } 
}
function removeOctopus(e:Event):void
{
    var count:int = octopusContainer.numChildren;
    var children:Array = [count];

    //load all the children of the component into an Array
    for (var i:int=0; i<count/* -1*/; i++)
    {
        children[i] = octopusContainer.getChildAt(i/* + 1*/);
    }

    for (i=0; i<count/* - 1*/; i++)
    {
        if (children[i] is Octopus1 || children[i] is Octopus2)
        {
            trace(i);
            trace("Is an octopus");
            if (children[i].currentFrame >= 202)
            {
                octopusContainer.removeChild(children[i]);
            }
        }
    } 
}

如果有任何建议可以帮助我克服这个障碍并继续我的项目,我将不胜感激。

提前谢谢你。

克里斯·柯林斯。

【问题讨论】:

  • 乍一看,您每次点击都会添加一个框架侦听器,而不必在下次点击之前删除该侦听器:addEventListener(Event.ENTER_FRAME, removeStone); - 您的大部分问题可能都源于此

标签: actionscript-3 flash


【解决方案1】:

您的问题(或至少其中一个问题)是您的代码只会删除最近的StoneSplash。因此,如果您在启动动画和结束动画之间单击多次,则只会删除最后一次单击的动画。

这是因为您使用全局变量 (stoneSplash) 来引用启动画面,并且它会被新的变量覆盖。您需要在石头本身上添加一个飞溅参考,或者创建一个字典以便您知道哪个飞溅与哪个石头搭配。

这是一种方法:

if (children[i].currentFrameLabel == "Splash")
        {
            stoneSplash = new StoneSplash(); 
            MovieClop(children[i]).stoneSplash = stoneSplash; //add a reference the splash on the stone itself

然后,而不是octopusContainer.removeChild(stoneSplash); 做:

octopusContainer.removeChild(MovieClop(children[i]).stoneSplash);

这样你就可以消除与这块石头一起出现的正确飞溅。


这是一种更简洁的方式来构建它,而不是使用输入帧处理程序:

  1. 在您的 Stone 课程时间轴上,将以下代码分别放在您的 Splash 和 End 帧上:

    启动帧:this.dispatchEvent(new Event("Splash"));

    结束帧:this.dispatchEvent(new Event("End"));

  2. 在创建新石头实例时监听这些事件:

    stone = new Stone();
    stone.x = stonePositionX;
    stone.y = stonePositionY;
    stone.addEventListener("Splash", splashHandler,false,0,true);
    stone.addEventListener("End",removeStone,false,0,true);
    addChild(stone);
    
  3. 适当地响应这些事件:

    function splashHandler(e:Event):void {
        var stone:Stone = e.currentTarget as Stone;
        stoneSplash = new StoneSplash();
    
        //you need a reference to the splash from the stone class - it would be best to create a class file and add a public property called splashObj and then just use stone.splashObj = new StoneSplash();
        MovieClip(stone).stoneSplash = stoneSplash;  //so on the end event we can read this var to remove stoneSplash
        octopusContainer.addChild(stoneSplash);
        stoneSplash.x = stone.x;
        stoneSplash.y = stone.y;
    }  
    
    function removeStone(e:Event):void {
        var stone:Stone = e.currentTarget as Stone;
        octopusContainer.removeChild(MovieClip(stone).stoneSplash);
        addOctopus(stone.x, stone.y);
        removeChild(stone);
    }  
    

【讨论】:

  • 嗨。感谢您的帮助。当您说将代码放在 Splash 和 End 帧时,您是指在符号编辑器时间轴上,还是使用一些 as3 代码来访问帧?我不想在符号编辑器的符号时间线上直接放任何代码。
  • 我的意思是在具有“Splash”标签的同一帧上的影片剪辑时间轴上,将代码放在该帧上。如果使用需要与代码同步的时间轴动画,这是迄今为止最优雅的方式。
  • 我尝试了您在答案的第一部分中提出的建议,它按我的意愿工作。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多