In writing an ActionScript 3 program, I am trying to make it so that I can drag an object from one location to another after doing some other stuff. The trouble is, I can drag just fine, but apparently I can't stop dragging, even with a listener to make it stop. I can't figure out any reason why this is happening. The relevant part of my code is as follows:
public function setToDragAndDrop(){
this.graphic.removeEventListener(MouseEvent.CLICK, rotate);
this.graphic.addEventListener(MouseEvent.MOUSE_DOWN, drag);
this.graphic.addEventListener(MouseEvent.MOUSE_UP, endDrag);
}
private function drag(e:MouseEvent):void{
trace("Dragging...");
this.graphic.startDrag(true);
trace(this.graphic.hasEventListener(MouseEvent.MOUSE_UP)); //Returns true
}
private function endDrag(e:MouseEvent):void{
trace("Stopped dragging.");
this.graphic.stopDrag();
}
I do not get the "Stopped dragging" line in my output, so the endDrag MouseEvent is never getting called, even though it exists (as the trace proves). So instead whether the mouse is up or down, it continues to drag. I've found that if I click on another draggable object, that one starts dragging instead.
I'm baffled. Any help would be greatly appreciated!
I figured out the problem. Apparently when you create the shape, it's "drag point" is at (0,0), or if you premake the shape in Flash, the upper left corner of the "rectangle" that surrounds the figure. When you click on the shape, your mouse jumps to this "drag point."
Apparently, if the drag point does not actually lie on the body of the shape, drag and drop doesn't work. So the ovals I was using earlier didn't work because the drag point was off the shape. Your example did work because it was created at (0,0) and your drag point was at (0,0). But if you draw a circle that isn't at (0,0), like drawCircle(200,200,100) (i.e. draw a circle at point (200,200) with a radius of 100), then you encounter the problem that I have because the drag point is not on the shape.
The solution then is to create the circle at 0,0, then move it to the position you want. It's strange, but I finally got it to work.
public function setToDragAndDrop(){
this.graphic.removeEventListener(MouseEvent.CLICK, rotate);
this.graphic.addEventListener(MouseEvent.MOUSE_DOWN, drag);
}
private function drag(e:MouseEvent):void{
this.graphic.startDrag(true);
this.graphic.removeEventListener(MouseEvent.MOUSE_DOWN, drag);
this.graphic.addEventListener(MouseEvent.MOUSE_UP, endDrag);
}
private function endDrag(e:MouseEvent):void{
this.graphic.stopDrag();
this.graphic.removeEventListener(MouseEvent.MOUSE_UP, endDrag);
this.graphic.addEventListener(MouseEvent.MOUSE_DOWN, drag);
}
it works very well here.
http://wonderfl.net/c/CvWO
Check the flash "fiddle" .
Related
I've a problem with ROLL_OVER event listener. When I enter the empty area withing the movieclip with mouse cursor, ROLL_OVER event triggers. But I want that event trigger only when mouse cursor is on the colored area.
To Make it more clear: Think about " O " letter, when mouse cursor is between the empty area of O letter (inside of O) , event shouldn't trigger. It should trigger only when mouse curser is on the black area.
How can I implement this?
Thanks
-Ozan
PROBLEM IS SOLVED THANKS TO #Ethan Kennerly
I just want to add a few things to help people have problem same as me. In my situation I tried to make continents glow when my mouse is over them. I used the ROLL_OVER/MOUSE_OVER eventlistener to check if my mouse is over them or not. But with the data given by Ethan Kennerly I produced another way.
In Ethan Kennerly's solution, if your mouse enters the area of continent from a transparent area , it doesn't get blur effect because ROLL_OVER and MOUSE_OVER event listeners only trigger once per enters so I used MOUSE_MOVE event listener on each continent movieclips.
And for this statement:
if (isPixelTransparent(DisplayObject(event.currentTarget), new Point(stage.mouseX, stage.mouseY)) {
return;
}
add whatever is in the "ROLL_OUT or MOUSE_OUT" eventlistener function, add all of them inside this statement. But don't remove ROLL_OUT or MOUSE_OUT functions.
It sounds like the movie clip contains a shape that has transparent pixels. Transparent pixels respond to mouse over and roll over. If you could draw vector graphics that have no shapes with transparent pixels, the mouse would ignore the empty space in the movie clip's bounding box.
Yet it sounds like you need to use transparent pixels and you want the mouse to ignore them, so you could guard, like this:
private function onRollOver(event:MouseEvent):void
{
if (isPixelTransparent(DisplayObject(event.currentTarget), new Point(stage.mouseX, stage.mouseY)) {
return;
}
// respond to roll over.
}
To detect transparency, Miguel Santirso rendered the pixels and translated the coordinate space here: http://sourcecookbook.com/en/recipes/97/check-if-a-pixel-is-transparent-in-a-displayobject (Except line 38 looks on my computer like "rect" got rendered as "ct"). You could optimize that code by only drawing the pixel in question, instead of the whole image, and checking if that pixel value (getPixel32) is 0, instead of calling a hitTest. I would optimize Miguel's code like this:
public static function isPixelTransparent(objectOnStage:DisplayObject, globalPoint:Point):Boolean
{
var local:Point = objectOnStage.globalToLocal(globalPoint);
var matrix:Matrix = new Matrix();
matrix.translate(-local.x, -local.y);
var data:BitmapData = new BitmapData(1, 1, true, 0x00000000);
data.draw(object, matrix);
return 0x00000000 == data.getPixel32(0, 0);
}
By the way, if all your movie clips would have the same hit test shape, you could create a separate transparent shape that listens to the roll over. I use a transparent shape to define a custom hit test shape that is a consistent and simple shape (like a circle) when the image is a more complicate shape (like an X or an O with nothing in the middle). The custom hit test shape is a Sprite with a transparent shape. The sprite listens to the roll over. A separate mouse listener shape is also useful if your movie clip, on later frames, creates new shapes that alter the silhouette of the movie clip.
The easiest solution would be using the Interactive PNG class by Moses.
http://blog.mosessupposes.com/?p=40
Normally the clear areas of a PNG are treated as solid, which can be especially frustrating when dealing with a lot of images that overlap each other because they tend to block mouse interactions on the clips below them.
This utility fixes that so that mouse events don't occur until you
bump against a solid pixel, or a pixel of any transparency value
besides totally clear. InteractivePNG lets you set an alphaTolerance
level to determine what transparency level will register as a hit.
I have a custom cursor in my flash project. That cursor consists of several parts (i.e. several movie clips inside of the cursor movie clip). And when the cursor rolls over different movie clips in my project, the parts of the cursor distort a little bit as though moving 1 pixel in relation to each other. And therefore the look of the whole cursor distorts a little. This happens every time the cursor crosses the boundary between the movie clips of the project (buttons, design pieces and so on). How can I make my cursor always retain one and the same look?
Thanks in advance
I'm guessing you're doing something like this to position your custom cursor:
stage.addEventListener(MouseEvent.MOUSE_MOVE, moved);
function moved(e:MouseEvent):void {
customCursor.x = e.stageX;
customCursor.y = e.stageY;
}
If so, when you move the mouse over a MovieClip or other element, your listener is receiving the event from that DisplayObject rather than the Stage. For some reason, DisplayObjects positioned at sub pixel values produce e.stageX and e.stageY values which aren't exactly the same as stage.mouseX and stage.mouseY, so your custom cursor elements are jumping slightly as the pixel values round differently.
Try using the Stage mouse position directly instead:
stage.addEventListener(MouseEvent.MOUSE_MOVE, moved);
function moved(e:MouseEvent):void {
customCursor.x = stage.mouseX;
customCursor.y = stage.mouseY;
}
I have created a map of Europe in Flash using AS3. I am an absolute beginner. Each country has been converted into a movie (using lasso tool). These movies are on one layer (with slight outline visible) on main timeline. On the other main timeline layer is the original outline map of Europe.
I have managed to make it so when a country is rolled over, a box tweens in scale to full size (to later insert text in).
I need to make it so that when each country is rolled over, that country's text box (which appears on Roll_Over) comes 'to the front'.
At the moment a couple of countries' text boxes work perfectly (ie: filled with white and completely visible), but most are either buried beneath the main map, or threading randomly through the faint movie clip outlines (which are at the front).
I'm guessing that this has to do with the display list. The countries that work perfectly are probably at the top. But how do I make it so that the country rolled over immediately goes to the top and returns on Roll_Out?
This would complete my map so any help would be VERY MUCH appreciated.
I have used following code:
//FRAME ONE
this.stop();
movieClip_6.addEventListener(MouseEvent.ROLL_OVER, fl_MouseOverHandler_15);
function fl_MouseOverHandler_15(event:MouseEvent):void
{
gotoAndPlay(2);
}
movieClip_6.addEventListener(MouseEvent.ROLL_OUT, fl_MouseOutHandler_67);
function fl_MouseOutHandler_67(event:MouseEvent):void
{
gotoAndStop(1);
}
//SECTION BELOW IS MY PROBLEM
movieclip_6.addEventListener(MouseEvent.ROLL_OVER,Rollover,false,0,true);
function Rollover(event:MouseEvent): void
{
setChildIndex(MovieClip(e.target),this.numChildren-1);
}
Many thanks in advance.
You can try calling addChild() again to the DisplayObject/Movieclip to bring it to the front. Instead of:
setChildIndex(MovieClip(e.target),this.numChildren-1);
Try going:
addChild(MovieClip(e.target));
You can use "layers" to bring objects in front of another.
constructor:
//Create the front layer
var frontLayer:Sprite = new Sprite();
//put all text boxes into front layer
frontLayer.addChild(textbox1); //etc...
//Add layer to mc
addChild(frontLayer);
rollover pops up:
textbox1.visible = true;
pop down:
textbox1.visible = false;
I have this interactive 5 seconds animated intro for a website. the preloader and one item are animating and i made the second animation follow the mouse cursor but it has to stay within a certain part of the stage to work with the other animation happening on screen.
I have this code on the movie clip
Mouse.hide();
potistiri.addEventListener(Event.ENTER_FRAME, newCursor);
function newCursor(event:Event): void { potistiri.x = mouseX;
potistiri.y = mouseY; }
and i like i said i just want it to stay in the area i want...
i found this code which gives me errors for not putting the staments if and else if correctly or that it needs a rightparen when i input my numbers in...
if(this._x>Stage.width){
this._x=Stage.width;
}else if(this._x<0){
this._x=0; }
but i cant get it to work...
i need it to move between x 208-656 and y 140-336 and when it gets out of that area the object stay there doing its loop and you see the normal mouse cursor moving in the rest of the screen.
thanks a lot in advance...im leaving my it to the experts in here to pls help me ouy!
The logic you're using in your if/else is fine for clamping the movie clip to a specific area, what exactly do your errors say?
In regards to seeing the normal mouse cursor again you could try using the same if/else checks to determine whether the mouse should or should not be hidden ie if the mouse is outside the area and is hidden, call Mouse.show(), else if it is inside the area and shown, call Mouse.hide().
Pretty basic question here, but its still got me a little confused..
I have an object(navigation menu bar) that I want to change the colors on with code, so in an updateColor function, I get the bounds of the object (which is a drawing shape contained in a movieclip) and redraw a new shape on top of it with the new color, but I've noticed that the last shape still exists behind this redraw.
I tried using obj.graphics.clear(); before the redraw but that didn't get rid of the original shape. Is there another command that I'm overlooking?
Unless you drew the object you wish to remove within the same graphics object, clearing won't work. You need to remove the DisplayObject.
Depending on the number of children you can do:
obj.removeChildAt(0);
This also removes movieclips / buttons you placed on the stage manually.
If you have a reference to the DisplayObject you wish to remove you can simply do
obj.removeChild(backgroundClip);
Note that you can also change the color of a DisplayObject directly:
import flash.geom.ColorTransform;
...
public var test:MovieClip; //instance on stage
...
var cf:ColorTransform = test.transform.colorTransform;
cf.color = 0xff0000;
test.transform.colorTransform = cf;
while(this.numChildren)
{
this.removeChildAt(0);
}
Will clear child object on this MovieClip,
if it's clearing too much, then put the shape drawing in a subclip, and clear the subclip.