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
Related
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;
}
}
I don't know why I can't figure out this problem that is really basics !! (sometimes the brain is tired I guess).
I've got a movieclip with a guitar string.
I want the string to move everytime I click on it.
I've created a movie clip with 2 lables. the first = non movement, the second = movement.
I've placed in the second one a stop(); action. (in order to stop the loop)
I've put this code :
stringOne.addEventListener(MouseEvent.CLICK, accord1, false, 0, true);
public function accord1(e:MouseEvent):void{
var stringOne;
trace("DING");
stringOne.gotoAndStop("first");
}
It works but, of course, it only play the string movement at the first click.
Do you know how I could play the string movement EVERYTIME that I click on the string ?
Thank you very much and sorry for this easy question (little ashamed)..,
EDIT
Ah ! It seems to work with goToAndPlay !
if (stringOne.currentLabel=="premier") {
stringOne.gotoAndStop("default");
} else {
stringOne.gotoAndStop("first");
}
Just a thing, I have to click twice..
(one click = the string vibrate (label2))
(one click again = the string does nothing (going to label 1))
(one click again = the string vibrate (label 2))
Is there anyway to automatically skip the 2nd click (the one that tells the string to go back at label 1), and let do the code like : - When animation of label 2 is finished, automatically go back to label 1 ? –
Presumably, the "movement" label of the string is some sort of animation?
It seems to me what you want in your "guitar string" movieClip is, on the last frame of the timeline animation for "movement", a script that says gotoAndStop('non movement'). The click handler should gotoAndPlay('movement').
Then, when the string 'movement' animation is finished, it will reset itself, so that the next time you click it will play again.
So, your original code is fine (before the edit; but remove the "var stringOne;" since that will break the reference to stringOne). The only thing you need to add is a script in the timeline on the last frame of the movement animation ("first" label?) that says gotoAndPlay("default") (assuming default is the 'non movement' label). You may need a stop() in the timeline frame for "default".
Something like that :
stage.addEventListener( MouseEvent.CLICK, onStageClick);
protected function onStageClick(event:MouseEvent):void
{
switch( event.target )
{
case stringOne:
trace("String one stuff");
break;
case stringTwo:
trace("String 2 stuff");
break;
}
}
Or add your movieClip into a Sprite and listen click event on the Sprite and not on the MovieClips.
Thank you for the answer. I've found an other way, instead of mouse click I've used mouse down for going to frame 2 and mouse up for going to frame 1
I'm creating a quiz with buttons and I'm new to ActionScript 3.0, but very familiar with 2.0.
I have a variable inside of a MC called NextQuestion. When it reaches a certain frame, it changes to 1, then back to 0.
On the main timeline, when NextQuestion == 1, it's supposed to NextFrame();. I can't get it to work though, this is the last thing I'm having trouble with.
This is my main code with 4 buttons, 3 wrong, 1 right. The feedback MC plays an animation, and when it finishes, it sets the VAR NextQuestion to 1, which is supposed to make the main timeline advance to the NextFrame.
stop();
right.addEventListener(MouseEvent.CLICK, rightClick1);
wrong1.addEventListener(MouseEvent.CLICK, wrongClick1);
wrong2.addEventListener(MouseEvent.CLICK, wrongClick1);
wrong3.addEventListener(MouseEvent.CLICK, wrongClick1);
feedback1.addEventListener(Event.ENTER_FRAME, answerRight1);
function answerRight1()
{
if (feedback1.NextQuestion == 1)
{
trace(feedback1.NextQuestion);
nextFrame();
}
else
{
trace("do nothing");
}
}
function rightClick1(ev:MouseEvent):void
{
trace(feedback1.NextQuestion);
feedback1.gotoAndPlay("right1");
}
function wrongClick1(ev:MouseEvent):void
{
trace("wrong");
feedback1.gotoAndPlay("wrong");
}
Any help is greatly appreciated! :)
The nextFrame() method in AS3 doesn't loop trough your movieClips, it just set's the movie clip to the next frame provided there is a next frame, otherwise it does nothing.
you might want to re-write the nextFrame() to:
if (totalFrames == currentFrame)
{
gotoAndStop(1); // or gotoAndPlay(1) if you need
}
else
{
nextFrame();
}
Thats regarding why the movie clip might not start from the beginning.
Another thing that look weird is that you need a FRAME_ENTER event to check if the answer is correct. You must have a lot of spam in the output log. I'd recommend you to totally ditch the ENTER_FRAME event listener for this and do it all with the CLICKED event and dispatching the event from the feedback1 object.
As much as I understand the movie clip plays when you click a button and when the animation is over you want to either progress to next frame or do nothing. If so, on the feedback1 object add a following line in the end of animation for label "right1":
dispatchEvent(new Event("right"));
and instead of the line feedback1.addEventListener(Event.ENTER_FRAME, answerRight1); have:
feedback1.addEventListener("right", answerRight1);
That way you won't need to check the answer on every frame and you don't need to check if the answer is right or not, because when the dispatchEvent(new Event("right")); fires - it's always right.
Hope I didn't misunderstand your question :)
I'm constructing an area with selectable buttons that transition and appear every 10 frames. During these 10 frame transition periods I don't want the buttons to be selectable and if possible to disable the rollover.
I've tried creating an If statement on the addEventListener so that it only works when currentFrame is 11,21,31 etc but this didn't work. I then also tried the same principal on the function to which the Event Listener relates but still no success.
Does anyone have any ideas?
Add a listener for the ENTER_FRAME event, and put the if in the callback function.
For example
this.addEventListener (Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame (evt:Event):void {
if (currentFrame == 21) {
yourButton.enabled = false;
} else {
yourButton.enabled = true;
}
}
You could do 2 things:
1:
You manually add and remove the listener.
So when you start the transition, the listener is removed,
then when the transition ends, the listener is added.
2:
You make a custom listener which checks for the state of the frame to see whether it should execute its body.
EXAMPLE:
public void listener(event:Event) {
if (event.getSource().stage.getCurrentFrame() == 10) {//This is an example, I don't know whether this specific way will work.
//Run your code here
}
}
I am in the process of building a game with around 20 levels. Now, as I was thinking of trying to add a "skip" option to the game with the space bar key. I have a little trouble, since holding down the spacebar invokes the KeyboardEvent.KEY_DOWN event multiple times.
The above scenario (Keydown and keyup) works just fine when I'm trying to move my player character on screen.
The one main concern that is lingering in my mind is "Is this going wrong because the KeyboardEvent listeners do get removed and added when changing levels?"
P.S: Adding the skip option as a button works just fine, but I'd really like to use Spacebar for the ease of use.
Listen for KeyboardEvent.KEY_UP as well, and keep a boolean that acts as a switch. If the keyboard is pressed AND the boolean is false, set the boolean to true and proceed. Then, when the key_up event callback is invoked, reset the boolean to false.
Does somethig like this work for you?
private function levelInit () : {
// ...
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
// ...
}
private function keyDownListener (e : KeyboardEvent) : void {
if (e.keyCode == Keyboard.SPACE) {
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
// add stuff to initiate the level skip
}
}
You could also call the stage.addEventListener from a setTimeout to delay adding the listener to protect things more.
Remove the key_down listener in the function and add a key_up listener. Then in the key_up function remove that listener and add back the key_down listener.