AS3 localToGlobal returning seemingly random x values - actionscript-3

I have a main timeline with a scroll bar. The sub timeline contains a long string featuring buttons. I am using localToGlobal to determine where the buttons are located on the stage so I can have relative information pop up on the left or right hand side of the button depending on where the pop out may fall on the stage. Everything seems to work until the scroll bar moves the timeline too much, then the x values traced seem to return random values.
Any idea on how to get a consistent result of x value that just shows where I click on the stage so I may tell the pop out to go right if it's too close to the left edge and left if it's too close to the right edge? I have the structure laid out it's just the x value on the main stage that seems to be wonky.
Here is the AS on the timeline.
stop();
import flash.events.MouseEvent;
import flash.geom.Point;
//attach listeners to all your buttons
btn19980930.addEventListener(MouseEvent.CLICK, showPopup);
btn20110928.addEventListener(MouseEvent.CLICK, showPopup);
btn20111214.addEventListener(MouseEvent.CLICK, showPopup);
btn20120110.addEventListener(MouseEvent.CLICK, showPopup);
//define space in the timeline movie clip
var leftEdge:Number=360;
function showPopup(evt:MouseEvent){
//figure out which button got clicked
var buttonClicked = evt.currentTarget;
//first get the local position of the button
var localPoint:Point = new Point(buttonClicked.x, buttonClicked.y);
//then calculate the buttons position in the global space
var buttonGlobalPoint:Point = buttonClicked.localToGlobal(localPoint);
trace(localPoint);
trace(buttonGlobalPoint);
if (buttonGlobalPoint.x < leftEdge){
gotoAndStop(buttonClicked.name + "_right");
} else {
gotoAndStop(buttonClicked.name + "_left");
}
}

You should be able to get the global coordinates of the mouse event with stageX and stageY:
var stageMousePoint:Point = new Point(evt.stageX, evt.stageY);

One thing that did finally work, although it's messy and overly bulky is to copy the section of script for each button to be able to give each button a different "leftEdge" parameter so even if the buttons vary in size and in anchoring, they react to a custom number. I know there is probably a way to condense the script but I am moving forward with what I know.
// button 01
//attach listeners to all your buttons
btn19980930.addEventListener(MouseEvent.CLICK, showPopup);
var leftEdge:Number=200;
function showPopup(evt:MouseEvent){
//figure out which button got clicked
//figure out which button got clicked
var buttonClicked = evt.currentTarget;
//first get the local position of the button
var stageMousePoint:Point = new Point(buttonClicked.stageX, buttonClicked.stageY);
//then calculate the buttons position in the global space
var buttonGlobalPoint:Point = buttonClicked.localToGlobal(localPoint);
//trace(localPoint);
trace(buttonGlobalPoint);
if (stageMousePoint.x < leftEdge){
gotoAndStop(buttonClicked.name + "_right");
} else {
gotoAndStop(buttonClicked.name + "_left");
}
}
// button 02
//attach listeners to all your buttons
btn19990224.addEventListener(MouseEvent.CLICK, showPopup);
var leftEdge2:Number=215;
function showPopup2(evt:MouseEvent){
//figure out which button got clicked
var buttonClicked2 = evt.currentTarget;
//first get the local position of the button
var localPoint2:Point = new Point(buttonClicked2.x, buttonClicked2.y);
//then calculate the buttons position in the global space
var buttonGlobalPoint2:Point = buttonClicked2.localToGlobal(localPoint2);
//trace(localPoint);
trace(buttonGlobalPoint2);
if (buttonGlobalPoint2.x < leftEdge2){
gotoAndStop(buttonClicked2.name + "_right");
} else {
gotoAndStop(buttonClicked2.name + "_left");
}
}

