Categories Displayed in Flash

Archive for November, 2008

Flash: Kirupa Snow in AS3.0

Thanks to Kirupa for the very popular snow tutorial effect...goes back ages..AS1. To see the finished product be sure to check out the cool product we are giving away for christmas.. 25 games a $7.99 value...free!, http://www.kidthing.com/christmas

While I'm sure one for AS3 exists, there's not much codeso I just converted the AS2 one here, which apparently was converted from the AS1 version here

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Follow pretty much either of them to get the gist if you need pictures of the IDE.

I differ slightly in implementation.

Create a new MovieClip named SnowFlake, draw the appropriate snow graphic, (e.g. a white 4x4 pixel circle at -2,-2). Right click in the library and give it a linkageID of "SnowFlake" as it will be needed by the SnowField Generator.

Create a 2nd MovieClip named SnowField inside draw a outlined box no fill the dimensions you want the snow to fill. Paste the following on it's frame1.

  1. var snowflakes:Array = new Array();
  2. var snowflakeProps:Dictionary= new Dictionary(true);
  3. var max_snowsize:Number = .04;
  4. // pixels
  5. var snowflakesCnt:Number = 150;
  6. var oheight:Number;
  7. var owidth:Number;
  8. init();
  9. function init():void {
  10.  
  11.         owidth = width;
  12.         oheight = height;
  13.         // quantity
  14.         for (var i:int=0; i<snowflakesCnt; i++) {
  15.  
  16.                 var t:MovieClip = new SnowFlake();//
  17.                 t.name = "snowflake"+i;
  18.  
  19.                 t.alpha = .2+Math.random()*.6;
  20.                 t.x = -(owidth/2)+Math.random()*(1.5*owidth);
  21.                 t.y = -(oheight/2)+Math.random()*(1.5*oheight);
  22.                 t.scaleX = t.scaleY=.5+Math.random()*(max_snowsize*10);
  23.                 var o:Object = new Object();
  24.                 o.k = 1+Math.random()*2;
  25.                 o.wind = -1.5+Math.random()*(1.4*3);
  26.  
  27.                 snowflakeProps[t] = o;
  28.  
  29.                 addChild(t);
  30.                 snowflakes.push(t);
  31.         }
  32.         addEventListener(Event.ENTER_FRAME, snowFlakeMover);
  33. }
  34. function shakeUp():void{
  35.         for (var i:int=0; i<snowflakes.length; i++) {
  36.                 var t:MovieClip = snowflakes[i] as MovieClip;
  37.                 t.x = -(owidth/2)+Math.random()*(1.5*owidth);
  38.                 t.y = -(oheight/2)+Math.random()*(1.5*oheight);
  39.         }
  40. }
  41. function snowFlakeMover(evt:Event):void {
  42.         var dO:MovieClip;
  43.         var o :Object;
  44.         if(visible && parent.visible){
  45.         for (var i:int = 0; i < snowflakes.length; i++) {
  46.                 dO = snowflakes[i] as MovieClip;
  47.                 o = snowflakeProps[dO];
  48.                 dO.y += o.k;
  49.                 dO.x += o.wind;
  50.                 if (dO.y>oheight+10) {
  51.  
  52.                         dO.y = -20;
  53.  
  54.                 }
  55.                 if (dO.x>owidth+20) {
  56.  
  57.                         dO.x = -(owidth/2)+Math.random()*(1.5*owidth);
  58.                         dO.y = -20;
  59.  
  60.                 } else if (dO.x<-20) {
  61.  
  62.                         dO.x= -(owidth/2)+Math.random()*(1.5*owidth);
  63.                         dO.y = -20;
  64.                 }
  65.  
  66.         }
  67.         }
  68. }

Some interesting aspects of this approach.

  • we capture the size of the manually built bounding box, this is generally easier to work with than variables for designers, in the Fla the outline is invisible
  • using a Dictionary to store the various model for the MovieClip view, instead of appending them to the MovieClip. They could be arbitrarily complex and have strong typing if so desired.
  • one centralized animation loop, useful if you ever want to say stop all flakes, most the old approaches had onEnterFrame per snowflake, making them harder to wrangle. It might also be slightly faster with it centralized, not 100% sure.
  • we disable the animation if the clip or the parent is invisible, or it's been removed from stage, bumping up the number of particles this is likely to help performance
  • add a reposition animation that is useful for reusing the snow component between scenes, but keeping the snow fresh
  • fun with the gradient glow filter to create a semi icecube effect on the text
  • fun with the bevel filter to create a snow bank effect

Here's the FLA

AIR: Getting the URI of an AIR apps install directory

