MouseEvent.MOUSE_UP not working for AS3 code - actionscript-3

I am trying to use the drag feature of flash to move a sprite I created.
I understand that I can add the mouse up event inside of the mouse down event and add to the stage but I would prefer to see if I can get this working first.
Part of the reason I want to use sprite instance mouse up handler is later in code I am referencing the event.target.name for further processing. Below is the code that is giving me the issue with mouse up.
var cnt_fat_1:Sprite = new Sprite();
var g : Graphics = cnt_fat_1.graphics;
g.lineStyle(0,0x555555,0.5);
g.beginFill(0xFFffff);
g.drawRect( 0, 0, 25, 25 );
g.endFill( );
cnt_fat_1.x = 20
cnt_fat_1.y = 20
cnt_fat_1.addEventListener(MouseEvent.MOUSE_DOWN, move_choose)
cnt_fat_1.addEventListener(MouseEvent.MOUSE_UP, move_stop)
addChild(cnt_fat_1)
function move_choose(event:MouseEvent):void {
event.target.startDrag(true);
}
function move_stop(event:MouseEvent):void {
event.target.stopDrag()
}

Related

MouseDown event not firing

I have hundreds of movieclips constantly being created on a timer, each with a mouseDown event listener which will remove the movieclip on mouseDown. For nearly all the movieclips the mouseDown event seems to fire correctly, however sometimes I notice that the mouseDown event does not fire for a movieclip (i.e. it is not removed).
This is function creating the movieclip:
public function pickShape():MovieClip {
//possible shapes
var shapes:Array = [new triangle(), new rectangle(), new square()];
var randomCol:int = Math.floor(Math.random()*colours.length);
var randomShape:int = Math.floor(Math.random()*shapes.length);
var chosenShape:MovieClip = shapes[randomShape];
//change shape to random colour
var shapeCol:ColorTransform = chosenShape.transform.colorTransform;
shapeCol.color = colours[randomCol];
chosenShape.transform.colorTransform = shapeCol;
chosenShape.addEventListener(MouseEvent.MOUSE_DOWN, destroyShape); //remove mc
return chosenShape;
}
pickShape() is called from another function which is called on a timerEvent, in this other function the scaleX, scaleY and rotation of chosenShape are altered. chosenShape will be moving across the screen in an EnterFrame, when it is offscreen it is removed.
What would cause this?
thanks for any help
Does your destroyShape function looks like this:
function destroyShape(e:MouseEvent):void
{
e.currentTarget.parent.removeChild(e.currentTarget);
}
?

Add/Remove Event Listener to/from child Movie Clip in AS3

