donderdag 6 januari 2011

Multiple keys don't work properly in Flash as3

If you press up, left simultaneously, there is no keyDown event when you press SPACE as well.

My output and what happened:
key down38    // I pressed up!
key down37   // I pressed left!
key up37       // I released left!
key up38      // I released up! (so far so good!)
key down32         // I pressed space
key up32             // I released space
key down37       // I press left
key down32      //  I press space
key up32         // I release space
key up37        // I release left, (still good!)
key down38      // I press up
key down32     // I press space
key up32         // I release space
key up38       // I release up (ok, that all works, NOW for the real test!)

key down38   // I press up
key down37 // I press left
                   // I press space: NOTHING HAPPENS, but my computer beeeps!
key up37   // I release left
key up38 // I release up
              // I release space, AGAIN NOTHING HAPPENS

Seems trivial, right, but this means, in my game, when you jump left and want to fire a snowball, you have to let go of only the left key to aim upwards, or let go of both before you press space (and don't aim upwards)
This sucks...

I'm going to make a GameKeys object as a Singleton to attempt to work around this.
When finished, you'll find it here..

I found a great place to start:
http://www.senocular.com/flash/actionscript/?file=ActionScript_3.0/com/senocular/utils/KeyObject.as

It's not a singleton so it will have the same focus problem, I described before. Also I don't like all the proxy stuff, it's unnecessary I feel. So re-writing time:

Here you are, I put it in the container package, I feel handling raw keys is a responsibility of the container, as is maintaining loaded pages and sounds.

package  nl.ludatic.container {

 import flash.display.Stage;
 import flash.events.KeyboardEvent;
 import flash.ui.Keyboard;

 /**
  * Usage:
  *
  * import nl.ludatic.container.GameKeys;
  * private var GameKey:GameKeys=GameKeys.getInstance(stage);  
  * if (GameKey.isDown(Keyboard.LEFT)) { ... }
  * 
  * GameKey.setKeyDownCallback(keyDownHandler);
  * private function keyDownHandler(key:uint):void {
  *   switch (key) {
  *    case Keyboard.LEFT :
  *    ....
  *   break;
  *   }
  * }
  * this keyDownHandler-function will be called with a keycode, the moment a key is pressed, but only once!
  *
  */
 
    public final class GameKeys
    {
  private static var stage:Stage;
  private static var _instance:GameKeys; // set up as a singleton!
  private static var keysDown = new Array();
  private static var cbKeyDown =null;
  
  public function GameKeys(pvt:PrivateClass)
  {
   stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
   stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
  }

        public static function getInstance(stg:Stage):GameKeys {
   GameKeys.stage = stg;
   if(GameKeys._instance == null)
   {
    GameKeys._instance=new GameKeys(new PrivateClass());
   }
            return GameKeys._instance;
        }
  public function setKeyDownCallback(cb)
  {
   cbKeyDown=cb;
  }
  
  public function isDown(keyCode:uint):Boolean 
  {
   if(keysDown[keyCode]) return true;
   // duplicate presses!
   else return false; // also when it's null!
  }
  
  private function keyPressed(evt:KeyboardEvent):void {
   if(keysDown[evt.keyCode]!=true)
   {
    if(cbKeyDown!=null)cbKeyDown(evt.keyCode);
    //trace("key first down"+evt.keyCode);
   }
   keysDown[evt.keyCode] = true;
  }
  
  private function keyReleased(evt:KeyboardEvent):void {
   //trace("key up"+evt.keyCode);
   keysDown[evt.keyCode]=false;
  }

 }
}
class PrivateClass
{
 public function PrivateClass(){
  trace("GameKeys PrivateClasse called");
 }
 
}
In the game I'll add facilities for using different keys from left right etc, like numpad.
This way I have a better chance of making a workaround for this Adobe-bug for my users/players.

Geen opmerkingen:

Een reactie posten