Actionscript 3 and dynamic masks
Solution 1
this.masker.mouseEnabled = false; //set on this.masker
That should work. Right now it is intercepting your events before they get to anything else in the container. Not 100% sure, but I believe a mask will sit on top of the container. Another option would be to add another masking child to MyContainer at the bottom of the displayList and add panel as its sibling. You will want to set mouseEnabled and mouseChildren to false on the masked sprite/mc still though.
package
{
import flash.display.Shape;
import flash.display.Sprite;
public class MyContainer extends Sprite
{
protected var masker : Shape = null;
protected var panel:MyPanel;
public function MyContainer()
{
this.masker = new Shape();
this.masker.graphics.clear();
this.masker.graphics.beginFill( 0x00ff00 );
this.masker.graphics.drawRect(0, 0, 1, 1); // 1x1 pixel.
this.masker.graphics.endFill();
addChild( this.masker );
this.panel = new MyPanel();
this.addChild(panel);
this.mask = this.masker;
}
// called by it's parent when the stage is resized.
public function resize( width : Number, height : Number ) : void
{
// set the mask to half the size of the stage.
this.masker.width = width / 2;
this.masker.height = height / 2;
// set the panel to half the size of the stage.
}
}
}
-
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class MyPanel extends Sprite
{
public function MyPanel()
{
this.graphics.beginFill(0xFF0000)
this.graphics.drawRect(0,0,10,10);
this.addEventListener(MouseEvent.MOUSE_OVER, this.handleMouseOver)
this.addEventListener(MouseEvent.MOUSE_OUT, this.handleMouseOut)
}
public function handleMouseOver(event:Event):void
{
this.graphics.clear();
this.graphics.beginFill(0x00FF00)
this.graphics.drawRect(0,0,10,10);
}
public function handleMouseOut(event:Event):void
{
this.graphics.clear();
this.graphics.beginFill(0xFF0000)
this.graphics.drawRect(0,0,10,10);
}
}
}
Solution 2
One thing i noticed is if the mask in a child of the masked object, the position of that mask for all mouse related event or interactivity will be off, while visually everything seems fine.
For example i had a clip with a button inside end it was masked by one of it's child. What happened is only half the button could be clicked and if I moved the clip a bit to the left, only a quarter of the button remained click-able.
Basically the mouse event masking seems to position itself relative to the parent of the masked object while the visual mask does not.
You need to move the mask to the parent clip. Here how i did it :
class MaskedObject extends MovieClip{
public var maskClip:MovieClip;
public var maskOrigin:Point
public function MaskedObject (){
maskOrigin = new Point(maskClip.x,maskClip.y);
parent.addChild(maskClip);
maskClip.x = maskOrigin.x + this.x;
maskClip.y = maskOrigin.y + this.y;
mask = maskClip;
}
override function set x(val:Number):void{
super.x = val;
maskClip.x = maskOrigin.x + this.x;
}
override function set y(val:Number):void{
super.y = val;
maskClip.y = maskOrigin.y + this.y;
}
}
Luke
Updated on June 04, 2022Comments
-
Luke about 2 years
I have a container MovieClip that serves as a content area that I need to mask off. When I create a mask inside this container using a Shape I can't seem to interact with the contents of other containers I create here, like buttons etc.
This is what I'm doing in code (I've left out all the import's etc.):
class MyContainer extends MovieClip { protected var masker : Shape = null; protected var panel : MyPanel = null; public function MyContainer() { this.masker = new Shape(); this.masker.graphics.clear(); this.masker.graphics.beginFill( 0x00ff00 ); this.masker.graphics.drawRect(0, 0, 1, 1); // 1x1 pixel. this.masker.graphics.endFill(); addChild( this.masker ); this.panel = new MyPanel(); // has buttons and stuff. addChild( this.panel ); this.mask = this.masker; } // called by it's parent when the stage is resized. public function resize( width : Number, height : Number ) : void { // set the mask to half the size of the stage. this.masker.width = width / 2; this.masker.height = height / 2; // set the panel to half the size of the stage. this.panel.resize( width / 2, height / 2); } }
When I add the mask (Shape) to the display hierarchy I can no longer interact with whatever buttons are defined in MyPanel. However, not adding the mask to the display hierarchy does let me interact with the contents on MyPanel but the mask is not sized/positioned correctly. I guess that when the mask is not added to the display hierarchy it sits in the top-left corner of the movie (I cannot prove this though).
How do I go about making my mask size/position correctly and let the user interact with the buttons in MyPanel?
-
Luke almost 15 yearsBut masker is a Shape and therefore doesn't have a mouseEnabled property. It's a reason I used a Shape instead of a Sprite.
-
Luke almost 15 yearsJust tested it with a Sprite instead of a Shape (with the mouseEnabled property set to false). Doesn't work either. :(
-
Joel Hooks almost 15 yearsPerhaps the problem is in your MyPanel class? I tested it with my added code above and it works as expected.
-
Luke almost 15 yearsThe MyPanel class is just content of the container, it could have been anything. The point I'm tying to make is that by adding the mask to the display hierarchy you can't interact with any objects in the scope of that masked display object.
-
Luke almost 15 yearsYes. The example above works indeed. However, my application doesn't. There must be something else at work here since my actual application is a lot more complex of course. In the meantime I've solved my problem by not adding the mask to the display hierarchy and use a localToGlobal to position the mask correctly. Thanks for your help so far!
-
Luke almost 15 yearsOK. I'm still not there but I found out that the Glow filter applied to the container was impacting the mask somehow. Removing the Glow filter from the container made it work as described above. However, I was not able to reproduce the problem with the above example. If I find out more I will comment here.
-
Triynko over 12 yearsFrom the documentation: "When display objects are cached by setting the cacheAsBitmap property to true an the cacheAsBitmapMatrix property to a Matrix object, both the mask and the display object being masked must be part of the same cached bitmap." ----------------------------------------------------------------------------------------------------Note that cacheAsBitmap is automatically true when any filters are applied, so that's why this applies in that circumstance.
-
Triynko over 12 yearscontinued... "Thus, if the display object is cached, then the mask must be a child of the display object. If an ancestor of the display object on the display list is cached, then the mask must be a child of that ancestor or one of its descendents. If more than one ancestor of the masked object is cached, then the mask must be a descendent of the cached container closest to the masked object in the display list."