In short, here is what I'd like to accomplish:
Click Movie Clip, add child
Click child movie clip, play sound
Click child again, stop sound
Click child a third time, remove child
Sadly, I've only gotten as far as step 1. I've figured out how to get a sound to play when the parent movie clip is clicked (I'm using linkage), but when I attempt the same after with the child, I get the following error:
TypeError: Error #1010: A term is undefined and has no properties. (I'm no longer getting this error)
Scene 1, Layer 'actions', Frame 1, Line 29 1120: Access of undefined property newBox.
leftBox.addEventListener(MouseEvent.CLICK, addBox);
function addBox(event:MouseEvent):void
{
var newBox:right_box = new right_box();
addChild(newBox);
newBox.x = 0;
newBox.y = 0;
newBox.width = leftBox.width;
newBox.height = leftBox.height /2;
}
newBox.addEventListener(MouseEvent.CLICK, playSound);
function playSound(event:Event)
{
var mySound:testSound = new testSound();
mySound.play();
}
Any help would be much appreciated.
Thanks!
(P.S. I'm a n00b, so please, be nice!)
You are trying to add an event listener to newbox, before it is created.. Try it as follows:
// mySound should be availible in scope
var mySound:testSound = new testSound();
// newBox also
var newBox:right_box;
// here is a channel for you
var channel: SoundChannel;
// ok this adds the first listener...
leftBox.addEventListener(MouseEvent.CLICK, addBox);
function addBox(event:MouseEvent):void {
newBox = new right_box();
addChild(newBox);
newBox.x = 0;
newBox.y = 0;
newBox.width = leftBox.width;
newBox.height = leftBox.height /2;
// you should add listener here...
newBox.addEventListener(MouseEvent.CLICK, playSound);
// you have to avoid multiple newBoxes on each other and
// leaving the older ones under..
// So stop listening to the newBox generating event:
leftBox.removeEventListener(MouseEvent.CLICK, addBox);
}
function playSound(event:Event){
channel = mySound.play();
// On next click you want sound to stop so
// First remove the old listener to avoid play over:
newBox.removeEventListener(MouseEvent.CLICK, playSound);
// and hook listener to stop method
newBox.addEventListener(MouseEvent.CLICK, stopSound);
}
function stopSound(event:Event){
channel.stop();
// On next click you want to remove newBox
// First remove the old listener to avoid play over:
newBox.removeEventListener(MouseEvent.CLICK, stopSound);
newBox.addEventListener(MouseEvent.CLICK, removeNewBox);
}
function removeNewBox(event:Event){
// First remove the listener :
newBox.removeEventListener(MouseEvent.CLICK, removeNewBox );
removeChild(newBox); // now remove from display list
newBox = null; // make contents eligible for garbage collection
}

Simulate Mouse Click in AS3

I am working on an AS3 project and I am struggling with one particularly fragile part which will need a lot of refactoring in the near future. Just unit testing separate classes in isolation does not catch all issues we are running into. For example, we might forget to disable mouse events on a transparent overlay and thereby block all clicks on a button. Therefore, I am trying to write a test that simulates real user input.
I have tried to manually send a MouseEvent to the stage at the correct position:
stage.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, true, 380, 490, stage));
Since the stage has no click event handler, I expected the event to propagate through the hierarchy to the button that will actually handle it (as it does when I physically click the mouse). However, it doesn't.
I know that I could just dispatch the event on the button, but that will not detect if the object is somehow obstructed. Is there some way to simulate mouse events, such that they will properly propagate through the hierarchy?
Edit:
I managed to do it by re-implementing the propagation behavior of Flash:
Edit 2:
My previous solution didn't work if there was a partly transparent overlay with a click handler, like a Sprite with a few Shapes in it. The problem is that the hitTestPoint method returns true even if the object in question is completely transparent at that point. Therefore, I modified it to check the actual pixel value:
private function clickObject(obj:DisplayObject) : void
{
var relPos:Point = new Point(obj.width / 2, obj.height / 2);
var globalPos:Point = obj.localToGlobal(relPos);
simulateClick(obj.stage, globalPos);
}
private function simulateClick(obj:InteractiveObject, globalPos:Point) : Boolean
{
// first, check if we have any children that would rather handle the event
var container:DisplayObjectContainer = obj as DisplayObjectContainer;
if (container != null)
{
if (container.mouseChildren)
{
for (var i:int = 0; i < container.numChildren; ++i)
{
var child:DisplayObject = container.getChildAt(i);
var interactive:InteractiveObject = child as InteractiveObject;
if (interactive != null)
{
if (simulateClick(interactive, globalPos))
{
// if we have found a handler in the children, we are done
return true;
}
}
}
}
}
if (!obj.mouseEnabled) {
return false;
}
if (obj.hitTestPoint(globalPos.x, globalPos.y))
{
var localPos:Point = obj.globalToLocal(globalPos);
// check if object is visible at the clicked location
var pixel:BitmapData = new BitmapData(1, 1);
pixel.draw(obj, new Matrix(1, 0, 0, 1, -localPos.x, -localPos.y));
var color:uint = pixel.getPixel32(0, 0);
if ((pixel.getPixel32(0, 0) & 0xff000000) != 0)
{
// if yes, dispatch the click event
var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, true, localPos.x, localPos.y, obj);
obj.dispatchEvent(e);
return true;
}
}
return false;
}
Unfortunately, there is still at least one case not covered: If the object is a mask for another object. I have no idea how to check for this, since it could be mask anywhere in the display hierarchy. I would have to traverse the whole tree and check every single display object to find this out.
So, my question remains: Isn't there an easier way to do this?
I've had issues with events in AS3 as well. I've found that the best way is to have the eventListeners added to the same object that's dispatching the events. In your case, adding the .addEventListener to the stage and sending the function as a function on a child clip. eg:
stage.addEventListener(MouseEvent.CLICK, object.object.clicked);
I hope this may help. I've used this method with success in the past.
You can use stage.getObjectsUnderPoint(new Point(pointerX , pointerY )); function , that will return You array with objects . Than remove overlay object and last instance in array should be deepest DisplayObject.
note: last instance can be graphic or such thing , so You should loop through parent objects to find nearest InteractiveObject .
Also , dont forget that parent objects can have mouseChildren = false or mouseEnabled = false

