How to do "if Single Click" instead of "if MouseDown" in AS3? - actionscript-3

I want to do a single click and have it not repeat the function if my mouse is still down if that makes any sense.
Currently I have it:
if (mouseDown)
{
avatar.moveABit( 0, -2);
sfxSoundChannel = moveSound.play();
}
and if I keep my Mouse Down it keeps repeating that. I want it to only work with a single click, and have to keep tapping to do it instead of leaving the mouse down.

You probably want
MouseEvent.MOUSE_CLICK
I would add an event listener on the object that is being clicked to listen for the click, and on the click run the handler function which would contain your move and soundplay code.
See this documentation.

You need MouseEvent.CLICK like so:
//Create a function (which moves avatar) to be called on mouse click
function moveAvatar(e:MouseEvent):void
{
avatar.moveABit( 0, -2);
sfxSoundChannel = moveSound.play();
}
stage.addEventListener(MouseEvent.CLICK, moveAvatar); //add mouse click event listener
EDIT: moveABit should not be using ENTER_FRAME event.

I don't know if I understood it correctly, maybe we'll need more of your code to understand what you really want.
I'm assuming that you're using some kind of loop (setInterval, Event.ENTER_FRAME) to check if the mouse button is down or not. If you are, I think you should change that to only fire inside a function like this:
function OnMouseDownHandler(event:MouseEvent):void
{
avatar.moveABit( 0, -2);
sfxSoundChannel = moveSound.play();
}
stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDownHandler, false, 0, true);
If you use MouseEvent.CLICK event the OnMouseDownHandler Method will be fired only when you release the mouse button, using MouseEvent.MOUSE_DOWN will behave more like a "Tap".

Related

Why doesn't stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, true) work?

I want to listen to stage for keyboard event, and I want to catch an event directly when it appears (not in bubbling or target). Why can't I do this?
Actually it seems that I can't use useCapture for keyboard events at all.
I want to open my inner console window by pressing tilda button, and change focus to input field. So, I wrote something like this
public function init(stage:Stage):void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
}
private function onStageKeyDown(event:KeyboardEvent):void
{
event.stopImmediatePropagation();
switch(event.keyCode)
{
case Keyboard.BACKQUOTE:
visible = !visible;
stage.focus = visible ? inputField : stage;
break;
}
}
The problem is, it writes "`" character in my input, which I don't want it to do. So, I decided to try to listen to keyboard event in capture phase to stop its propagation. But it seems that stage can't have capture phase, because there is no nodes before it. How can I handle that situation properly?
To simply answer your question, you can listen for keyboard events on the capture phase.
Most likely, the reason you can't, is because nothing has focus. If nothing has focus in your application then the stage will not get a keyboard event. By default, when a swf runs nothing has focus.
Give an item focus when your application starts (anything besides the stage itself), and the event will come.
public function init(stage:Stage):void
{
stage.focus = this; //assuming this is the document class
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown, true);
}
Now, to follow up with what you are actually trying to accomplish (aside from your actual question) all you need to do is listen for the right event (TEXT_INPUT). Your answer is close, but it can be much simpler without the need for flags or a key down listener:
stage.focus = this; //give something focus, probably not needed if you have to click the text input in order to input text
//listen on the capture phase for text input
stage.addEventListener(TextEvent.TEXT_INPUT, onStageTextInput, true);
function onStageTextInput(event:TextEvent):void
{
switch(event.text)
{
//if the new text was a backquote or # sign, don't let the event trigger it's normal action
case "`":
case "#":
event.preventDefault(); //prevent default is needed
break;
}
}
I finally found a workaround for this problem.
First of all: handling and stopping KeyboardEvent.KEY_DOWN is NOT preventing TextField from getting input. That's sad because in this case it would be useful, but it seems there is some other reasons for not doing this.
So, what I should do is listen for TextEvent.TEXT_INPUT by inputField
inputField.addEventListener(TextEvent.TEXT_INPUT, onTextInput);
and listen to KeyboardEvent.KEY_DOWN by stage
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
in case I may still want to put tilda of backquote signs in my TextField (for example by coping and pasting them) I decided to use a flag
private function onStageKeyDown(event:KeyboardEvent):void
{
switch(event.keyCode)
{
case Keyboard.BACKQUOTE:
...
inAction = true;
break;
}
}
so when TextEvent.TEXT_INPUTevent fires I can see if that was opening window action or not. And if it is, then preventDefault() behaviour, which means NOT inputting received sign in TextField
private function onTextInput(event:TextEvent):void
{
if(inAction)
{
event.preventDefault();
inAction = false;
}
}

