donderdag 13 januari 2011

3d as2/as3

This used to be my prefered method to do 3D in flash:

I made layers in flash, which I scaled and stacked on top of each other and beveled for lighting. By rotating some and not all of the layers, I can even animate the top half of the liebherr.. Now with just 8Kb, you have a remarkably detailed 3d animatable model. You can only use them small and orthogonally, but the effect is quite nice and you have a lot of control over how a model looks. Also it's quite easy to do..
I am curious how the same model would look in true 3d in as3, so this is a challenge I'll get back to..

woensdag 12 januari 2011

dinsdag 11 januari 2011

garbage collection gets rid of singleton class

I had a singleton class called gameLogic, which held all the outsiders needed to know about the game.
The idea behind this, is that the setHighscore movie can set the score after the game is unloaded..
It didn't work at first.
The game was taken of the display list and the reference to the loader was put to null. At that moment the garbage collector GOT RID of my singleton class.
When I instantiated it again after loading the setHighscore page, score was 0 instead of what I just set in the game.

The answer was very simple: instantiate the gameLogic class in the container and it will not be thrown away and reinited. Find this type of bug takes me ages now, but I hope it will become easier in time..

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!

Another Container Issue Loaders refer to Timeline placed objects!

Simplified the code looks like this:
private var pageContent:MovieClip;
var loader:Loader=new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, pageLoaded);
loader.load(new URLRequest(url), new LoaderContext(true));
private function pageLoaded(loadEvent:Event):void
  {
   pageContent=MovieClip(loadEvent.currentTarget.content);
   pageContent.name=pageLayer.currentPageName;
}
Now I get an error:
Error: Error #2078: The name property of a Timeline-placed object cannot be modified.
 at flash.display::DisplayObject/set name()

At first this didn't make sense to me, but... A loader loads an SWF, everything in this SWF is a Timeline-placed object, so the statement is true..
But I want to change it's name, and it seems I can't..
I'll have to program around it, keeping an array of Loaders, in stead of an array of MovieClips.

donderdag 6 januari 2011

a litte bit about gamedesign

This game started as a reworking of a game called "Goudlopers", which was later reworked to "magische Mickey". The concept of the game was based on the classic game: pitfall.
When Sanoma introduced the element of snowball-throwing, I warned them:
"We won't be able to build on the same game-engine."
There were some parts we could reuse. The scrolling we could reuse, although the character couldn't be in the center of the viewport anymore, so that needed to be re-written.
Some of the animations of goudlopers could be reused, but we needed a few more. All in all it turned out to be a completely new game, instead of a PIMP of SKIN.

This seemed a perfect opportunity to go to AS3..

But it also illustrates the importance of playing a game in your head, before you start programming. If I hadn't spotted the fact that snowballs would mean a whole different game, we would have been in trouble. Because we would just get paid for reworking the graphics and not the engine..
Sometimes little things added or thrown away can make a HUGE difference in gameplay.

Because of the snowballs the AI-opponents in the game, make the game much more intense, than a simpel exploring-game. If we would have the traps, slings, jumping frogs and whatever of the old pitfall-like game, it would be too much for the player.
It also means, we could make a smaller level, because the player has many other things to do, than look at the surroundings. The player needs to evade the snowballs thrown at him, and time his own throws at the oppenent, to hit them. Also he could only carry three snowballs and then has to return to a pile to load up..
After we introduced a life-meter for our opponents, as well for our hero, we had a game..

But it was quite different from where we started.

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..

CS5 project window..

not only was I programming in as2, I was using CS3. Well, no more..
We have bought the total complete master version of CS5..
So I have now installed it, to be totally up to date, but what's this:
THEY HAVE STOLEN MY PROJECT WINDOW, that I loved in CS3 professional.
I was making a *.flp for every project I did.
Especially in as3, using all these classes, it allowed me to create a logical structure and keep things togeter, like this:

I want my project window back the way is was. Now it just copies my hard disk.. We have a little thing called Explorer, that does that (and better)..
I cannot even open my old *.flp's, never heard of backward-compatibility, or did you think: well we didn't giv'm any backward compatibility on as3-as2, and nobody protested, so why not bugger all?

I cannot think why anyone would consider this an improvement. Anyone....?

1046: Type was not found or was not a compile-time constant: Loader.

As3 has been driving me crazy.
I tried creating a container the way I used to do this in as2.
Load in stuff with LoadMovieNum (Yes, I'm old fashioned, but I found the "layer"-concept very usefull in building minisites).

The pre is that you can develop a page (almost) completely independant and then get stuff from _level0.. The beauty is, because there is a _root as well as a _level0 the _root functionality isn't lost.
But oh well, as2 is long ago.

When I was trying to create this in as3, I got this enigmatic error when I just followed the example from adobe:

package nl.ludatic.container{
 import flash.display.*;
 import flash.events.*;
 import flash.net.URLRequest;
 import flash.net.navigateToURL;
 import flash.system.*;
 import flash.text.*;

 public class Container extends MovieClip
 {
  private var loader:Loader=new Loader();

and BAM!
There was no way I could get the compiler to go past this line...

Now what happened:
nl.ludatic.container means, the compiler has to look in nl/ludatic/container to get to the Container class..
In this directory I had also put a empty file called Loader.as.
Apparantly the compiler looked at this file when I said new Loader() and found it empty, so it concluded there was NO Loader class.

Now I don't know how an empty file can override a hard import, but it did.
I got rid of the file and everything works beautifully.

So I worked it out in the end, but wow...
Oh well, on to the next inexplicable error!

zaterdag 1 januari 2011

as2 to as3

I'm a regular flash-guru according to some. I program games, so if there is a problem in Flash, I usually find it. Up until last year I still programmed in as2 and hadn't done much OOP (Object Oriented Programming)
So I figure, I go learn it in 2011, blog about what I find and maybe make some people happy, who knows.

Now I found out one of the first surprising things quite quickly. Don't think you know something, even when it doesn't seem to have changed.

this is (very concise) as2:
mc.localToGlobal(p={x:0,y:0});

after this p.x and p.y hold the coordinates of mc's anchorpoint on the stage..
I use this a lot in game-development in as2.
I was thrilled that the function hadn't changed..
BUT!
in as3 the above always leaves you with the original point, nothing happens!
in as3 the snippet would be:
var p:Point=new Point(0,0);
p=mc.localToGlobal(p);

As you can see, the difference is subtle. In as2, the point that you give is modified. In as3 the point is returned from the function and the original point is left unaltered.
I know the latter is more correct and I understand now why they did it..
But WHY weren't we warned. I found NO reference to this whatsoever.

Bad Adobe!