AS3 - KeyboardEvent.KEY_DOWN in AIR project not triggering handler after removing display objects, and stage.focus not working - actionscript-3

I am developing an kiosk-like application (a game) which needs to be locked in full screen all the time. I am using as3/flash/AIR for it. Things started well at first, and for the most part all works fine.. but there is a mystery brewing somewhere which I haven't been able to figure out... That's where your help would be greatly appreciated!
The way I handled this problem is by adding at the very beginning of the app:
stage.addEventListener(KeyboardEvent.KEY_DOWN, playerOnKeyDown);
Then, on my playerOnKeyDown function:
function playerOnKeyDown(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.ESCAPE)
{
event.preventDefault();
//More code here opening out menus, etc, etc.)
}
}
So, all of this worked just fine, but of course I needed to also bring along:
stage.focus = stage;
into the party, otherwise, when removing objects - as in removeChild() - the event firing wouldn't behave as I wanted, because flash changed the focus elsewhere in the display list.
I have been careful to add the focus to the stage every time a remove a "child", and it works great everywhere, except for one time in the entire run, right after I remove an object from an externally loaded swf.
I still add the lines as it should be expected to work:
removeChild(childFromLoadedSWF);
stage.focus = stage;
except that when I hit the any key, the event won't trigger my function, and if I hit the ESC key, it takes me out of full screen (its default behavior), once again, circumventing completely my listener function playerOnKeyDown.
The strange thing is that right before doing this, the line:
stage.hasEventListener(KeyboardEvent.KEY_DOWN))
traces true!
The focus is on the stage, the listener is on, and yet when pressing the ESC key the default behavior is ignoring my function completely....
What could be causing this?
THANK YOU!!

Looks like I just needed to remove an ENTER_FRAME listener I had. That was wreaking havoc with the stage.focus. Now everything works great!
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame)
For anyone looking into using AS3 to develop desktop games for mac or PC (as in Steam), this is great.
the game Machinarium must have done something like this, because the ESC key never causes this effect, event though it was made in flash.

Related

Strategy for finding a missing mouse event in AS3

Will make this brief, I have a game map with units on it and had finalized a fully interactive minimap where the units on the minimap have event listeners for rollover/rollout (displays a small popup unit data summary) and click (selects the "real" unit on the main game map and scrolls the viewpoint to that location). All done, tested, working.
I then implement an interactive scrollable unit list with more status summary data and dozens of objects with rollover/rollout/click listeners. All tested and working fine.
Then I go back and look at my minimap, and the listeners on the mini-ships aren't working anymore. Things tried:
Debug code to make sure listeners still being added
Debug to watch the one place where I remove those listeners to make sure that ain't happening unexpectedly
Debug to watch all the places I refresh that dialog to make sure every iteration adds the listeners back
Can't see that there is any transparent object on top intercepting
Checked mini-ship parents to make sure I didn't turn off mouseChildren or something like that somewhere
No added stage-level listener, in fact I killed all of them temporarily to test this
What happens when I debug with a breakpoint on the mini-ship listener handler is nada. It's no longer receiving mouse events. So either something I haven't thought of has stopped them from listening or something I don't know of is intercepting.
So what is the strategy here? How can I find the break in the chain?
Well knowing what the actual problem was certainly gives us the advantage of hindsight... that being said, you could have detected the error by adding a trace call inside your function that adds the listener and another one inside your function that removes it. Then you would have seen that it isn't getting re-added. Or you could set break points there.

Pressing space does weird things

I've made a simple game in flex. You control falling blocks and your goal is to eliminate viruses. It's almost a copy of the 90s game dr Mario. I've made it so you control blocks with the arrow keys and you spin the block with space. Everything works fine as it should when playing. However when i switch to another program and the application is out of focus and i get back to the game, whenever i press space the game restarts. It's like it calls a function that reinitializes the game and resets all the variables to the start values.
The game is made with several NavigationContent components that acts like scenes. The game doesn't go back to the start screen when i press space, it just resets the game. Wich is really weird.
Are there any default method that is called that causes this behavior? Anyone have a clue?
EDIT: The issue arises - as it seems - exclusively when i tie a function to the space key (keyCode 32). I solved the issue by rebinding the key to "CTRL". But still it would be great to know what's up with the SPACE key. The game works fine with space if i use Internet Explorer. Other browsers doesn't work with the space key. It's the same issue with all of them.
EDIT: This is how the event listener looks:
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, moveBlocksKeyboardEvent);
Even if i comment out all the code in the moveBlocksKeyboardEvent method the game still restarts. It's exclusively when hitting the SPACE-key. If i hold down the key the blocks spin. It's when i release the space button the game restarts. As if it's some reinitialization method tied to the KEY_UP event or something.
This type of behaviour is often tied to a null or undefined value, causing a nonsense-code jump which then results in a reset.
Make sure that that event handler for key down is attached to a valid object; if you are using "stage" then make sure it exists. When you move out of focus, the event handler may be left associated with a null object; when you reenter, it doesn't exist anymore, and therefore you get the reset behaviour.
This thread may help provide more detail:
Adding a key listener in Action Script 3

