views:

163

answers:

1

Can anyone help me make sense of the following?

I create a few squared sprites and then remove the first one and display the coords. The result is:

  (x=0, y=0, w=208, h=40) 0 208
  (x=42, y=0, w=166, h=40) 0 166

The x coordinate is still 0, though width has changed, getBounds shows correct values. I would expect x to change as well. Because of the wrong value of x, globalToLocal and localToGlobal work incorrectly.

If you click somewhere on the left side of the second (still visible) rectangle you get:

2 28 (x=2, y=28)

which is good for nothing. The values in brackets should be in stage coords and they are not.

The code:

    public function test():void {
        var s:Sprite;
        var i:int;

        var arr:Array = new Array();
        for (i = 0; i < 5; ++i)
        {
            s = new Sprite();
            s.graphics.beginFill(0x999);
            s.graphics.drawRect(0, 0, 40, 40);
            s.graphics.endFill();
            s.x = i * 42;
            arr.push(s);
            addChild(s);
        }
        trace(this.getBounds(stage), x, width);
        removeChild(arr[0]); arr[0] = null;
        trace(this.getBounds(stage), x, width);
        addEventListener(MouseEvent.CLICK, click);
    }

    private function click(e:MouseEvent):void {
        trace(e.localX, e.localY, localToGlobal(new Point(e.localX, e.localY)));
    }
+1  A: 

You're confused on two separate points, but I think they each stem from an incomplete view of how Flash deals with coordinate systems. Recall that every display object carries around its own coord system. In your first question, an object's "x" and "y" properties aren't calculated dynamically to reflect the object's upper-left corner, they simply denote the location of that object's origin, with respect to its parent's coordinate system. So an object's "x" value won't change just because the object's contents changed - it changes when you move the object itself.

The problem with your stage coordinates is that the localToGlobal method converts coordinates from the scope in which it's called - and you're calling it from the parent of the rectangles, but you're passing in coordinates from the local system inside the rectangle. Stare that following for a bit and it should make sense:

function click(e:MouseEvent):void {
    // bad - uses rectangle coords in scope of "this"
    //trace(e.localX, e.localY, localToGlobal(new Point(e.localX, e.localY)));
    // works - call localToGlobal from the scope of the rectangle
    trace( e.target.localToGlobal(new Point(e.localX, e.localY)));
    // alternately, call it from any scope with coordinates taken from that scope:
    trace( localToGlobal( new Point( mouseX, mouseY )));
    trace( e.target.localToGlobal( new Point( e.target.mouseX, e.target.mouseY )));
}

Update: Part of what makes this confusing is how event bubbling works in AS3. Read the first few paragraphs of this excellent article to get the general idea, and then understand that in this example the events are initially issued from a rectangle (because that's where the graphic that got clicked is), but you only catch them as they bubble through the scope where you set your listener. So e.target is the rectangle, and e.currentTarget is the scope of your listener. Then the final piece of the puzzle is to understand that e.localX and e.localY are always in the coordinate system of the event's original target. (This is because they are properties of the event, and it wouldn't make sense for them to keep changing as the event bubbled up the display list.)

As a final note, if you're wondering how beginners usually cope with this stuff, the answer is that people usually attach listeners directly to the display object that has the graphical contents that will be clicked. In that case, e.target and e.currentTarget will always be the same, and most beginners won't need to understand any of this.

fenomas
That's right - I wasn't calling the localToGlobal in the right way.Thank you.So it seems that the local coords returned are always with respect to the actually used portion of a sprite. And to get the coords with respect to (x, y) you have to take the bounds into consideration.It makes sense, but as usual with Flash, it is completely undocumented. :-)
stach
Sorry, you have it backwards - the coords returned are with respect to the sprite's origin, and the sprite's (x,y) is the location of that sprite's origin in its parent's coord system. As per documentation. ;)I think the confusing point is that the click occurs on a rectangle, so (e.localX, e.localY) is a point in the coord system whose origin is the UL corner of the rectangle clicked. But your click handler is scoped in the rectangle's parent.
fenomas
I was (probably ;-) assuming that events will be in the context of the object whose addEventListener was called before. But the event is in the context of its child.I have to read more about the event model.Thanks again.
stach
Ahh, I see. I'll edit a link into my answer, which I think will make everything make a lot more sense.
fenomas