MouseEvent.CLICK in transparent area - actionscript-3

I have a movieClip that i want to get mouse click event on it,
it works fine but it doesn't fire this event when i click on transparent area.
is there any solution except to define a rectangle as hitArea?
mc.addEventListener(MouseEvent.CLICK, onMouseClickEvent);
function onMouseClickEvent(event:Event) {
trace("on clicked");
}

It's true that you won't be able to click the transparent area, however, here is an alternate solution.
If you can monitor your mouse state with a global listener like:
stage.addEventListener( MouseEvent.CLICK, onStageClicked );
Then you can write another function that does a hit test against your display object:
public function mouseTest( someAsset:DisplayObject ):Boolean
{
return someAsset.hitTestPoint( stage.mouseX, stage.mouseY );
}
Last from your onStageClicked() handler:
private function onStageClicked( e:Event ):void
{
if ( mouseTest( mc ) )
{
//do something
}
}
That should suffice for the transparent area.

Related

Actionscript 3: Listeners not working after child is removed, then added again

I have some code that adds a "back" button to the stage that has its own code, and clicking it removes the button and brings users back to a title screen. However, when the "back" button is reintroduced to the stage, none of its listeners work.
public class BACK extends SimpleButton {
public function BACK() {
// constructor code
trace('back button on stage');
addEventListener(Event.ADDED_TO_STAGE, startUp);
}
function startUp(ev:Event): void{
addEventListener(MouseEvent.CLICK, gotoTitle);
addEventListener(Event.REMOVED_FROM_STAGE, backBtnCleanUp);
}
function gotoTitle(ev:MouseEvent): void{
trace('gototitle called');
MovieClip(root).gotoTitle();
}
function backBtnCleanUp(ev:Event): void{
trace('back button cleanup called');
removeEventListener(Event.ADDED_TO_STAGE, startUp);
removeEventListener(MouseEvent.CLICK, gotoTitle);
removeEventListener(Event.REMOVED_FROM_STAGE, backBtnCleanUp);
}
}
the trace function executes when it is first added to the stage, but not when it is added again after being removed. This is the code (from Main) that both adds and removes it.
function gotoHelp(): void{ // transitions to the help screen
cleanTitle();
addChild(helpBG);
addChild(backBtn);
backBtn.x = 550;
backBtn.y = 200;
}
function gotoTitle(): void{ //goes to the title screen
trace('going to title');
removeChild(backBtn);
removeChild(helpBG);
titleStartUp();
}
You should create a new instance of your BACK button every time you need to show it, or remove this line from backBtnCleanUp function : ( not tested )
removeEventListener(Event.ADDED_TO_STAGE, startUp);

Can any one explain this code how i use this in my application

I have a problem similar like this question but i'm not able to get understand this answer code, Can any one explain this code.
private function attachListeners():void
{
this.addEventListener(MouseEvent.MOUSE_DOWN, selfMouseDownHandler, false,0,true);
this.addEventListener(MoveEvent.MOVE, selfMoveHandler, false,0,true);
}
private function selfMoveHandler(event:MoveEvent):void
{
redrawConnectedLinks();
}
private function selfMouseDownHandler(event:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler, false,0,true);
stage.addEventListener(MouseEvent.MOUSE_MOVE, stageMouseMoveHandler, false,0,true);
}
private function stageMouseUpHandler(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler, false);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, stageMouseMoveHandler, false);
}
private function stageMouseMoveHandler(event:MouseEvent):void
{
dispatchEvent(new MoveEvent(MoveEvent.MOVE));
}
Please suggest me how to use this in flex application.
This code is tracking mouse movement by Flash's MouseEvent.MOUSE_UP, MouseEvent.MOUSE_MOVE and MouseEvent.MOUSE_DOWN.
Along with those events, the code is using a custom Event: MoveEvent.MOVE.
Any time, a MoveEvent.MOVE is being dispatched, the app would redraw the connectors. So, a listener to MoveEvent.MOVE is being added once and for all at the beginning.
Also, to track a drag, this code waits for MOUSE_DOWN and then keep on dispatching MoveEvent.MOVE for each MouseEvent.MOUSE_MOVE until a MOUSE_UP event occurs.
Now, let me associate the above explanation to the lines of code:
private function attachListeners():void
{
/*Wait for mouse down event to initiate mouse move and mouse up tracking*/
this.addEventListener(MouseEvent.MOUSE_DOWN, selfMouseDownHandler, false,0,true);
/*Always track MoveEvent.MOVE and start redrawing connectors whenever it's dispatched*/
this.addEventListener(MoveEvent.MOVE, selfMoveHandler, false,0,true);
}
private function selfMoveHandler(event:MoveEvent):void
{
/*Redraw connectors when the custom event MoveEvent.MOVE is received*/
redrawConnectedLinks();
}
private function selfMouseDownHandler(event:MouseEvent):void
{
/*Wait for mouse up event on receiving a mouse down*/
stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler, false,0,true);
/*Track mouse movement once mouse is down*/
stage.addEventListener(MouseEvent.MOUSE_MOVE, stageMouseMoveHandler, false,0,true);
}
private function stageMouseUpHandler(event:MouseEvent):void
{
/*Once mouse up happens stop tracking mouse up... */
stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler, false);
/*Don't track mouse movement once mouse button gets released*/
stage.removeEventListener(MouseEvent.MOUSE_MOVE, stageMouseMoveHandler, false);
}
private function stageMouseMoveHandler(event:MouseEvent):void
{
/*dispatch MoveEvent.MOVE when mouse is moved.
If you read the above setup again, this should get dispatched on mouse moves
happening after a mouse down and before a mouse up
*/
dispatchEvent(new MoveEvent(MoveEvent.MOVE));
}
HTH.
Explanation of custom events as asked in the comment by OP
Custom events are useful to add custom message passing semantics. e.g. in this case, mouse drag is a detected by a series of mouse events, and once those events happen a custom event is dispatched to notify the connectors should be redrawn. Similarly, you might have a refresh button and clicking on it might dispatch the same event to force redraw.

