Archive for January, 2010

AS3 and Big Numbers

Wednesday, January 27th, 2010

I ran into a problem when transferring large numbers between the client and server. They would send me a number and when I sent it back to them it would be different. Turns out ActionScript 3 has problems with big numbers. Here is a quick example. The expected output would be 129090238754375001.

  1. var string:String = "129090238754375000";
  2. var number:Number = Number(string);
  3. var nextNumber = number + 1;
  4. trace(nextNumber);

Here are the variables after execution. Notice that both number and nextNumber are 129090238754375008.

Screenshot showing variables at breakpoint

And the output window:

Output window showing 129090238754375000

So int has a range of -2,147,483,648 to 2,147,483,647 and uint has a range of 0 to 4,294,967,295. While Number can represent integers outside the range of int and uint, it has precision limitations.

The solution in our case was that, since we were not doing any math and just using it as an identifier, we changed the server code to use a string instead.

Ultimate Reset of a Loaded AS3 MovieClip

Wednesday, January 27th, 2010

I had a project that loaded individual SWF files for playing in sequence. There were the typical play, pause, previous, next buttons. The SWFs were loaded via Loader. An MP3 file was associated with each SWF.

If the loaded SWF had no nested movieclips, everything went smoothly with movieClip.stop(), movieClip.play(), etc. However on this project, there were nested movieClips in the SWF, so these all needed to be stopped when the user pressed pause, and restarted when the user pressed play.

  1. private function stopMovieClipAndChildren(content:DisplayObjectContainer):void
  2. {
  3.     if (content is MovieClip)
  4.         (content as MovieClip).stop();
  5.     if (content.numChildren)
  6.     {
  7.         var child:DisplayObjectContainer;
  8.         var n:int = content.numChildren;
  9.         for (var i:int = 0; i < n; i++)
  10.         {
  11.             if (content.getChildAt(i) is DisplayObjectContainer)
  12.             {
  13.                 child = content.getChildAt(i) as DisplayObjectContainer;
  14.                 if (child.numChildren)
  15.                     stopMovieClipAndChildren(child);
  16.                 else if (child is MovieClip)
  17.                     (child as MovieClip).stop();
  18.             }
  19.         }
  20.     }
  21. }
  1. private function playMovieClipAndChildren(content:DisplayObjectContainer):void
  2. {
  3.     if (content is MovieClip)
  4.     {
  5.         var movieClip:MovieClip = content as MovieClip;
  6.         if (movieClip.currentFrame < movieClip.totalFrames) // if the main timeline has reached the end, don't play it
  7.             movieClip.play();
  8.     }
  9.     if (content.numChildren)
  10.     {
  11.         var child:DisplayObjectContainer;
  12.         var n:int = content.numChildren;
  13.         for (var i:int = 0; i < n; i++)
  14.         {
  15.             if (content.getChildAt(i) is DisplayObjectContainer)
  16.             {
  17.                 child = content.getChildAt(i) as DisplayObjectContainer;
  18.                 if (child.numChildren)
  19.                     playMovieClipAndChildren(child);
  20.                 else if (child is MovieClip)
  21.                 {
  22.                     var childMovieClip:MovieClip = child as MovieClip;
  23.                     if (childMovieClip.currentFrame < childMovieClip.totalFrames)
  24.                         childMovieClip.play();
  25.                 }
  26.             }
  27.         }
  28.     }
  29. }

(my google search landed me here before writing my own)

Clicking the previous button presented a problem however. Calling movieClip.gotoAndStop(1) on the movieClip (and even all its children) was not putting it back to its “new out of the box” state. I needed a way to do an ultimate reset of the movieClip but since it was a loaded SWF, I didn’t have the class to do:

  1.  movieClip:MovieClip = new SomeLoadedMovieClip();

However, after reading this blog I found out how.

  1. private function resetMovieClip(movieClip:MovieClip):MovieClip
  2. {
  3.     var sourceClass:Class = movieClip.constructor;
  4.     var resetMovieClip:MovieClip = new sourceClass();
  5.     return resetMovieClip;
  6. }

Use it like this:

  1. stopMovieClipAndChildren(movieClip);
  2. // remember to remove all event listeners from movieClip and anything that references it
  3. // remove movieClip from the display list
  4. removeChild(movieClip);
  5. // reset the loaded movieClip by creating a new instance of it
  6. movieClip = resetMovieClip(movieClip);
  7. addChild(movieClip);