Issue with MOUSE_MOVE and MOUSE_OUT applied to stage - actionscript-3

I'm having an issue with MOUSE_OUT being called while it shouldn't. What I'm doing is quite simple: two images are shown when I move the mouse across the stage, and when the mouse leaves the stage they are hidden.
The problem is, that whenever the mouse hits the border of any movieclip on the stage, the MOUSE_OUT function gets called, hiding the two images. This means that whenever I move the mouse
My code (only the relevant parts are shown):
public class Slider extends MovieClip {
var img1:Img1 = new Img1;
var img2:Img2 = new Img2;
var img1_hover:Img1_hover = new Img1_hover;
var img2_hover:Img2_hover = new Img2_hover;
public function Slider() {
img1.alpha = 0;
img2.alpha = 0;
stage.addEventListener(MouseEvent.MOUSE_MOVE, showArrows);
}
function showArrows(e:MouseEvent) {
img1.alpha = 1;
img2.alpha = 1;
stage.addEventListener(MouseEvent.MOUSE_OUT, hideArrows);
}
function hideArrows(e:MouseEvent) {
img1.alpha = 0;
img2.alpha = 0;
}
}
Flash throws no errors. I am using a separate .as file (just one) and have no code inside of the action panel in the .fla.
Where there's stage.addEventListener, I also tried this., root. and nothing instead of stage.

You want to use the MOUSE_LEAVE event instead http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Stage.html#event:mouseLeave
Alternatively, in the hideArrows function you can check the target of the event:
function hideArrows(e:MouseEvent) {
If(e.target == stage){
img1.alpha = 0;
img2.alpha = 0;
}
}

Related

Flash AS3 MouseOver not working

I am having trouble getting a MOUSE_OVER event to fire consistently and as intended. I have a custom cursor (movieclip) attached to my mouse and it has 2 frames (1st frame cursor is black and second frame it is white).
Here is code from my cursor script:
private function onAddedToStage(event:Event):void
{
gotoAndStop(1);
this.mouseChildren = false;
this.mouseEnabled = false;
}
public function rollover():void
{
gotoAndStop(2);
trace("change cursor");
}
Here is the class for an object that will react when the cursor moves over it:
public class DoorHS01 extends MovieClip
{
public var cursor:Cursor;
public function DoorHS01()
{
cursor = new Cursor();
this.addEventListener(MouseEvent.MOUSE_OVER, rollover);
}
public function rollover(e:MouseEvent):void
{
cursor.rollover();
trace("rollover");
}
}
}
So in the DoorHS01 class the MouseEvent doesn't always fire or it will be really delayed. The cursor.rollever function gets called and it executes in the cursor class (I know from the traces) but the cursor never changes.
What am I missing?
I decided that the best way to achieve what I wanted was to test collision with my custom cursor rather than creating classes for everything object that needed a rollover function. I also currently do not know how many objects will require this rollover functionality as the designer I'm working with is still working out the game details so it is going to be easier to just add what is needed to an array when needed. I ended up going with this:
for (var i:int = 0; i < _hotSpotArr.length; i++)
{
if (cursor.hitTestObject(_hotSpotArr[i]))
{
cursor.gotoAndStop(2);
break;
}
else
{
cursor.gotoAndStop(1);
}
}

Timeline Seekbar in AS3

I'm trying a flash actionscript project to include a custom seekbar for timeline frame navigation. Now i could get dragger moving across the seekbar with respect to the totalframes. But dragging the seekbar brings error. Also i want to include timer to show the minute and seconds passed.
var ratio = 0;
ratio = this.totalFrames/main.line.width;
var go = 0;
var isComplete = false;
var tFrame = this.totalFrames;
var isPress = false;
stage.addEventListener(Event.ENTER_FRAME, drag);
function drag(event:Event):void {
if(main.dragger.x<=main.line.width){
main.dragger.x = this.currentFrame/ratio;
}
}
main.dragger.addEventListener(MouseEvent.MOUSE_DOWN, drag1);
function drag1(event:MouseEvent):void {
main.dragger.startDrag(false, new Rectangle(0, 9.2, main.line.width, 9.2));
isPress = true;
main.dragger.addEventListener(Event.ENTER_FRAME, frame);
}
function frame(event:Event):void
{
trace (this.currentFrame);
if(this.currentFrame < tFrame){
gotoAndPlay(Math.round(main.x*ratio));
}else{
gotoAndPlay(tFrame-1);
}
}
main.dragger.addEventListener(MouseEvent.MOUSE_UP,release);
function release(event:MouseEvent):void {
main.dragger.stopDrag();
main.dragger.removeEventListener(MouseEvent.MOUSE_DOWN, drag1);
}
when i click the dragger to move, it automatically jumps to starting position and also the gotoAndPlay jumps to that position and continuously stays there..
Attachment:
https://drive.google.com/open?id=0B4UOEUQTrhB0a21EaUpaUE52MGM
UPDATE
This is an other method found in adobe forum, But this also gives the same dragging problem.
var tl:MovieClip=this;
tl.addEventListener(Event.ENTER_FRAME,enterframeF);
paramF(tl,1,0,tl.totalFrames,slider.line.width); // create a horizontal slider movieclip that contains a track movieclip and a thumbscroll movieclip that do the obvious and have left-sided reg point
paramF(slider,0,1,slider.line.width-slider.thumbscroll.width,tl.totalFrames);
var scrollRect1:Rectangle=new Rectangle(0,0,slider.line.width-slider.thumbscroll.width,0);
function enterframeF(e:Event):void{
slider.thumbscroll.x=tl.m*tl.currentFrame+tl.b;
}
slider.thumbscroll.addEventListener(MouseEvent.MOUSE_DOWN,scrolldownF);
slider.thumbscroll.addEventListener(MouseEvent.MOUSE_UP,scrollupF);
function scrolldownF(e:MouseEvent):void{
tl.removeEventListener(Event.ENTER_FRAME,enterframeF);
slider.thumbscroll.startDrag(false,scrollRect1);
slider.addEventListener(Event.ENTER_FRAME,scrollF);
}
function scrollupF(e:MouseEvent):void{
tl.addEventListener(Event.ENTER_FRAME,enterframeF);
slider.thumbscroll.stopDrag();
slider.removeEventListener(Event.ENTER_FRAME,scrollF);
}
function scrollF(e:MouseEvent):void{
tl.gotoAndStop(Math.round(slider.thumbscroll.x*slider.m+slider.b));
}
function paramF(mc:MovieClip,x1:Number,y1:Number,x2:Number,y2:Number):void{
mc.m=(y1-y2)/(x1-x2);
mc.b=y2-mc.m*x2;
}

scrollable activity in as3 is not working perfect for android air

i want to make a scrollable index of particular math book for android version where i will be able to scroll a movie clip consists of 56 child movieclips(there are chapter 1 to chapter 56 child clips has made "buttons_all" parentclip) and when i will choose a child movie clip it will go to selected label or chapter(suppose if i click chapter 1 movie clip it will gotoAndPlay("chapter 1")).i had made the parent movieclip scrollable and added eventlistener to each child movie clip..but when i want to scroll it is doing two things,first it scrolls then go to that "chapter" that i clicked to start scrolling whether i want to go this chapter or not.to solve that i added a timer event to create an interval to stop selecting chapter immediately before i want to select a specific chapter..but it is working partially.i want to add this interval to every button.because i dont have a scrollbar here for up and down..please help me to solve this..here is my part of code
var pat1:MovieClip = scrolling_manu.buttons_all.part1;
var listTimer:Timer; // timer for all events
var tapDelayTime:Number = 0;
var maxTapDelayTime:Number = 20; // change this to increase or descrease tap sensitivity
var tapEnabled:Boolean = false;
init();
function init()
{
//removeEventListener(Event.ADDED_TO_STAGE, init);
pat1.addEventListener(TouchEvent.TOUCH_BEGIN, onmouseDown );
//trace("hit");
pat1.addEventListener(TouchEvent.TOUCH_END, onmouseUp );
listTimer = new Timer( 33 );
listTimer.addEventListener( TimerEvent.TIMER, onListTimer);
listTimer.start();
}
function onmouseDown( e:TouchEvent ):void
{
handleItemPress()
}
function onmouseUp( e:TouchEvent ):void
{
onTapDisabled();
//listTimer.stop();
}
function onListTimer(e:Event):void
{
// test for touch or tap event
if(tapEnabled)
onTapDelay();
}
function onTapDisabled():void
{
tapEnabled = false;
tapDelayTime = 0;
}
function onTapDelay():void
{
tapDelayTime++;
if(tapDelayTime > maxTapDelayTime )
{
//tapItem.selectItem();
tapDelayTime = 0;
tapEnabled = false;
trace("hit");
pat1.gotoAndPlay("over1");
pat1.addEventListener(TouchEvent.TOUCH_END, onmouseUp );
}
}
function handleItemPress()
{
tapDelayTime = 0;
tapEnabled = true;
trace("hit");
}
Firstly, I recommend you to convert all vector images to raster. It's very hard for processor to animate vector images.
Delete all code after drop_me function.
Write this:
scrolling_manu.buttons_all.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
scrolling_manu.buttons_all.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
var touchedPart:MovieClip;
var posY:int;
function onTouchBegin(event:TouchEvent):void
{
touchedPart = event.target as MovieClip;
posY = scrolling_manu.buttons_all.y;
}
function onTouchEnd(event:TouchEvent):void
{
// if list was been moved, that isn't a tap.
if (posY == scrolling_manu.buttons_all.y)
{
trace("part tapped", touchedPart.name);
touchedPart.gotoAndPlay("over1");
}
}