Flash AS3 hit test go to next frame

I have a object that can be dragged into another object. I have set up a hit test for the collision. When the collision occurs I would like to progress to the next frame however, I have to click on the draggable object for it to do so. I would like it to move to the next frame right away without clicking. Is there anyway to fix this?
I mean after I have dragged the objected to create the collision I need to click on the object again to progress to the next frame. I do not want to have to click on the object again I want it to go to the next frame as the collision occurs.
This is my code
bottle.buttonMode = true;
bottle.addEventListener(MouseEvent.MOUSE_DOWN, drag);
bottle.addEventListener(MouseEvent.MOUSE_UP, drop);
function collision():void{
if(bottle.hitTestObject(hit)){
nextFrame();
}
}
function drag(e:MouseEvent):void{
bottle.startDrag();
collision();
}
function drop(e:MouseEvent):void{
bottle.stopDrag();
}
You should be checking for collisions after the drop, not at the start of the drag:
function collision():void{
if(bottle.hitTestObject(hit)){
nextFrame();
}
}
function drag(e:MouseEvent):void{
bottle.startDrag();
}
function drop(e:MouseEvent):void{
bottle.stopDrag();
collision();
}
Change collision() into an event listener and attach it to bottle.
Try this one ( adapted from Gary Rosenzweig ) :
bottle.buttonMode = true;
bottle.addEventListener( MouseEvent.MOUSE_DOWN, startBottleDrag );
stage.addEventListener( MouseEvent.MOUSE_UP, stopBottleDrag );
function collision():void {
if( bottle.hitTestObject( hit ) ) {
stopBottleDrag();
nextFrame();
}
}
// to keep bottle location as it is when clicked
var clickOffset:Point = null;
function startBottleDrag( e:MouseEvent ) {
clickOffset = new Point( e.localX, e.localY );
bottle.addEventListener( Event.ENTER_FRAME, dragBottle );
}
function stopBottleDrag( e:MouseEvent = null ) {
clickOffset = null;
bottle.removeEventListener( Event.ENTER_FRAME, dragBottle );
}
function dragBottle( e:Event ) {
bottle.x = mouseX - clickOffset.x;
bottle.y = mouseY - clickOffset.y;
collision();
}

Click event outside MovieClip in AS3