Even better, Cadin hinted in the correct direction of using the mouse, but rather than worrying about where the mouse is exactly i only needed to know if the mouse was on the left or the right side of the screen within a certain threshold. The i could decide which side the popout would appear.
stop();
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.display.MovieClip;
import flash.display.DisplayObject;
//attach listeners to all your buttons
btn19980930.addEventListener(MouseEvent.CLICK, showPopup);
btn19990224.addEventListener(MouseEvent.CLICK, showPopup);
btn20010105.addEventListener(MouseEvent.CLICK, showPopup);
btn20050702.addEventListener(MouseEvent.CLICK, showPopup);
btn20060000.addEventListener(MouseEvent.CLICK, showPopup);
btn20060629.addEventListener(MouseEvent.CLICK, showPopup);
btn200720080000.addEventListener(MouseEvent.CLICK, showPopup);
btn20080229.addEventListener(MouseEvent.CLICK, showPopup);
btn20090307.addEventListener(MouseEvent.CLICK, showPopup);
btn20091209.addEventListener(MouseEvent.CLICK, showPopup);
btn20101125.addEventListener(MouseEvent.CLICK, showPopup);
btn20110120.addEventListener(MouseEvent.CLICK, showPopup);
btn20110312.addEventListener(MouseEvent.CLICK, showPopup);
btn20110729.addEventListener(MouseEvent.CLICK, showPopup);
btn20110316.addEventListener(MouseEvent.CLICK, showPopup);
btn20110815.addEventListener(MouseEvent.CLICK, showPopup);
btn20110909.addEventListener(MouseEvent.CLICK, showPopup);
btn20110928.addEventListener(MouseEvent.CLICK, showPopup);
btn20111214.addEventListener(MouseEvent.CLICK, showPopup);
btn20120110.addEventListener(MouseEvent.CLICK, showPopup);
var initialX : Number = 496;
function showPopup(evt:MouseEvent){
//figure out which button got clicked
var buttonClicked = evt.currentTarget;
// not finished, we need to calculate using timeline_mc x and width
if (stage.mouseX <= 400){
gotoAndStop(buttonClicked.name + "_right");
} else {
gotoAndStop(buttonClicked.name + "_left");
}
}

Related

How to move the character up when touched the stage in ActionScript 3

I am new to ActionScript 3 and yes it is quite interesting. But I have got a problem with touch event.
I have already coded for the character (bird) to move forward and down at each frame and now I need to insert a function to move the bird upwards when tapping on the screen. I have tried it with an example in this url - https://help.adobe.com/en_US/as3/dev/WS1ca064e08d7aa93023c59dfc1257b16a3d6-7ffe.html
But still nothing happens. Please help me.
My code is as below.
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.ui.Multitouch;
Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT;
public class MyBirdy extends MovieClip{
public var bird: Birdy;
public var sky: Background;
public var sky2: Background;
public var birdinsky: MovieClip;
public var skyBreadth:Number;
public function MyBirdy(){
bird = new Birdy();
sky = new Background();
sky2 = new Background();
skyBreadth = 1453.15;
sky.x = 730;
sky.y = 360;
bird.x = 100;
bird.y = 340;
sky2.x = sky.x + skyBreadth;
sky2.y = sky.y;
birdinsky = new MovieClip();
birdinsky.addChild(sky);
birdinsky.addChild(sky2);
birdinsky.addChild(bird);
stage.addChild(birdinsky);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function onEnterFrame(e:Event):void{
bird.x += 4;
birdinsky.x = 100 - bird.x;
bird.y += 2
if(sky.x + skyBreadth + birdinsky.x < 700){
sky.x = sky.x + (2 * skyBreadth);
}
if(sky2.x + skyBreadth + birdinsky.x < 700){
sky2.x = sky2.x + (2 * skyBreadth);
}
birdinsky.addEventListener(TouchEvent.TOUCH_TAP, onTap);
}
function onTap(e:TouchEvent): void {
bird.y -= 2;
//I want my bird to fly up when tapped!
}
}
The reason it doesn't work, is because your tap movement is always going to be negated by the movement in the enter frame handler. e.g. you tap, which moves the bird up 2 pixels, but then on the next frame tick of your application (when you'd see the visual change) you move the bird down again 2 pixels in onEnterFrame - which runs every frame tick.
Here is a way to do what you'd like:
Take this line, and remove it completely (or if you actually want a tap and not a hold, move it out of the onEnterFrame method and into your constructor - you don't want to add a listener over and over again every frame)
birdinsky.addEventListener(TouchEvent.TOUCH_TAP, onTap);
If you don't need multiple simultaneous touch support, it would be simpler to use mouse events. remove this line if switching to mouse events instead of touch (though you could still use touch if you'd like):
Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT;
In your constructor function (MyBirdy) add the following lines to listen for the mouse up and down events:
As suggested in the comments, you should listen on the stage for the mouse down (or touch begin) if you want a press anywhere on the screen to work
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); //or TouchEvent.TOUCH_BEGIN
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); //or TouchEvent.TOUCH_END
Then create the handler functions for those listeners, as well as a var to track the mouse button state:
private var isMouseDown:Boolean = false;
private function onMouseDown(e:Event):void {
isMouseDown = true;
}
private function onMouseUp(e:Event):void {
isMouseDown = false;
}
With the above you now have a var (isMouseDown) that will be set to true when the mouse is down, and false when the mouse is up. Remember that mouse here is also the same of a finger press/hold.
Now, inside your enter frame handler (onEnterFrame), add the following:
remove the line bird.y += 2.
Add:
if(isMouseDown){
bird.y -= 2; //move the bird up, as the screen is being pressed/clicked
}else{
bird.y += 2 //move the bird down
}
Now, instead of a single tap event, any frame where the mouse is down (or a press and hold) the bird will move up instead of down.