MOUSE OUT is being called inside MovieClip

I added a MOUSE_OVER event listener to my MovieClip, then i added MOUSE_OUT just like this :
mc.addEventListener(MouseEvent.MOUSE_OVER, boxItemMouseOver, false, 0, true);
protected function boxItemMouseOver(e:MouseEvent):void
{
trace("mouse over");
var boxItem:MovieClip = e.currentTarget as MovieClip;
boxItem.addEventListener(MouseEvent.MOUSE_OUT, boxItemMouseOut, false, 0, true);
boxItem.removeEventListener(MouseEvent.MOUSE_OVER, boxItemMouseOver);
}
protected function boxItemMouseOut(e:MouseEvent):void
{
trace("mouse out");
var boxItem:MovieClip = e.currentTarget as MovieClip;
boxItem.addEventListener(MouseEvent.MOUSE_OVER, boxItemMouseOver, false, 0, true);
boxItem.removeEventListener(MouseEvent.MOUSE_OUT, boxItemMouseOut);
}
But whenever i move the mouse inside my MovieClip, the MOUSE_OUT event function is being called, although i still didn't leave the area taken by the MovieClip.
I managed to find out where my Problem is, but still can't fix it, i'm adding to my SWF a Cursor that replaces the icon of the mouse (I hide the mouse), once i add it the problem occurs, here is a simple example.
Code : Simple Source Code, Couple of classes
Set mouseChildren to false on boxItem.
1.. u have 'trace("mouse over")' in both functions
2.. first remove mouse over listener, than add mouse out listener
3.. i don't get, why do u need to declare new variable 'boxItem' when u can just write e.target.removeEventListener(..)
4.. it's impossible what u are talking, i caught several unnecessary code in few lines, so there is big chance u are doing somth wrong in your code, show us bigger piece of your code..
p.s. also, try mouseEnabled to false along with mouseChildren to false, but i doubt it will work
Listen for ROLL_OUT instead. MOUSE_OUT is dispatched when cursor left any of the nested chidlren of you MovieClip.

AS3 - Button inside MovieClip triggers MC's event

