Does the following line fix it if I add it to my key listener:
The .stopPropagation method will prevent that particular event from bubbling any further up the display list. This reply is about to get off the topic of your particular problem, but hopefully will be useful general Flash event handling stuff.
Say you have a display list like this (anne and conique are direct children of stage, ben is a child of anne)
| |___ ben
If a KeyboardEvent is dispatched from Ben it will first trigger any listeners on Ben, then "bubble" up to Anne triggering any listeners on her, then bubble up to stage and trigger any listeners there. Conique will have no idea that the KeyboardEvent ever happened.
This is why if you want to catch all the keyboard events that happen you usually add your listeners to the stage or some other similarly base-level DisplayObject.
If you have a listener on Anne which calls the .stopPropagation method on the event then it will be stopped there, and will not bubble up to the stage.
Not all events do the bubbling phase; you can see if one does by examining the read-only property bubbles
Not all events can have their propagation stopped; again you can check by examining the read-only property cancelable
.The Source of KeyboardEvents
Something interesting to know about is which object Flash dispatches KeyboardEvents from. They are dispatched from whatever InteractiveObject is indicated by your stage's focus
property, or the stage itself if that property is null
. You can detect when focus changes by listening for FocusEvent.FOCUS_IN for an object gaining focus and/or FocusEvent.FOCUS_OUT for an object losing focus. These events bubble, so if you place your listeners on the stage you should hear about all of them (or at least about all the FOCUS_IN events).
You'll find that focus
will generally change to whatever InteractiveObject was last clicked on or selected using the tab key (to be more accurate, it changes when you click on a TextField, but will revert to null on clicking a Sprite - I'm unsure how exactly it is determined what objects will automatically shift focus). The reason for this is so that textfields and textfield-like things can be sure that they receive keyboard input after they've been selected by the user.
Most of the time this doesn't matter in games, as we're just listening on the stage, and bubbling events always eventually reach the stage, right? Almost always. Say Ben is the focus
, and he is removed from the display list. KeyboardEvents are still going to be dispatched from him, but as he's now disconnected from the display list they will have nowhere to bubble to and will go unheard by our listeners on the stage. Until the user next clicks somewhere, you'll miss out on all their keyboard input.
There's two ways to prevent this:
Make a little utility class that listens on the stage for FOCUS_IN events and keeps track of that object, manually resetting focus
to null if that object dispatches an Event.REMOVED_FROM_STAGE. Just make sure you don't end up leaving event listeners attached to objects all over the place.
Simply set stage.focus = null
every frame. Simple, but that will totally break any input TextFields you might be using.And now back to the actual question at hand.
Simplest solution would be to have a Boolean variable hasTurnedThisUpdate, set to false at the start of each frame and have your event listeners check that it's false before turning the snake (and set it to true once they do). Problem is if a user presses two different directions in quick succession this will effectively ignore the second input, which leads to controls feeling buggy and unresponsive.
So instead! You'd want to create a queue structure to hold incoming input commands. Using an Array or Vector should be fine (if you're chasing performance queues are best implemented as linked lists but it'll really not matter in this case), and have your KeyboardEvent listener just .push the event it receives on to the back of the queue. Your main game loop will then .shift the front event from the queue and deal with it. This way there's no lost keyboard events, and you always have a maximum of one event to deal with each update.
Problems with this solution that are "left as an exercise for the reader":
If the user mashes a load of unrelated buttons and then presses the key to turn Left, your game loop will take several frames before it gets around to dealing with the Left command. Laggy controls!
Similarly (and slightly less contrived) if the player is holding down the Down key and then presses Left then depending on their system your queue may be filled with dozens of Down key events which will delay reception of the Left key event. Again leading to the feeling of laggy controls.(You'll want to either filter what key events are added to the queue by your listener, or allow the game loop to intelligently deal with multiple key events each loop - but without reintroducing the original instant U-turn problem.)