Actionscript 3 - How do I make new instances draggable?

I am attempting to build a drag and drop game where a user can build something using the images I provide. I will have images in a menu that the user can click and drag to the building area. The user will be able to add however many instances of that image as they want.
I was able to get part of it working. So far, I can click the image and drag it around, and create as many instances as I want. However, I cannot click and drag the image once I have placed it.
When I do a trace to see what the name is, it says that all the new instances are named hillChild1. I tried to make them named hillChild1, hillChild2, etc., but that doesn't seem to work either... not sure that is an issue, though.
Here's my code:
thesubmenu1.hill.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
var myImage:Sprite = Sprite(new Hill_mc());
var i:Number=0; i++;
function onDown(e:MouseEvent):void {
var myImage:Sprite = Sprite(new Hill_mc());
myImage.name = "hillChild"+i;
addChild(myImage);
myImage.x = mouseX;
myImage.y = mouseY;
myImage.startDrag();
myImage.buttonMode = true;
}
function onUp(e:MouseEvent):void {
var myImage:Sprite = Sprite(new Hill_mc());
myImage.stopDrag();
myImage.name = "hillChild";
}
stage.addEventListener(MouseEvent.CLICK, traceName);
function traceName(event:MouseEvent):void { trace(event.target.name); }
myImage.getChild(myImage).addEventListener("mouseDown", mouseDownHandler);
stage.addEventListener("mouseUp", mouseUpHandler);
function mouseDownHandler (e:MouseEvent):void{
myImage.startDrag();
}
function mouseUpHandler (e:MouseEvent):void{
myImage.stopDrag();
}
I am new to StackOverflow and also Actionscript 3, if it isn't apparent.
Your issue is likely that you are creating a new instance on mouse up (when what you want is a reference to instance that was already created on mouse down). Also, you never add a click listener to you new objects. Add the mouse up listener to stage only after the mouse down (then remove the listener in the mouse up).
thesubmenu1.hill.addEventListener(MouseEvent.MOUSE_DOWN, createCopy);
var i:int=0;
var tmpImage:Sprite; //to store which image is being dragged currently
function createCopy(e:MouseEvent):void {
tmpImage = new Hill_mc();
tmpImage.name = "hillChild"+(i++); //increment every copy
addChild(tmpImage);
tmpImage.x = mouseX;
tmpImage.y = mouseY;
tmpImage.startDrag();
tmpImage.buttonMode = true;
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); //add the mouse down to this new object
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //since the mouse is currently down, we need to listen for mouse up to tell the current copy to stop dragging
}
//this will be called when click a copy
function onDown(e:MouseEvent):void {
tmpImage = Sprite(e.currentTarget); //get a reference to the one that was clicked, so we know which object to stop dragging on the global mouse up.
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //listen for the mouse up
tmpImage.startDrag();
}
function onUp(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP,onUp); //now that the mouse is released, stop listening for mouse up
tmpImage.stopDrag(); //stop dragging the one that was clicked
}

Buttons within Movieclip AS3 not working

I'm relatively new to flash and as3. Basically I'm trying to load a movieclip to the stage and then click a button within that movieclip to remove the child again from the stage. I have the following movieclip:
var myResultBox:ResultBox = new ResultBox();
addChild(myResultBox);
I have a button placed within the movieclip called closeButton1. I am trying to click the close button which in turn removes the movieclip.
the code within the MovieClip is -
//Event Listener for Close button within my results box
closeButton1.addEventListener(MouseEvent.CLICK, closeBMI);
function closeBMI(evt:MouseEvent):void
{
removeChild(myResultBox);
}
Following error
code: 1120: Access of undefined property closeButton1.
Any help would be most appreciated
Below is a simple program which i think has the functionality of what you are asking for. As far as I understand, you have button A on the stage. When you click button A, movie clip B is added to the stage. Movie clip B has button B in it. When you click button B, Movie clip B and button B are removed.
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
// This creates a movie clip that contains a button.
// This button will remove the movie clip that contains
// it when it is clicked.
var MovieClipB = new MovieClip();
MovieClipB.graphics.lineStyle(1,0);
MovieClipB.graphics.beginFill(0x0000FF,1);
MovieClipB.graphics.drawRect(0,0,50,50);
var ButtonB:MovieClip = new MovieClip();
ButtonB.buttonMode = true;
ButtonB.graphics.lineStyle(1,0);
ButtonB.graphics.beginFill(0xFFFFFF,1)
ButtonB.graphics.drawCircle(0,0,10);
ButtonB.x = ButtonB.y = 25;
MovieClipB.addChild(ButtonB);
ButtonB.addEventListener(MouseEvent.CLICK, removeButtonClickHandler, false, 0, true);
function removeButtonClickHandler(event:MouseEvent):void
{
var button = MovieClip(event.currentTarget);
var container = button.parent;
container.parent.removeChild(container);
}
// This creates a button that starts on the stage.
// When clicked, it adds the movie clip defined above to the stage
var ButtonA:MovieClip = new MovieClip();
ButtonA.buttonMode = true;
ButtonA.graphics.lineStyle(1,0);
ButtonA.graphics.beginFill(0xFF0000,1)
ButtonA.graphics.drawRect(0,0,50,50);
addChild(ButtonA);
ButtonA.x = ButtonA.y = 20;
ButtonA.addEventListener(MouseEvent.CLICK, addButtonClickHandler, false, 0, true);
function addButtonClickHandler(event:MouseEvent) : void
{
addChild(MovieClipB);
MovieClipB.x = 200;
MovieClipB.y = 20;
}
Within the button? But you can't reference button in such way. You should put your code within movieclip that holds button, where you add result addChild(myResultBox); So your event handler will be able reference myResultBox
For code within a button:
this.addEventListener(MouseEvent.CLICK, closeBMI);
function closeBMI(evt:MouseEvent):void
{
//removeChild(myResultBox);
//Sadly, you don't have reference on myResultBox within a button...
}

Flash AS3 rollover and button with ClickTag