Useful tip from Mike Chambers on how, good replacement in AIR if you were expecting the old _url or contentLoader.url property to work.

http://www.mikechambers.com/blog/2008/11/06/getting-the-file-uri-of-a-file-in-an-air-apps-install-directory/#more-1597

Flash: Compile Errors “1046: Type was not found or was not a compile-time constant: .” FIX

Valid easy to miss error (especially if you type and fast), obscure message.

  1.  
  2. //WRONG ==
  3. function something(testVar:Object == null):void{
  4. }
  5.  

Should be setting to '=' value instead of equality '==' check

  1.  
  2. //CORRECT =
  3. function something(testVar:Object = null):void{
  4. }
  5.  

Flash: Troubleshooting flashlog.txt not being generated? Another tips..check ADL.exe

Ran in to two interesting cases, where the flashlog.txt wasn't working and thus trace utility SOS Max stopped working. For a bit I thought it was something about setting up Flash 10 debug version. It wasn't at least entirely.

The first case was my normal development machine, the second was a new non-development test machine (interestingly slow pc's can help show errors in ways my fast dev machines cannot). For the dev machine, this was particularly annoying as it's how I debug many applications.

In both cases, I first followed the instructions here which are just the basic settings. and made sure that the debug version was installed by going to the version check

Case 1: The Primary XP Development Machine
In the first, mm.cfg was set to write to a place that SOS wasn't looking at C:\flashlog.txt, which may have been the Flash 10 install, somewhere in Flash 9 they took out the ability to specify the location of the flashlog.txt. So I reset it to what SOS was expecting e.g.

C:\Documents and Settings\\Application Data\Macromedia\Flash Player\Logs\flashlog.txt

But that still didn't work. So I tried deleting flashlog.txt and *couldn't do it*, as it was in use by AIR, adl.exe ... in fact two instances of them, likely spawned by Flash CS3 publishing for AIR. Unlocking them, allowed the Flash CS3 and various other flash debug players to write to the log file again.

Looking into this appears to be a common headache see

More worrying is per Adobe that there is a bug open on it, but per discussion "There is no workaround for this" and no fixes are planned

ALSO in the same folder policyfiles.txt was a whopping 200MB! This is due to apppend in the mm.cfg being set to true, so beware that you clean up periodically if you do have it on (e.g. if your fishing for intermittent bugs)

CASE 2: The Windows Home Netbook

This was more subtle, a fresh pc, downloaded the debug player.

Being a 'power' user of PC's I always have 'show hidden files and folders' and 'show file extensions' turned on, but on a new install these are off by default, the hidden folders was easy to spot, many of the folders (e.g. Application Data) weren't visible. I created a new text document mm.cfg, saved it. But the Log directory and flashlog.txt never were created. I tried a bunch of things, while concerned with IE, tried with FireFox, restarted the OS. After much restarting trying different things, constantly reinstalling the flash player, trying IE7.

What helped me solve it was going into a command prompt and opening up C:\Documents and Settings\\mm.cfg into the DOS editor...it came up blank, I recreated the mm.cfg, and hit save and then in Windows Explorer I had 2 mm.cfg! Turns out one was mm.cfg.txt, but I couldn't see it due to the missing file extensions....grrr!

It would have been faster to have copied the mm.cfg from the original dev machine, but when something so simple as a text file doesn't work, I've frequently found that it comes back to haunt me. Given this machine will be used at CES I'm glad I spent the time.

I've also discovered that mm.cfg apparently is checked every time the flash player starts up, so that no restarting of the browser or PC is needed in the case of IE which can install ActiveX without restarting itself.

AIR: Listing Files in Directory

Had a small project to compare files in a local system to that of another, thought it would be a fun project to learn more about AIR, only took a couple hours, most research. Here's the relatively simple code to list the files in the directory the AIR app is run in. Learned about that trick from FLEX{er}

  1.  
  2. import <a href="http://livedocs.adobe.com/apollo/1.0/aslr/flash/filesystem/File.html">flash.filesystem.File</a>;
  3. import flash.events.FileListEvent;
  4. import flash.desktop.NativeApplication;
  5.  
  6. var appDir:File;
  7. var buildDir:File;
  8.  
  9. //debug("url: "+ loaderInfo.url); //app:fileName
  10. NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE,onInvoke);
  11.  
  12. function onInvoke(invokeEvent:InvokeEvent):void {
  13.  
  14.         appDir = invokeEvent.currentDirectory;
  15.         path_txt.text = appDir.url;
  16.         buildDir = new File(invokeEvent.currentDirectory.url +"");
  17.  
  18.         buildDir.addEventListener(FileListEvent.DIRECTORY_LISTING, dirListHandler);
  19.         buildDir.getDirectoryListingAsync();
  20.  
  21. }
  22. function dirListHandler(event:FileListEvent):void {
  23.         var contents = event.files;
  24.         var cFile:File;
  25.         for (var i = 0; i < contents.length; i++) {
  26.                 cFile = contents[i] as File;
  27.  
  28.                 if (cFile.isDirectory) {
  29.                         cFile.addEventListener(FileListEvent.DIRECTORY_LISTING, dirListHandler);
  30.                         cFile.getDirectoryListingAsync();
  31.  
  32.                 } else {
  33.  
  34.                       //show relative paths e.g. something.txt instead of C:\MyApp\something.ttxt
  35.                         debug(cFile.url.replace(buildDir.url+"/","") +", " + cFile.size);//+ contents[i].size);
  36.                 }
  37.         }
  38. }
  39.  
  40.  
  41. function debug(str:String):void {
  42.  
  43.         debugTA.htmlText += str;
  44.  
  45. }
  46.  
  47.  

