Good question!
I've done a quick test. There is a method called getObjectsUnderPoint() which
returns an array of objects that lie
under the specified point and are
children (or grandchildren, and so on)
of this DisplayObjectContainer
instance
according to the documentation.
Also
any child objects that are
inaccessible for security reasons are
omitted from the returned array. To
determine whether this security
restriction affects the returned
array, call the
areInaccessibleObjectsUnderPoint()
method.
So I don't know how helpful this might be.
Here's my test nevertheless:
//make some clips interactive
for(var i:int = 0 ; i < numChildren ; i+=2){
MovieClip(getChildAt(i)).mouseEnabled = true;
MovieClip(getChildAt(i)).buttonMode = true;
MovieClip(getChildAt(i)).mouseChildren = false;
}
//reuse this array
var clips:Array;
addEventListener(Event.ENTER_FRAME, checkClickables);
function checkClickables(event:Event):void {
clips = this.getObjectsUnderPoint(new Point(mouseX,mouseY));
for(i = 0 ; i < clips.length ; i++){
if(isInteractiveObject(clips[i])){
trace(clips[i]);
}
}
}
function isInteractiveObject(object:*):Boolean{
var extendsClass:XMLList = describeType(object).extendsClass;
for each(var classDef:XML in extendsClass){
if(classDef.@type == 'flash.display::InteractiveObject') return true;
}
return false;
}
I have some clips on stage, and I'm making some of them 'clickable'.
Then onEnterFrame I'm checking if there are any instances of a subclass
of InteractiveObject( the superclass for anything clickable )
For some reason in my test, getObjectsUnderPoint() returned only Shape objects, no Sprites.
Maybe it might work in your configuration.
Also it seems a bit complicated.
Here's my second approach:
function getInteractiveObjects(container:DisplayObjectContainer):Array{
var result:Array = [];
for(var i:int = 0 ; i < container.numChildren ; i++){
if(container.getChildAt(i) is Sprite || container.getChildAt(i) is MovieClip) result.push(container.getChildAt(i));
if(container.getChildAt(i) is DisplayObjectContainer){
var clips:Array = getInteractiveObjects(DisplayObjectContainer(container.getChildAt(i)));
var clipsNum:int = clips.length;
for(var j:int = 0 ; j < clipsNum ; j++)
if(clips[j] is Sprite || clips[j] is MovieClip) result.push(clips[j])
}
}
return result;
}
Use a recursive function that gets potentially interactive objective inside a clips(like the loader content). If it is either a Sprite or MovieClip, it's 'clickable'.
var iclips:Array = getInteractiveObjects(this);
for(i = 0 ; i < iclips.length ; i++){
trace(iclips[i].name);
//do extra tests here
if(iclips[i].hasEventListener(MouseEvent.ROLL_OVER)) trace(iclips[i].name + ' has roll over');
//etc.
}
You can then do extra tests, depending on what exactly you're looking for ( either it has and event listener for mouse events, either it is mouseEnabled, has buttonMode set to true, etc. )
This way you don't need to check for any mouse over ( don't have to wait for user interaction or call a function all the time ) and once you got the clips that don't behave the way you want to, you can change their behavior (mouseChildren = false, or something).
HTH