views:

604

answers:

6

I have a simple function that, when you click on a button, adds a movie clip to the stage in a random x and y position. The issue I am having is that the new movie clips eventually cover up the button. I tried to change the z-index of the newly created mc to be below the z-index of the button, but that doesn't solve the problem. How does one stop the new mc's from covering up an element that already exists.

    friends1_btn.addEventListener(MouseEvent.CLICK, friendMaker);

function friendMaker(evt:MouseEvent):void {
    var newFriend:Teddy = new Teddy();
    newFriend.x = Math.random()*stage.width;
    newFriend.y = Math.random()*stage.height;
    newFriend.z = 0;
    stage.addChild(newFriend);
}
A: 

MovieClip doesn't have a propery named 'z' in AS3 (reference)

You should read up on the new display list model for AS3. It should help you understand how objects can be layered on top of one another.

jessegavin
They have if you're targeting Flash Player 10.
MrKishi
One thing I didn't demonstrate in my original code was that was tracing the z-index of these mcs and the btn and they read as expected. So, as3 was assigning them a z-index w/o error, but that wasn't the correct property to modify. As everyone here is pointing out, layering is actually handled in the display list (why isn't there a "layer" property, eh?).
staypuffinpc
Thanks Kishi. I updated my flash reference bookmark.
jessegavin
A: 

swapChildren() should do it.

friends1_btn.addEventListener(MouseEvent.CLICK, friendMaker);

function friendMaker(evt:MouseEvent):void {
    var newFriend:Teddy = new Teddy();
    newFriend.x = Math.random()*stage.width;
    newFriend.y = Math.random()*stage.height;
    stage.addChild(newFriend);
    stage.swapChildren(newFriend, friends1_btn);
}
MrKishi
I get an error when trying to run this script: "Error #2025: The supplied DisplayObject must be a child of the caller."
staypuffinpc
A: 

This way will ensure the button is the very top item no matter what you do. Calling addChild on something that is already added (in the same container) will readd it to the top.

friends1_btn.addEventListener(MouseEvent.CLICK, friendMaker);

    function friendMaker(evt:MouseEvent):void {
        var newFriend:Teddy = new Teddy();
        newFriend.x = Math.random()*stage.width;
        newFriend.y = Math.random()*stage.height;

        stage.addChild(newFriend);
        stage.addChild(friends1_btn);
    }

You can also do the same by replacing

stage.addChild(friends1_btn);

with

stage.swapChildrenAt(stage.getChildIndex(friends1_btn), stage.numChildren - 1);
Allan
A: 

The "z" property of a MovieClip is used for 3D transformations in Flash Player 10 - instead you need to set the child index of the MovieClip explicitly

A good way is to manually set the index of friends1_btn to the front:

friends1_btn.addEventListener(MouseEvent.CLICK, friendMaker);

function friendMaker(evt:MouseEvent):void {
    var newFriend:Teddy = new Teddy();
    newFriend.x = Math.random()*stage.width;
    newFriend.y = Math.random()*stage.height;
    stage.addChild(newFriend);
    stage.setChildIndex(friends1_btn,stage.numChildren-1);
}

(A side note - if you want to randomly position a MovieClip on the Stage, you should use stage.stageWidth and stage.stageHeight, otherwise you are only getting the width and height of objects on the stage, not the stage itself).

Reuben
bummer. I really hoped this would work, but I when I click the button, I get the message, "Error #2025: The supplied DisplayObject must be a child of the caller."
staypuffinpc
ok, for further clarification, this actually did generate the newFriend object on the stage, but it was still on top of the button, in addition to getting the said error.
staypuffinpc
+5  A: 

Or alternatively - and maybe more use longterm - don't have all the added objects as children of the same layer as the button.

So instead of:

stage
  |
  +--- object 1
  |
  +--- object 2
  |
  +--- button
  |
  +--- object 3

Have:

stage
  |
  +--- object layer
  |       |
  |       +--- object 1
  |       |
  |       +--- object 2
  |
  +--- button

Or even:

stage
  |
  +--- object layer
  |       |
  |       +--- object 1
  |       |
  |       +--- object 2
  |
  +--- button layer
          |
          +--- button

Where object layer and button layer could simply be Sprite objects, i.e.:

var objectLayer:Sprite=new Sprite();
var buttonLayer:Sprite=new Sprite();
stage.addChild(objectLayer);
stage.addChild(buttonLayer);
buttonLayer.addChild(myButton);

and so on.

I think you'll find it's more useful to get into that way of thinking longterm rather than just to shift the z-indices around.

Incidentally, the updated Flash Player 10 does have a .z property (even though it's not in the documentation) - as Reuben says, it's used for the new 3D transforms. Sadly 3D transforms have no support whatsoever for z-sorting or z layering, so don't help in this case.

IanT
Yes I would recommend this way for anything slightly complicated. Sometimes you want something higher than one thing but not as high as something else. This makes it much easier to manage.
Allan
for some reason, I wanted to see if I could achieve this without having to use Sprites, but this is the only answer here that actually worked as expected, so bravo, IanT. Consequently, on your code I needed to add one more line. To get the newFriend to appear, I needed to write: objectLayer.addChild(newFriend);
staypuffinpc
One more thing: the little visuals you created above were very useful for understanding what this answer is doing, so thanks for that.
staypuffinpc
No probs - glad to be of help.
IanT
+1  A: 

I know this question has already been answered, but you could also use addChildAt() to specify which index you want to add the DisplayObject at, you can use numChildren, or keep your own record of indexes at which to add.

private var friends1_btn:Sprite;

function friendMaker(evt:MouseEvent):void
{
    var newFriend:Teddy = new Teddy();
    newFriend.x = Math.random()*stage.width;
    newFriend.y = Math.random()*stage.height;
    stage.addChildAt(newFriend, stage.numChildren-1);
    //or if your not sure if the button will always be on top
    stage.addChildAt(newFriend, stage.getChildIndex(friends1_btn)-1);
}

You do NOT want to keep adding the original button to the stage as this will keep triggering the event Event.ADDED_TO_STAGE, it will also cause flickering as the button will be removed from the stage briefly due to the way the display list works.

So, interestingly, the stage.numChildren-1 code works well, but the stage.getChildIndex(friends1_btn)-1 returns the error: "Error #2025: The supplied DisplayObject must be a child of the caller." when I click on the button. This is the same error returned with most of the other answers folks here gave. Since the button (in this case) is a child of the stage, I'm not sure why that error comes up. Any ideas?
staypuffinpc
I really quick way to test this would be to do either of the followingstage.contains(friends1_btn) which returns true if it is contained, but to find out what the parent is simply do trace(friends1_btn.parent), let me know what you get