Posts tonen met het label mulitple keys. Alle posts tonen
Posts tonen met het label mulitple keys. Alle posts tonen

vrijdag 7 januari 2011

Weird loss of keyboard focus in game.. revisited

Yes!
I know what caused it.
It had to do with the scoping of the loader var.
You can keep a private var Loader in your main class and when you reload it goes like this:
import flash.display.Loader;
 import flash.events.Event;
 public class Container extends MovieClip
 {
  private var currentPage:Loader;//=new Loader();
  public function Container()
  {
   pageLayer=new MovieClip();
   stage.addChild(pageLayer);
   requestNewPage("splash");
  }
  private function requestNewPage(pageName:String):void 
  {
   var mc:MovieClip;
   var url=pagePath+pageName+".swf";
   trace("requestNewPage: "+url);
   progressMc.visible=true;
   currentPage=new Loader();
   currentPage.contentLoaderInfo.addEventListener(Event.COMPLETE, pageLoaded);
   currentPage.load(new URLRequest(url), new LoaderContext(true));
  }
   public function pageCallback(a=null,b=null,c=null,d=null)
  {
   //trace("pageCallback: "+a);
   switch(a)
   {
    case "requestNewPage":
     requestNewPage(b);
    break;
    case "startGame":
     requestNewPage("game");
    break;
    default:
     trace("pageCallback undefined action: "+a);
    break;
   }
  }
  private function pageLoaded(loadEvent:Event):void
  {
   var mc:MovieClip=MovieClip(currentPage.content);
   pageLayer.addChild(mc);
   mc.setUmbellical(stage,pageCallback);
  }
Now in the splash page, you create a public function called setUmbellical and receive the pageCallback.
If you need to communicate with the class that loaded you, call pageCallback..
In this setup calling it with arguments ("requestNewPage","filename") will cause the next page to be loaded, but WITHOUT the strange loss of focus!

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.

woensdag 5 januari 2011

Focus of child destroyed, when child no longer on displaylist....

Ok, so what happens is the following:

I have a container movie, which loads a splash page.
The container movie has a key-listener, this works from the first moment the movie is executed.

The splash page receives a click.. (I guess it gets keyboard focus then instead of the stage.., but the stage still receives key-events, because it's child has focus..)
Now the splash page is removed from the displayList in order to load a new page (the game)
Then keyboard focus is lost, the moment the MovieClip which had the focus at that point is removed.
So now the stage does no longer get Key Events!!

If I leave the page on the displayList, the stage continues to get Keyboard events.

I don't know what the logic is, yet, or if it is a bug, but this is definitely what happens..

Weird loss of keyboard focus in game..

Ok, I have this game set up in AS3, yeah! But it needs to be loaded in a container (we always develop that way, so the different programmers/designers and backenders don't get in each others way)..

I have a container.swf, loading the splash screen (splash.swf), on the splash screen is a button.
If the button is pressed, the container receives a callback (no, not an event) and clears up the first load, then loads the game on the same movieClip.
This works.
Now I have the same thing for the game, and it works aswell. BUT....
I loose keyboard focus, apparantly to the browser??.. Doesn't a child inherit keyboard focus from the stage???

You can look at my setup here:

http://www.snoep.at/flashcandy/05_01_2010/index.php
Click either start or continue, it doesn't make a difference at this point.
You can play the game, but after you press the start button and the game loads, you have to click again, in order for the keyListeners to do anything.. (Arrow keys and space control Huey Dewey or Louie, it's not decided yet)

There is the ugly solution offcourse: add a popup of sorts, that people have to click, but YUK, it must be doable some other way..
Here is the code:
loader=new Loader();
   loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
   loader.contentLoaderInfo.addEventListener(Event.COMPLETE, pageLoaded);
   loader.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, showProgress);
   loader.contentLoaderInfo.addEventListener(Event.INIT, pageInitiated);
   timestamp=getTimer();
   loader.load(new URLRequest(url), new LoaderContext(true));
and of course the handler:
private function pageLoaded(e:Event):void 
  {
   //trace("pageLoaded");
   pageContent=MovieClip(loader.content); // keep for future reference..
   pageLayer.addChild(pageContent); // add is to my Layer, which is a bit like as2 LoadMovieNum :)
   pageContent.setUmbellical(stage,pageCallback); // give the page a reference, to set up the keyListeners..
  }


Can't imagine now, why it wouldn't work.. I hope I find it tomorrow, or I'll just have to go for the ugly solution for now..
I have this great book about as3 and OOp (ActionScript 3.0 Design Patterns) it really helped up to now, who knows, maybe there is something in there that might explain all this..