Is there any way to detect if the user click outside a MovieClip?
For instance, I need to detect it to close a previously opened menu (like Menu bar style: File, Edition, Tools, Help, etc).
How can I detect this kind of event? Thanks!
Add a listener to stage and check if stage is the target of the event.
Example of code here:
http://wonderfl.net/c/eFao
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class FlashTest extends Sprite
{
private var _menu : Sprite;
public function FlashTest()
{
_menu = new Sprite();
_menu.x = 100;
_menu.y = 100;
_menu.alpha = 0.5;
with(_menu.graphics)
{
beginFill(0xFF0000, 1);
drawRect(0, 0, 300, 300);
endFill();
}
addChild(_menu);
_menu.addEventListener(MouseEvent.CLICK, onClickHandler);
stage.addEventListener(MouseEvent.CLICK, onClickHandler);
}
private function onClickHandler(event : MouseEvent) : void
{
switch(event.target)
{
case _menu:
_menu.alpha = 0.5;
break;
case stage:
_menu.alpha = 1;
break;
}
}
}
}
You can add a listener to the click event of the root element:
MovieClip(root).addEventListener(MouseEvent.CLICK, clickObject);
then in the function clickObject, you can check to see what you are clicking.
function clickObject(e:Event):void
{
var hoverArray:Array = MovieClip(root).getObjectsUnderPoint(new Point(stage.mouseX, stage.mouseY));
var hoverOverObject:* = hoverArray[hoverArray.length - 1];
}
hoverOverObject references the element that you are clicking on. Often this will be the shape within the movie clip, so you'll need to look at it's parent then compare it to your movie clip. If the click wasn't on the drop down movie clip, trigger the close.
var container:MovieClip = new MovieClip();
var mc:MovieClip = new MovieClip();
with(mc.graphics){
beginFill(0xff0000,1);
drawCircle(0,0,30);
endFill();
}
mc.name = "my_mc";
container.addChild(mc);
addChild(container);
stage.addEventListener(MouseEvent.CLICK, action);
function action (e:MouseEvent):void
{
if(e.target.name != "my_mc"){
if(container.numChildren != 0)
{
container.removeChild(container.getChildByName("my_mc"));
}
}
}
Use capture phase:
button.addEventListener(MouseEvent.CLICK, button_mouseClickHandler);
button.stage.addEventListener(MouseEvent.CLICK, stage_mouseClickHandler, true);
//...
private function button_mouseClickHandler(event:MouseEvent):void
{
trace("Button CLICK");
}
private function stage_mouseClickHandler(event:MouseEvent):void
{
if (event.target == button)
return;
trace("Button CLICK_OUTSIDE");
}
Note that using stopPropagation() is good for one object, but failed for several. This approach works good for me.
Use a stage and a sprite (menu) click listener with the sprite listener executing first and apply the stopPropagation() method to the click handler of the sprite. Like this:
menu.addEventListener(MouseEvent.CLICK, handleMenuClick);
stage.addEventListener(MouseEvent.CLICK, handleStageClick);
private function handleMenuClick(e:MouseEvent):void{
// stop the event from propagating up to the stage
// so handleStageClick is never executed.
e.stopPropagation();
// note that stopPropagation() still allows the event
// to propagate to all children so if there are children
// within the menu overlay that need to respond to click
// events that still works.
}
private function handleStageClick(e:MouseEvent):void{
// put hide or destroy code here
}
The idea is that a mouse click anywhere creates a single MouseEvent.CLICK event that bubbles from the stage, down through all children to the target, then back up through the parents of the target to the stage. Here we interrupt this cycle when the target is the menu overlay by not allowing the event to propagate back up to the parent stage, ensuring that the handleStageClick() method is never invoked. The nice thing about this approach is that it is completely general. The stage can have many children underneath the overlay and the overlay can have its own children that can respond to clicks and it all works.

mouse up event not working properly

can anyone please help me on this.
attached is the fla which has a part of code i am working on for a project.
with help of mouse you can draw a circle on the image, but for some reasons the mouse up event does not work. it works fine when the eventlisteners is attached to the stage, but does not work when its attached to the movieclip.
also how can i restrict the circle to be drawn only inside the movieclip which is a rectangle.
here is the code
const CANVAS:Sprite = new Sprite();
var _dragging:Boolean = false;
var _corner:Point;
var _corner2:Point;
menFront.addEventListener(MouseEvent.MOUSE_DOWN, setAnchor);
menFront.addEventListener(MouseEvent.MOUSE_UP, completeRect);
function setAnchor(e:MouseEvent):void{
trace("mouse down");
if(!_dragging){
CANVAS.graphics.clear();
_corner = new Point(e.stageX, e.stageY);
_dragging = true;
menFront.addEventListener(MouseEvent.MOUSE_MOVE, liveDrag);
}
}
function completeRect(e:MouseEvent):void{
trace("mouse up");
if(_dragging){
_dragging = false;
menFront.removeEventListener(MouseEvent.MOUSE_MOVE, liveDrag);
CANVAS.graphics.lineStyle(0, 0, 0);
CANVAS.graphics.beginFill(0x222222,.5)
_corner2 = new Point(e.stageX, e.stageY);
trace(Point.distance(_corner,_corner2).toFixed(2));
CANVAS.graphics.drawCircle(_corner.x, _corner.y, Point.distance(_corner,_corner2));
addChild(CANVAS);
}
}
function liveDrag(e:MouseEvent):void{
CANVAS.graphics.clear();
CANVAS.graphics.lineStyle(0, 0x999999);
_corner2 = new Point(e.stageX, e.stageY);
//trace(Point.distance(_corner,_corner2).toFixed(2));
CANVAS.graphics.drawCircle(_corner.x, _corner.y, Point.distance(_corner,_corner2));
addChild(CANVAS);
}
If you add the MouseEvent.MOUSE_UP to the object that you are dragging, the event will only fire if the item is underneath the mouse at the moment the MOUSE_UP happens, but since you're updating the item with MOUSE_MOVE, that's a race-condition between when the MOUSE_UP happens and when the MOUSE_MOVE happens.
To avoid such problems you want to guarantee that you receive the MOUSE_UP whenever MOUSE_UP fires, during your live-update cycle. To do that, add the event listener to the stage just when it's needed, something like this:
menFront.addEventListener(MouseEvent.MOUSE_DOWN, setAnchor);
function setAnchor(event:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, completeRect);
// your other functionality
}
function completeRect(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, completeRect);
// your other functionality
}
so that your completeRect doesn't get called inadvertently if you're clicking elsewhere.
Hope This Helps