ActionScripting Issue: adding/removing children

I have three movie clips all linked to the stage and I want them to behave like a button/ But I am not using a button because I have not found a way to have each part (up, over, down, hit) be animated and not just change when the mouse is in use with it. So far I have been able to have all three appear on my stage and show when I have the mouse over and as well when I click, but I think I'm doing something wrong with removeChild. Each MC should appear one at a time and now all three show up when I hover over and seem to "flash". Here's my code:
var mainMoon:swayingMoon = new swayingMoon();
mainMoon.x = 50;
mainMoon.y = 10;
addChild(mainMoon);
var hoverMoon:glowMoon = new glowMoon();
hoverMoon.x = 50;
hoverMoon.y = 10;
var movieMoon:clickedMoon = new clickedMoon();
movieMoon.x = 50;
movieMoon.y = 10;
mainMoon.addEventListener(MouseEvent.ROLL_OVER, showHoverMoon);
mainMoon.addEventListener(MouseEvent.ROLL_OUT, hideHoverMoon);
hoverMoon.addEventListener(MouseEvent.CLICK, startMovieMoon)
function showHoverMoon(event:MouseEvent):void
{
addChild(hoverMoon);
}
function hideHoverMoon(event:MouseEvent):void
{
removeChild(hoverMoon)
}
function startMovieMoon(event:MouseEvent):void
{
addChild(movieMoon);
}
I don't recommend doing it this way as it can make things needlessly complex. For a single button now, you have 3 times as many movie clips/sprites, add/remove child event handlers, and other variables to check/debug for. Multiply this by however many buttons you have.
Instead, I'd recommend using or extending the SimpleButton{} class or writing your own class to encapsulate the behaviour.
SimpleButton class: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/SimpleButton.html
I think you should encapsulate your three moon states into a separate MovieClip that will control all the moon phase changing by itself. If it's already so, fine. The general principle with such a MovieClip-Button type objects is that the listener is assigned to the parent instance, not the parts of that button.
public class Moon extends Sprite {
private var upState:swayingMoon=new swayingMoon();
private var overState:glowMoon=new glowMoon();
private var downState:clickedMoon=new clickedMoon();
private var areWeClicked:Boolean;
private var areWeOver:Boolean;
public function Moon() {
areWeClicked=false;
areWeOver=false;
addChild(upState);
addEventListener(MouseEvent.ROLL_OVER, showHoverMoon);
addEventListener(MouseEvent.ROLL_OUT, hideHoverMoon);
addEventListener(MouseEvent.CLICK, showClickedMoon);
addEventListener(Event.COMPLETE, hideClickedMoon);
}
private function showHoverMoon(e:MouseEvent):void {
areWeOver=true;
if (areWeClicked) return;
removeChild(upState);
addChild(overState);
}
private function hideHoverMoon(e:MouseEvent):void {
areWeOver=false;
if (areWeClicked) return;
removeChild(overState);
addChild(upState);
}
private function showClickedMoon(e:MouseEvent):void {
if (areWeClicked) {
downState.gotoAndPlay(1);
return;
}
if (overState.parent) removeChild(overState); else removeChild(upState);
addChild(downState);
downState.gotoAndPlay(1); // your clicked moon seems to be a playing MC, so starting it over
areWeClicked=true;
}
private function hideClickedMoon(e:Event):void {
if (e.target!=downState) return; // not our event
if (!areWeClicked) return;
areWeClicked=false;
removeChild(downState);
if (areWeOver) addChild(overState); else addChild(upState);
}
}
Now, your parent class is controlling what happens and when. I was under assumption that your clickedMoon MC will only play once fully, then dispatch an event Event.COMPLETE to itself, so that its parent will get notified and will act.
Originally, your event listener structure prevented you from hiding mainMoon MC, otherwise your other listener will never act, now you are using parent object to listen to events, and can safely remove parts of your moon.
Just for a custom button you are going too much complex way. one movieClip is enough for create the button. First create a movieClip and inside that movieClip's timeline create two more frame for 'hover' and click effect. here is little bit of code to start.
var myButton_btn:CustomButton = new CustomButton();
addChild(myButton_btn);
myButton_btn.x = 100;
myButton_btn.y = 100;
myButton_btn.addEventListener(MouseEvent.ROLL_OVER, onOver);
myButton_btn.addEventListener(MouseEvent.ROLL_OUT, onOut);
myButton_btn.addEventListener(MouseEvent.CLICK, onClick);
function onOver(event:MouseEvent):void {
//trace('over');
event.target.gotoAndStop('hover');
}
function onOut(event:MouseEvent):void {
//trace('normal');
event.target.gotoAndStop('normal');
}
function onClick(event:MouseEvent):void {
//trace('click');
event.target.gotoAndStop('click');
}

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.