On stage, I have a MovieClip named "mc" with a simple rectangle drawn inside. mc also has a Button child named "btn" which is another simple rectangle ( smaller than mc's rectangle obviously). Then I have this code on stage.
function mcDown( _e:MouseEvent):void{
trace( "mc" );
}
function btnClick( _e:MouseEvent):void{
trace( "btn" );
}
mc.addEventListener( MouseEvent.MOUSE_DOWN, mcDown );
mc.btn.addEventListener( MouseEvent.CLICK, btnClick );
The problem I am having is when click the button, mcDown event is also triggered and traces both "mc" and "btn".
How can I make it so that when I click the button, it triggers only btnClick and not mcDown along? I tried MOUSE_UP instead of CLICK, same problem. And mcDown event has to remain MOUSE_DOWN.
There is no way to prevent bubbling except setting the bubbles parameter as false in the dispatchEvent.
dispatchEvent(EVENT_TYPE, BUBBLES,....);
However, you can avoid the bubbling by doing a check. Just have the below line as first line of your listener function it avoids the events dispatched from all objects other then targets.
if(e.eventPhase != EventPhase.AT_TARGET) return;
So, for your sample code, when you click on the button both the events dispatches but in the mcDown function it won't execute after the above said line.
If you add button in a MC, and you click on the button, you also click on the MC, because the part of the MC that is under the button is still there and it runes the function for the whole of the MC, you can't remove it.
So it's good idea to make a function that will check if the button is pressed, otherwise it will run the function for the whole of the MC.
This one should do it.
//add this in you constructor
mc.addEventListener(MouseEvent.MOUSE_DOWN, myReleaseFunc);
function myReleaseFunc(e:MouseEvent):void {
if(e.currentTarget.name == Btn1) //Btn1 is instance name for a button
{
Btn_func1();
}
else if(e.currentTarget.name == Btn2) //Btn2 is another button.
{
Btn_func2();
//For every button you'll need to add another function and if statement to check if that button was clicked.
}
else
{
Mc_func();
}
}
// this outside the main class
function Mc_func():void{
//you code here
}
function Btn_func1():void{
//you code here
}
function Btn_func2():void{
//you code here
}
I think that this way is much more effiecient and it will works better and faster and you'll have a lot smaller chance of overloading the system.

Fake mouseclick on hover AS3

This morning I stumbled to this question:
When hovering a button, is it possible to click it automatically after X seconds? So the user doesn't need to click it with his mouse?
How can I let Flash believe my mouse really clicked some button on the stage or brought up with as3?
I have a lot of buttons in my movie. So I prefer to use some code which will cover this function for all existing or coming up buttons in my movie.
I would normally use a code like this but is there some workaround to accomplish this in a different way? I do no want to add code to every button.
this.addEventListener(MouseEvent.OVER, onMouseClickEvent);
public function onMouseClickEvent(event:Event)
{
trace(event);
if(event.buttonDown) // if button goes down normally
trace("MOUSE CLICKED NORMALLY");
else
trace("left button was not down");
}
The easiest way i think, is to subclass Button.
Then you should add mouse over/out listeners, add click listener that looks like that
:public function clickListener(event:MouseEvent = null){...}
When the mouse is hovering, raise a flag that the mouse is on the object, start a timer and when the timer callback function is called, you check the if the flag (you turn the flag down, when the mouse is out) is true and just call clickListener()
Listen for MouseEvent.MOUSE_OVER and start a timer, at the end of which the button will send the MouseEvent.CLICK event. In the mouseover handler, use the SystemManager to add a listener for MouseEvent.MOUSE_OUT which cancels the timer. The timer removes the listener using the SystemManager as well. So does clicking the button.
Finally! Solved!
This did the trick:
public function runOnce(event:TimerEvent):void {
btnSignal.dispatch("KEYBOARD", btnCode);
}
Robusto & Radoslav Georgiev: Thank you for pointing the right direction!
(I'm answering this a little late but would like to give input for future people).
One way to 'skin this cat' is to simply let your hover event trigger a timer (i.e. 3 seconds). In an EnterFrame or other function let a number or Boolean change when 3 seconds is reached.
//Pseudo code
if(timer == 3)
{ numberVar = 1;
//or
BooleanVar = True;
}
else
{
numberVar = 0;
//or
BooleanVar = false;
}
//end
Then just as you connected your methods to a mouseEvent, connect those same methods to fire when numberVar == 1 or BooleanVar == True. That's it.
For super simplicity and readability let your MouseClickEvent just be numberVar = 1 or BooleanVar = True.
These become super simple to implement over time and in my experience are 'very' error proof. Easy to fix also in the case of a typo or something else. No super elusive imports either. Hope that helped.
Great question by the way (+ 1)
:D

Actionscript 3: Preventing mouse events *except* for a specific button/movieclip?

Is there a way to block mouse events except for a specific MovieClip or Sprite?
i.e. I know that to prevent ALL mouse clicks, I can write something like:
stage.addEventListener(MouseEvent.CLICK, onPreventClick, true, 0, true);
...
private function onPreventClick(e:MouseEvent) {
e.stopImmediatePropagation();
e.preventDefault();
}
You can check e.currentTarget to find the object who fired the Event and doing your filtering according to that.