Fast rollOver on a button causes another label to rollOut (MovieClip button)

I'm new to AS3/Flash and stackoverflow and have tried to browse through different threads with this issue.
My issue is that when I rollover too quickly on one of my buttons, the button will rollover to the "Click" state. I have a tester that debugs the line "hit! " and whenever that glitch happens, the tester does not show the line "hit" so I know that it isn't actually registering a user-input click.
Interestingly enough, the issue also only happens when I move from the bottom or top of the button to the other side vertically. Faster FPS does seem to minimize the effect but it's still there. I have tried to get rid of my hit area layer, thinking that it was the culprit to the problem somehow but even then it did not do anything.
I'll post the .fla in case anybody can figure this out, would truly appreciate it as it's been driving me nuts.
https://dl.dropboxusercontent.com/u/18672917/Main_Btn_7halp6.fla
Here's the code I used in case someone wants to figure it out solely from possible coding errors. (Also, better_mc.Hit._visible = false; doesn't work it seems)
import flash.events.MouseEvent;
stop();
better_mc.addEventListener(MouseEvent.ROLL_OVER, betterOver);
better_mc.addEventListener(MouseEvent.ROLL_OUT, betterOut);
better_mc.addEventListener(MouseEvent.CLICK, betterClick);
function betterOver(evt:MouseEvent):void{
better_mc.gotoAndPlay("Over");
}
function betterOut(evt:MouseEvent):void{
better_mc.gotoAndPlay(27- (better_mc.currentFrame-10));
}
function betterClick(event:MouseEvent):void {
better_mc.gotoAndPlay("Click");
}
better_mc.hitArea = better_mc.Hit;
better_mc.addEventListener(MouseEvent.MOUSE_DOWN, Hitbox);
function Hitbox (event:MouseEvent){
trace("hit! "+this.name);
better_mc.Hit._visible = false;
};
Ok, got it. this is what is happening
Your calculation on rollout is creating a problem
function betterOut(evt:MouseEvent):void{
**better_mc.gotoAndPlay(27- (better_mc.currentFrame-10));**
}
This expression sometimes returns frame number 28 which is ahead of your 'stop()' which is at frame 27 and so it goes on playing the whole click animation.
27- (better_mc.currentFrame-10)
Try the simple solution of adding 'stop()' before your click animation starts i.e. frame 31 in this case.
See if this sorts your issue.
Can not open your fla as i have CS5 so not much help on that
Not sure why you need both click and mousedown events, code seems fine apart from the gotoAndPlay(labelname) parts since no idea how the animations are added here
Just for the last part of your query
(Also, better_mc.Hit._visible = false; doesn't work it seems)
For AS3, property 'visible' is used and not '_visible' so it will be,
better_mc.Hit.**visible** = false;

Keyboard listener is killing my framerate

I'm working on a game that uses four simultaneous key presses. It all works fine, except that when the keys are rapidly pressed, my framerate slows down significantly (if I hammer even just one of the keys, I can halve the framerate).
I initially just assumed that there was too much going on in the method that the key press triggers, but if I take the code out of the method completely, the slowdown still occurs.
Has anyone run into this before? The keypress is one where you hold the key down, so it's repeatedly firing a method call every frame, but this is pretty standard for many uses and I've never encountered this before.
EDIT: clarification.
Structurally, there's a KEY_DOWN and KEY_UP listener attached to the stage:
stage.addEventListener(KeyboardEvent.KEY_DOWN, menuKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, menuKeyUp);
which then calls a method with a single switch statement in, that contains five lines like this:
case ONE: pressing1 = true; break;
There's an ENTER_FRAME event that checks to see if any of the boolean flags are true, and handles character movement. This calculation happens regardless of key presses (i.e. if you let go of the keys, gravity still has an effect). This holds 60fps easily.
The issue is literally at the exact moment the key is pressed or released, there's an almost imperceptible frame drop. Repeatedly pressing the keys causes the framedrop to get worse and worse. Holding a key down doesn't kill the framerate, apart from the single split second frame drop when the key is pressed down. After that the game carries on as normal. Letting go of the key causes another tiny hitch and then the framerate goes back to normal.
EDIT 2 - I added a framerate checker so I could see exactly what was happening to the framerate. Interestingly, I can't make it go any lower than EXACTLY 30fps even when I press keys very rapidly. Is there some sort of restriction in play here with Flash Player?
Turns out that the code was correct all along. Playing 60FPS content in the debug player or the standalone player causes any events (mouse and keyboard) to hitch the framerate. Viewing the same content in a browser, or exported to AIR, stops the issue entirely. The content is now running perfectly at 60fps without any slowdown.
Hope this helps someone, I was tearing my hair out!
Do you have multiple different listeners, or one listener that appropriately routes the keypress? I would suspect the former. The solution is to switch to the latter.
What I typically do is have one object that's responsible for listening to key presses and translating keyboard events into other, more meaningful events.
For example:
protected function handleKeyboardEvent(e:KeyboardEvent):void {
if (e.ctrlKey) {
switch (e.keyCode) {
case Keyboard.A:
eventBus.dispatchEvent(new Event(ViewEventKind.SELECT_ALL));
return;
case Keyboard.Y:
eventBus.dispatchEvent(new Event(ModelEventKind.REDO));
return;
case Keyboard.Z:
eventBus.dispatchEvent(new Event(ModelEventKind.UNDO));
return;
}
}
}

AS3 Button stops working after random amount of click

I have a movieclip being used as a button. After a random amount of clicks the button stops working. In other words, the mouse will become a hand when hovering over the button but no clicks are registering to fire the function. I've even clicked it 40 times and it will work but then suddenly, bang!, it stops working. Heres the function that adds the btn, listener, animates it into the screen and also adds text.
function makeButton():void{
addChild(myBtn);
myBtn.mouseChildren=false;
myBtn.buttonMode=true;
myBtn.x=(stage.stageWidth/2)-(myBtn.width/2);
myBtn.y=-300;
myBtn.addEventListener(MouseEvent.MOUSE_DOWN, btnClicked, false, 0, true);
myBtn.btn_text.text="The string goes here";
TweenLite.to(myBtn, 0.5,{x:(stage.stageWidth/2)-(myBtn.width/2),y:(stage.stageHeight/2)-(myBtn.height/2)});
}
And then here's the function that animates the button outside the screen:
function btnClicked(e:MouseEvent):void{
myBtn.removeEventListener(MouseEvent.MOUSE_DOWN, btnClicked);
TweenLite.to(myBtn, 0.5,{x:(stage.stageWidth/2)-(myBtn.width/2),y:-300});
}
Strange thing is, I added a trace("listener added") into the 'makeButton()' AT THE VERY END, AFTER THE ADD EVENT. And it traces everytime, even on the times the button stops working. SO i can only assume there are no errors with listener being added. But then why is it not working?
I'm stumped. I thought it could be an event propagation problem. In other words the listener was being added to the target (myBtn) but somehow it was capturing or bubbling wrong but..... then why does it work at all? And for so many clicks?
The truth is out there. Or maybe in here, your insights will be much appreciated.
Where does myBtn get created? I can see right at the beginning of makeButton() that you are adding it the display list but can't see where it actually gets created? Is it already on the stage?
Adding a trace statement in the makeButton function will only tell you that a button is created, it won't say much about the functionality of your button. If you want to check if your button reacts to a click , you need to add your trace statement in the click listener.
According to your description , it sounds like you keep adding the same button to the stage rather than actually clicking the same button.
How often do you call the makeButton function before it stops working? This function looks like it should only be called once. As for the btnClicked function , why do you remove the listener, if you wish to click the button again?
Practically it looks like you should only have your Tweening functionality in your functions, I mean , once the button is created , you need one function to tween the button, then instead of adding the button again, simply call a function to tween the button back in place.
All the rest shouldn't be repeated.
I've fixed the code and the problem hasn't occurred again. The problem must have been that I was running the addChild every time the function called and that was doing something odd to the MC in the display list. I haven't pursued the error by clicking the buttons many times in a row for a minute or two, as I did to make the error happen originally. I think i'll let sleeping dogs lie.
With that said, my code is a lot cleaner with the addChild and other crap running in the initialization function and just sitting above the stage - and then being tweened into position in the 'makeButton' and 'btnClicked' functions (which are now fittingly named 'tweenBtnIn' and 'tweenBtnOut').
Thanks again