I have a banner with a ClickTag and a hover function.
My problem is that that the user can't click on the button because of the hover function.
My code is for the ClickTag:
knap1.addEventListener(MouseEvent.CLICK, ADFclicked);
function ADFclicked(event:MouseEvent) { AdfURLNavigator.navigateToUrl( AdfFlashVarsUtil.getParameter("clickTAG"), AdfFlashVarsUtil.getParameter("landingPageTarget")); }
And for the hover function:
var holder:MovieClip = new MovieClip();
btn.addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
btn.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
btn.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
function mouseOverHandler(e:MouseEvent):void{
//creating a new tooltip instance
var tooltip:Tooltip = new Tooltip();
//we tell the holder to hold our tooltip
holder = tooltip;
//positioning the tooltip on the stage
holder.x = 190;
holder.y = 280;
//adding the tooltip to the stage
addChild(tooltip);
}
function mouseOutHandler(e:MouseEvent):void{
//we remove the holder when the cursor is outside our button
removeChild(holder);
}
function mouseMoveHandler(e:MouseEvent):void{
holder.x = 190;
holder.y = 280;
}
Can anybody help?
I would assume, not seeing the entire code, that btn object is covering knap1 object so you cannot click on anything that is beneath btn.
If you want to have hover function over whole banner try using MOUSE_LEAVE event to detect mouse leaving and them MOUSE_MOVE to track if mouse is back on flash object after leaving it. As for MOUSE_MOVE event you can add listener to stage to detect mouse movement without any additional containers.
Hey you are using mousevent for hover & click at one time. So better remove addeventlistener & write the mouseover in button as inline.

How do I stop a function of a parent movieclip when in a child of that parents?

Help!!
I have a piece of code on a mc that when the mouse is dragged it plays through that movie clip, giving a 360 spin of a product.
Inside this movieclip on different increments of the 360 spin i have child movieclips with various other animations to relate to each angle of the product.
exp..
Scene 1 > spinY_mc > AWComplete_mc
My code for the spin is written within the actions in scene1 and controls spinY_mc but once im in AWComplete_mc i do not want you to be able to drag the mouse and spin?
Im sure this is simple but im a noob at all this and am taking on a mammoth project!
Here is the code used on the movieclip (spinY_mc) I dont want this code to work when inside of its child mc (AWComplete_mc).
// Rotation of Control Body Y
spin_Y.stop();
spin_Y.buttonMode = true;
var spin_Y:MovieClip;
var offsetFrame:int = spin_Y.currentFrame;
var offsetY:Number = 0;
var percent:Number = 0;
spin_Y.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
spin_Y.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
function startDragging(e:MouseEvent):void
{
// start listening for mouse movement
spin_Y.addEventListener(MouseEvent.MOUSE_MOVE,drag);
offsetY = stage.mouseY;
}
function stopDragging(e:MouseEvent):void
{
// STOP listening for mouse movement
spin_Y.removeEventListener(MouseEvent.MOUSE_MOVE,drag);
// save the current frame number;
offsetFrame = spin_Y.currentFrame;
}
// this function is called continuously while the mouse is being dragged
function drag(e:MouseEvent):void
{
// work out how far the mouse has been dragged, relative to the width of the spin_Y
// value between -1 and +1
percent = (mouseY - offsetY) / spin_Y.height;
// trace(percent);
// work out which frame to go to. offsetFrame is the frame we started from
var frame:int = Math.round(percent * spin_Y.totalFrames) + offsetFrame;
// reset when hitting the END of the spin_Y timeline
while (frame > spin_Y.totalFrames)
{
frame -= spin_Y.totalFrames;
}
// reset when hitting the START of the spin_Y timeline
while (frame <= 0)
{
frame += spin_Y.totalFrames;
}
// go to the correct frame
spin_Y.gotoAndStop(frame);
}
I'm pretty sure you just want to stop the propagation of an event from the child so it doesn't make it out to the parent. If you add a listener for the event you want to block (lets say it's mouseDown you want to block).
child_mc.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownBlocker);
private function mouseDownBlocker(event:MouseEvent):void
{
event.stopImmediatePropagation();
}
The way events work is they start at the "deepeest" child which the mouse has a hit event with, then they "bubble" up through all the parents. By stopping the propagation you block the bubbling from occurring, so the parents never get the event.