For the version living in a webpage, to check the size of the files uploaded, I created a small utility to check if files exist and are the same size via using URLLoader checking the loaded ByteArray.  This isn't as strong as MD5 but is still better than nothing. That FileExistsCheck(er) is here

Flash: Date+ Final + DescribeType + lack of IDate = Bug? Rant!

One of my largest issues with the conversion of AS2 to AS3 is the finalization of types, and the lack of interfaces for basic types. Finalization I can understand from a performance standpoint, the latter is annoying.

Am I missing something? Did Adobe/ECMA think that the core Date class could provide all that might be done?

The case in point is I'm trying to finish porting a Date Extension Utility class from AS2 to AS3. I think it was originally based on this one.   This should normally be straighforward. First snag, Date is now final...grrr. Okay so I'll wrap an inner Date object.   Next issue, Date has lots of methods to implement, and no interface...meaning I have to manually code them, but and there's not way for other classes to treat the new object as a Date object even though it will provide the same features.  Grrr! Which means all the places I used the extention now have to use "*" for type and type checking goes out the window..GRR!

I tried to shortcut and use describeType to help codeGen, but dammit only the accessors and 2 of the myriad of methods show up in the XML regardless if I use the static Date or an instance, the docs don't make it clear which properties are dynamic, which are most of them. Even so I tried for..in which should give some inclination and nothing either apparently it's not enumerable...what's up with that?   Out of curiosity since it's dynamic I tried to see if they could be appended to, can't since it's final.

<pre lang="actionscript">

var d:Date = new Date();

d["oldDate"]     = d.getDate;

d["getDate"] = function(){
trace("newGetDate");
return 3;

}

trace(d.oldDate() + " " + d.getDate());

//outputs

//Console: Warning: 3594: oldDate is not a recognized method of the dynamic class Date.

//Output window:    7 7
</pre>

This is not the first weirdness I've had with introspection, but that was in the early days. Kinda odd that half the introspection relies upon describeType (for the compile time) and the for-in for the dynamic type, instead of a consistent way.  I was hoping that by now they would have fixed it.

Flash: FLVPlayback.skinAutoHide issues, wierdness and Workaround

If your not familiar with it, FLVPlayback.skinAutoHide is a neat feature to fade in/out the prebuilt FLVPlayback skins in Flash CS3, in particular the semi-transparent ghosted ones that float above the video.

We've been having issues with the FLVPlayback.skinAutoHide where the controls won't show consistently regardless of what mouse movement is done over the FLVPLayblack video area. Trying to debug, It's hard to pin down, different browsers do different things, it is more consistently doesn't work when video is playing, on mac, and firefox. Oddly the left side of the controls tends to detect the mouse, when the right side (e.g. where the seek bar is) does not at all! I tried different skins to see if that might have been it, but no love.

Here's a workaround, detecting when the mouse is over the FLVPlayback manually, when it moves over the video turn off the skinAutoHide, when it's outside turn it back on (so it fades out).

  1.  
  2. var bnd:Rectangle = vidPlayer1.getBounds(vidPlayer1); //capture dimensions before transport is loaded! as the buffer bar is quite long+invisible.
  3. addEventListener(MouseEvent.MOUSE_MOVE, onMOUSE_MOVE);
  4. function onMOUSE_MOVE(evt:MouseEvent):void {
  5.        
  6.         var pnt:Point = new Point(vidPlayer1.mouseX, vidPlayer1.mouseY);
  7.         var hitMovie:Boolean = bnd.containsPoint(pnt);
  8.         trace("over movie? "+ hitMovie);
  9.         vidPlayer1.skinAutoHide = !hitMovie;
  10. }
  11.