Mouse Click detection only on opaque areas of movieclip

I have movieclips (which in turn have more than 1 movieclips in them ). My requirement is to add a MouseEvent.CLICK event to the parent movieclip. So that an event (MouseEvent.CLICK) is dispatched by flash only if the visually opaque (alpha = 100 %) area has been clicked, otherwise , ignore.
The workaround I do as of now is to create an alpha = 0.05 circle which follows the mousecursor in Event.ENTER_FRAME and do a hittest followed by a PixelPerfectCollisionDetection (courtesy one gr8 guy I admire on google code :) )
In short,
I need to know If I can make flash dispatch a MouseEvent only when clicked on a visually opaque area of the movieclip and NOT anywhere in the bounding box region.
Thanks,
Vishnu Ajit
I got this solution. But It's not perfect at all, cause you create everytime a new bitmapData object of your MovieClip:
myButton.addEventListener( MouseEvent.CLICK, clickFunction);
private function clickFunction(e:MouseEvent) {
if(pixelIsVisible(e.currentTarget, e.currentTarget.mouseX, e.currentTarget.mouseY)) {
//DoSomething
}
}
private function pixelIsVisible(target:*, xPos:int, yPos:int):Boolean {
var bmp:BitmapData = new BitmapData( target.width, target.height, false );
bmp.draw( target as MovieClip );
var pixelValue = bmp.getPixel( xPos, yPos);
//Dispose bitmapData to free memory
bmp.dispose();
var alphaValue:uint = pixelValue >> 24 & 0xFF;
//alphaValue is from 0 to 255
if(alphaValue >= 255) return true;
else false;
}

Some problems regarding removing a child added dynamically

I have this function where I want to get a movie clip (the function target) and change it to another one. The problem is that it obviously removes the movie clip before the new one is loaded.
var changePeca:Loader = new Loader;
var changeLoad:URLRequest = new URLRequest(e.target.name.substr(0,4)+".png");
changePeca.load(changeLoad);
e.target.removeChildAt(0);
e.target.addChild(changePeca);
I know that I must use the Event.COMPLETE thing, but how do I say which movie clip to remove, since I cant use e.target anymore?
"The problem is that it obviously removes the movie clip before the new
one is loaded."
Because you code says do so! :) You need to add the event listener which checks if the stuff is loaded.
private var holderMC:Sprite;
private var imageLoader:Loader;
private function load(e:Event):void
{
holderMC = e.target as Sprite // or something else you have there, just store it.
imageLoader = new Loader ();
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, handleLoadComplete)
imageLoader.load(new URLRequest(e.target.name.substr(0, 4) + ".png"));
}
private function handleLoadComplete(e:Event):void
{
if(holderMC.numChildren > 0)
holderMC.removeChildAt(0);
holderMC.addChild(imageLoader.content)
}