Jul 23 2009

Whirled API: Keyboard Focus

One of the most vexing issues with implementing the Whirled API in your single player game is keyboard input. With a standalone .swf deployment (such as a normal game), resetting the focus to the stage periodically is sufficient to keep keyboard inputs going to your handlers. However, due to Whirled’s security model, you are not allowed to add handlers to the stage directly, and instead must add your handlers to _control.local. (Assuming you named your GameControl object _control!) stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownListener) will through security errors.

Unfortunately, stage’s focus can only be set to an InteractiveObject. Therefore stage.focus = _control.local does not work to regain focus when it is lost.
This is because _control does not inherit from InteractiveObject.

There are at least two situations where your game is going to lose focus when running in the Whirled platform.

  1. The player clicks outside your game. (ie: to type in the chat window)
  2. The player clicks a button which you then remove from the stage. (ie: Start New Game)

Unfortunately, SimpleButtonobjects like to grab keyboard focus. When they’re removed from the stage, they keep focus and because they are no longer in the display list KeyboardEvents no longer bubble up to your handler. My solution (and it feels like a kludge, so if anyone has a better solution I would love to hear it) was to not remove my New Game button from the stage but rather remove it’s mouse event handler and make the button invisible. Because it is still on the stage, KeyboardEvents it is receiving continue to be passed up the display list to the handler. In anycase, this works in the test environment and in non-public testing on Whirled.

The other problem was slightly more complex, although I solved it first.. Although my games are written as classes extending Sprite which does inherit from InteractiveObject… the first thing I do is place a backdrop Bitmap object on the stage. Bitmap does not inherit from InteractiveObject, so clicks to the game playing area do not restore focus.

My initial solution then, was to place a Spriteobject which solely contained a transparent bitmap the width and height of the stage on top of my game. This object was able to recieve KeyboardEvents (but note, setting stage.focus = MyTransparentSprite did not restore focus), and then allows them to bubble up to the handler. Unfortunately this cut off my user interface buttons, because the Sprite was intercepting the mouse clicks. My current solution is to use THREE transparent bitmaps in that Sprite, arranged so they do not overlap my buttons. I’ve colored them in in the picture below:

 Mouse Capture Masking Example

As a result, at this point my game starts off correctly receiving keyboard inputs because the NewGame button grabs focus when it is pressed and does not leave the screen, and if the user takes focus away he or she can get it back by clicking anywhere in the game’s area– something which, judging by their forums, Whirled users seem to have been trained to do when their keyboards stop responding anyways.

No Comments

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment