views:

158

answers:

6

What is a good strategy for detecting when the position (x, y) of a sprite, relative to the stage, has changed? In other words, how can I detect changes to a sprite's global position?

This becomes difficult when the sprite is the child of other DisplayObjectContainer objects.

+1  A: 

Is it a UIComponent or just a Sprite? I'm not sure how to do it if it's just a Sprite, but if it's a UIComponent it's doable, but could get messy.

You'd have to listen to the component's move event. When you get that event you can get its position and convert that to global coordinates using the localToGlobal() method.

Unfortunately I think you'd have to also listen to move events for all of its parent components as well, as I don't think a component will raise the move event if its parent moves.

There might be a cleaner way to do this, but if not this should work.

Herms
pure as3 -- just using a sprite. although it is interesting that mx.* provides a move event. i think you are right about adding listeners to all of the parents. it just gets ugly if the chain back to the stage gets broken at some point (a child is removed from its parent)... need to listen for those events too i guess.
jedierikb
+2  A: 

Hi,

You could create a sub-class of Sprite and override the public function set x(value:Number):void and public function set y(value:Number):void

simple exemple:

public class Exemple extends Sprite{

    override public function set x(value:Number):void{
         super.x=value;
         dispatchEvent(new Event("move"));
    }
    override public function set y(value:Number):void{
         super.y=value;
         dispatchEvent(new Event("move"));
    }

}

Also, have a look at the Event.RENDER event...

OXMO456
Thank you, this would fire when the sprite is moved in respect to its parent. I am trying to determine when the sprite is moved in respect to the stage (meaning that its parents could move).
jedierikb
Ok, didn't understand : | sorry !
OXMO456
A: 

Another solution would be to create a "thread" using Timer to check the position using localToGlobal() every, say, 100ms. There would be delay between when the move happens and you get the event, but that way you wouldn't have to look at the entire display list to tell if the sprite or any of its parents changed. You'd just check the global position of the sprite, and if it's changed you call something.

You could even create a helper class that could check multiple sprites. Then you'd just register sprites with it, and each time it runs it would check all of them and raise a move event for each sprite it detects moved. Probably wouldn't be too hard to create it.

Again, this wouldn't be perfect, as you wouldn't get the events immediately after the move, but if you don't need to know right away it might be good enough.

Herms
+1  A: 

If you really want this, and you want it accurate, make an onEnterFrame and nest something like this inside it:

var vals:Object = new Object;
function checkPositionChanged(obj:DisplayObject):Boolean
{
var bool:Boolean = false;

var pt:Point = new Point(obj.x,obj.y);
pt = pt.localToGlobal(obj);
if( vals.x != pt.x || vals.y != pt.y ){
   bool = true;
}
vals.x = pt.x;
vals.y = pt.y;
return bool;
}
michael
A: 

You could accomplish this based on a modification of OXMO456's suggestion. As you are concerned about the notifications based on it's position in the stage, and not neccessarily it's parent, you can simply cache and compare the 'global' coordinates, and fire when that changes.

useful methods to know:

localToGlobal

globalToLocal

public class Example extends Sprite{
    private var stagePoint:Point = new Point(0,0);
    override public function set x(value:Number):void{
        super.x=value;
        if(stage != null){
            var globalPoint:Point = this.parent.localToGlobal(new Point(x,y));
            if(globalPoint.x != stagePoint.x){
                stagePoint = globalPoint;
                dispatchEvent(new Event("move"));
            }
        }
    }
    override public function set y(value:Number):void{
         super.y=value;
         if(stage != null){
            var globalPoint:Point = this.parent.localToGlobal(new Point(x,y));
            if(globalPoint.y != stagePoint.y){
                stagePoint = globalPoint;
                dispatchEvent(new Event("move"));
            }
        }
    }

}

EDIT: Oh wait, I think I mis-interpreted what you were asking, doh! I'll leave this up in case it's useful in some other way.

Can you give some more detail about the problem you're trying to solve by doing this? That might help us zero in on a solution that will work without deal-breaking overhead (like a ton of registered event listeners or some such)

JStriedl
A: 

The only way I can think is having a function called on the EnterFrame event and check the lacalToGloabal coordinates tested against a stored property. The problem is that this can become rather resource intensive if you have a lot of sprites. You can alleviate the problem somehow enabling and disabling the event handler based on external conditions. Otherwise I would really consider talking the problem the other way around and concentrate on the circumstances that may move the sprites, that is, the triggers and not the effects, if this is possible.

Julio Garcia