New: iPhone/iPad development course in Belgium in August.

28 Jun 2005

We had some extra time during my recent Best Practices Flash and Flex class and, at the request of the class, decided to cover FAMES. As part of this, we downloaded the latest Swfmill, which has support for linking classes to clips directly in the SWFML file. I thought we might as well use this new functionality as it is cleaner than littering your code with Object.registerClass statements. Little did I know at the time that this little addition would actually result in a huge shift in workflow. Much head-scratching later, I was able to come up with a workflow that is actually much simpler to work with than the current workflow. The problem is that currently it does not work with FAMES (Flashout, the "F", doesn't currently support this workflow) so you will have to use the command line for the time being.

Before we look at this new method, though, let's review the original method for working with Swfmill that has been popularized both here and elsewhere:

The Skeletal Injection Method

The original way of using Swfmill and MTASC together involves injecting a Swfmill Skeletal SWF with code. I'm calling this the Skeletal Inject Method. In this workflow, the skeletal SWF created by Swfmill only contains library assets and the only way to create an entry point into the application is to use a static main() method and compile using the –main attribute in MTASC.

The steps for creating a Flash application using the Skeletal Injection Method are:

1. Describe a skeletal SWF with library items using Swfmill's Simple (swfml-s) dialect (eg. skeletal.xml)

2. Use swfmill to compile the skeletal SWF (eg. skeletal.xml -> skeletal.swf )

3. Create an ActionScript 2 class with a static main() method and compile and inject it into your skeletal SWF using MTASC. If you want to link movie clips in your library with classes, you need to use Object.registerClass to do so in your class. You can, of course, also choose to assimilate _root and do all sorts of wonderful things along the way.

Pros:

  • The original way, so you most likely know it
  • Quick workflow that is currently supported by visual tools such as Flashout and AsAlter
  • Intuitive
  • You can still use it!

Cons:

  • Have to use Object.registerClass in code to link movie clips to classes
  • Use of static main() method as entry-point doesn't feel natural for Flash applications
  • Contains quite a few steps

The Natural Entry Point Method

The Natural Entry Point Method involves the use of at least two SWFs in your application. The first one is your main Application SWF and the second is a Classes SWF that contains the compiled code of your classes.

Your Application SWF contains your library, including any forms (movie clips that you link to classes using the new class attribute of the Swfmill <clip> tag.) Unlike the Skeletal Injection Method, which only contains a library, your Application SWF has to actually place a form (movie clip) on the Stage to provide a natural entry point for the application.

Instead of keeping your classes in the main application SWF, you keep them in a separate Classes SWF and import them into the main SWF as an external asset (at compile time).

In the next section, you will recreate the particles sample application which was previously constructed using the Skeletal Injection Method using the Natural Entry Point method instead.

Prerequisites: You will need to have Swfmill and MTASC installed and on your path. This example uses the command line (you don't need FAMES or other GUI tools to complete it.)

Natural Entry Point Example

Download the source files (NaturalEntryPointExample.zip; 106kb)

First, create the main application SWFML file, application.xml. The listing for this shown below:

SWFML-S:
  1. <?xml version="1.0" encoding="iso-8859-1"?>
  2. <movie width="320" height="240" framerate="30">
  3. <background color="#ffffff"/>
  4. <!--
  5. The Application and Particle classes have been
  6. compiled into the classes.swf file, which we
  7. import as an asset. This makes the classes
  8. available for linking to our movie clips.
  9. -->
  10. <clip import="classes.swf" />
  11. <frame>
  12. <!--
  13. The Library contains the Application form, linked
  14. to the Application class and the EclipseLogo
  15. sprite, linked to the Particle class.
  16. -->
  17. <library>
  18. <clip id="Application" class="Application" />
  19. <clip id="EclipseLogo" class="Particle" import="library/eclipse32.png" />
  20. </library>
  21. <!--
  22. Place an instance of the Application form on Stage
  23. to instantiate it and provide the Natural Entry Point.
  24. -->
  25. <place id="Application" name="app" x="0" y="0" depth="1000" />
  26. </frame>
  27.  
  28. </movie>

Let's break this down:

At the very top, you set up the movie's dimensions and background color as before.

Next, you import your Classes SWF. This file will eventually contain the compiled versions of the classes you will be using in the application.

Next, you start the first frame of the application and define a library there. In it, you create two clips (movie clip symbols).

The first one is an empty movie clip. Its Symbol ID is Application and, using the new class attribute, you are linking it to the Application class in the default package (for the sake of brevity, I did not use a package structure in this sample – in the form org.flashant.naturalEntryPointSample.*) as would be the norm for any real application).

The second movie clip symbol has a Symbol ID of EclipseLogo and is linked to the Particle class in the default package. You are asking Swfmill to import the eclipse32.png found in the library folder of your project and place it in the movie clip.

Finally, you need a way to instantiate your application and to do this, you place an instance of the main Application form (the movie clip with Symbol ID "Application" that is linked to the Application class) on the Stage using the <place> tag. In the tag, you give the Application form an instance name (not really necessary as it will contain all other objects and thus none will refer to it using its instance name) and specify its location and depth.

Now, you need to create the Application and Particle classes and compile them into the Classes SWF.

The Particle class, shown below, has not changed at all from the previous example:

ActionScript:
  1. class Particle extends MovieClip
  2. {
  3. var vX:Number = null;
  4. var vY:Number = null;
  5. var randomness:Number = null;
  6.  
  7. function Particle ()
  8. {
  9. _x = _width + Math.random() * ( Stage.width - _width );
  10. _y = _height + Math.random() * ( Stage.height - _height );
  11. _rotation = Math.random() * 360;
  12. var randomness = Math.random()*5;
  13. vX = Math.random() * randomness + 1;
  14. vY = Math.random() * randomness + 1;
  15. }
  16. function onEnterFrame ()
  17. {
  18. _rotation += 1.69;
  19. _x += vX;
  20. _y += vY;
  21. if ( _x < 0 || _x > ( Stage.width - _width/2 ) )
  22. {
  23. vX *= -1;
  24. _x += 2 * vX;
  25. }
  26. if ( _y < 0 || _y > ( Stage.height - _height/2 ) )
  27. {
  28. vY *= -1;
  29. _y += 2 * vY;
  30. }
  31. }
  32. }

The Application class, however, is considerably different:

ActionScript:
  1. import LuminicBox.Log.*;
  2.  
  3. class Application extends MovieClip
  4. {
  5. var tfCaption:TextField;
  6. // Clips attached dynamically from Swfmill library
  7. var mcSpheres:MovieClip;
  8.  
  9. var sW:Number = null; // Stage width
  10. var sH:Number = null; // Stage height
  11. // Log
  12. var log:Logger;
  13. function Application ()
  14. {
  15. // Setup logging
  16. log = new Logger();
  17. log.addPublisher ( new ConsolePublisher() );
  18. log.info ( "Application::Constructor" );
  19. }
  20.  
  21. function onLoad ()
  22. {
  23. log.info ( "Application::onLoad" );
  24. log.debug ( "this = " + this );
  25.  
  26. // Store stage dimensions for easy look-up
  27. sW = Stage.width - 1;
  28. sH = Stage.height - 1;
  29. // Draw border around the stage
  30. lineStyle ( 1, 0x000000 );
  31. moveTo ( 0, 0 );
  32. lineTo ( sW, 0 );
  33. lineTo ( sW, sH );
  34. lineTo ( 0, sH );
  35. lineTo ( 0, 0 );
  36. //
  37. // Create a message
  38. //
  39. var captionTextFormat = new TextFormat();
  40. captionTextFormat.size = 12;
  41. captionTextFormat.font = "_sans";
  42. var captionText:String = "Swfmill + MTASC Natural Entry Point Sample";
  43. var captionTextExtent:Object = captionTextFormat.getTextExtent ( captionText );
  44. var captionWidth:Number = captionTextExtent.textFieldWidth;
  45. var captionHeight:Number = captionTextExtent.textFieldHeight;
  46. var captionX = sW / 2 - captionWidth / 2;
  47. var captionY = sH - captionHeight;
  48. createTextField( "tfCaption", 10000, captionX, captionY, captionWidth, captionHeight );
  49. // Write caption text
  50. tfCaption.text = captionText;
  51. // Add ten particles
  52. for ( var i = 0; i < 10; i++ )
  53. {
  54. // Attach a sphere clip
  55. attachMovie ("EclipseLogo", "eclipseLogo" + i, 1000 + i );
  56. }
  57. }
  58. }

The main difference is that it no longer has (or needs) a static main() method to provide an entry point. By placing the Application form on Stage using swfml, you have created a natural entry point: Flash will automatically call the Application class' constructor.

In it, you set up the LuminicBox Logger and trace out an info message to signal that the constructor has, in fact, initialized (I've included the latest version of LuminicBox Logger in the files for this tutorial.) The really juicy stuff happens in the onLoad() event handler that gets called automatically in Flash.

In the onLoad() event handler, you first trace out an info message to confirm that the event handler has fired and then trace a debug message to confirm that the movie clip has initialized with the correct scope (things you may feel the need to do when you first try this method, as I did.) Notice that the scope is different from when we were assimilating _root using the Skeletal Injection Method – the Application form is _level0.app not _level0.

The rest of the code in the onLoad() method hasn't changed at all from the version in the previous tutorial. The only difference is that instead of the Particle instances being attached to _level0, they are being attached to _level0.app.

If you use ARP, the open-source pattern-based framework for the Flash Platform, you will no doubt have noticed how directly this applied to ARP application development in Flash and Flex: It uses exactly the same workflow.

Now that your source files are ready, all that remains is to compile them. You are going to compile the classes and create the Classes SWF in one step, using MTASC's -header argument. The -header argument allows you to specify the width, height and frame rate of a SWF and makes MTASC create a SWF with those properties and inject the compiled classes into it. (So you don't have to create an empty skeletal SWF using Swfmill.)

To do this, switch to your project folder in the command line and type the following, replacing the path in the classpath (-cp) with the path to the Flash MX 2004 classes folder on your computer:

mtasc –cp "C:\Documents and Settings\Aral Balkan\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Classes" -header 1:1:30 –swf classes.swf Application.as Particle.as

(Note: If you want to use the LuminicBox Logger in your own applications, do not copy an instance of it into each of your project's folders. Instead, keep it in a single location and add another classpath while compiling by adding a second –cp argument.)

Finally, use Swfmill to compile your main application SWF by entering:

swfmill simple application.xml application.swf

Run the application.swf and you should see the animated particles.

Pros:

  • Simple, familiar workflow
  • Provides a natural entry point
  • Don't have to use Object.registerClass manually
  • Fits in with ARP workflow

Cons:

  • Have to compile both your classes and your assets/main application when your classes change (ie., not as performant as the Skeletal Injection Method)
  • GUI tools do not currently support this workflow

I definitely prefer the Natural Entry Point Method to the Skeletal Injection Method and will be using it in my own projects. On the whole, it is simpler, more flexible and the workflow is identical to that used in an ARP project (although you can also use the Skeletal Injection Method with ARP projects as long as you either assimilate _root or, better yet, assimilate an application movie clip that you've placed on the _root timeline using Swfmill.)

Regardless of whether you use the Natural Entry Point or Skeletal Injection methods, the combination of Swfmill and MTASC offer a world of possibilities for Flash developers and for that I am eternally thankful to Nicolas Cannasse, Daniel Fischer and Mark Winterhalder – thanks guys for making all this possible :)

Download the source files (NaturalEntryPointExample.zip; 106kb)

Add Your Comment

Spam Protection by WP-SpamFree

The Natural Entry Point Method (Tutorial & Source Files) – Introducing A New Way to Create Flash Applications Using Swfmill and MTASC

  1. Thanks again to Daniel for reminding me last night in the #osflash IRC channel that I can use the -header argument in MTASC to save an additional swfmill compilation step. I’ve modified the article to use this method.

    Aral Balkan
  2. Thanks for the example Aral. And you are right. MTASC and Swfmill are great tools that make it all possible, along with ASDT.

    I am now building my whole application, both Flash and Java with one build. Really great and keeping all programming inside Eclipse.

    One question I have – and maybe it shouldn’t be here, but in the osflash mailing list – is whenever you have a Java/Flash application. Do you create a Java project in Eclipse and then add .as-classes in a Flash directory or do you create a Flash project and then add your Java code to the project?

    Kim Hansen
  3. I would currently go with creating a Java project and then adding the AS classes as JDE is a much more robust perspective. But I guess you could do both and then import one into the other using virtual folders, couldn’t you?

    Aral Balkan
  4. Well, until now I create a Java project and add the AS classes, just like you suggest. The thing with virtual folders doesn’t really appeal to me, but my suspicion is not backed with any real testing.

    Kim Hansen
  5. Hi Aral. I translated an article from Carlos Rovira this week, and was thinking on asking you something. Are you interested in having some of your OSFlash Articles translated into spanish? If so, let me know, I’m willing to.
    Cheers.

    vscorza
  6. I tried this for the first time yesterday. Works great, nice article. I am expanding on this to start building larger applications and just noticed the variable mcSpheres in the Application class is not referenced or refered to by anything. I removed it and the swf compiled and ran just fine. The comment says “Clips attached dynamically from Swfmill library”. How is this intended to be used? or am I missing the point of the variable? thanks.

    matt
  7. Great tutorial Aral. I’ve just watched Grant Davies’ tutorials on using MTASC with ARP, and while it works great, I think I like the natural entry point more. One hiccup however: the project I’m building uses a ridiculous amount of v2 components (I’m still new at this, so haven’t been able to figure out how to use OS components {the first component from the BBC’s SMX set didn’t work}). I read on the swfmill tutorial pages that v2 component classes can be included several times, which is not good news. So, which component set do you use, if any? Presumably, with large projects being built, there would be a need for at least a few components in each project?

    Many Thanks,
    Lazy Gekko

    lazygekko
  8. Hello Aral,

    I started using your method just today, it’s just wonderful, but…

    How can you use trace() on it.

    glantucan
  9. What are you looking to trace? Tracing a value should work normally regardless of which entry point method you use. I don’t understand the question :)

    Aral Balkan
  10. Well, I realized I made a mistake, thinking it’s the compiler who spits out the traces.

    I see now you need eclipse and flashout for that.:D

    But, as the natural entry point it’s not working in that manner there must be another way, am I right?

    Perhaps, this is not the place to ask about that.

    Would you kindly tell me where (forum or mailing list) could I ask you or other about this?

    Thank you very much

    Glantucan

    glantucan
  11. Hey Glantucan, check out the OSFlash mailing list. It’ll be easier to have this conversation there and others can help out too! :)

    Aral Balkan
  12. Thanks a lot. See you there :D
    Glantucan

    glantucan
  13. Thanks for this very nice article. It was very helpful, even though I’m writing in haxe, not actionscript. I did want to mention that the source code examples are very hard to read, at least in the browser I’m using, because the scroll-boxes were too narrow, so I had to constantly scroll left and right to read the code.

    RetroJ
  14. Heippa, nice approach, and indeen a very well written article,

    just for anybody considering of adapting the method: The general disadvantage is that you cannot access the content of included library-swf’s by script, as MTASC does not know them at compile time and complains about not-exsisting properties. So if you use swf’s you want to dynamically tweak later by script the Skeletal Injection Method works better. If you use the swf’s as passive content the Natural Entry Point approach might be something to have a closer look at.

    Have fun finding your own ways in ActionScript.

    Alex

    Alexander Bethke
  15. Perhaps a silly question, but where do you get the MX 2004 class files from? Is that something that just gets installed with Flash, or is there another way to get those files? Also how do those class files differ from the files that come with mtasc in the std and std8 folders? Finally, I have been successfully building projects without the MX 2004 classes in my classpath. Do you find you use them often for your projects? Thanks so much for your helpful articles. Your blog has been super helpful for me.

    Daniel Worthington
  16. Great article Aral, I’m trying to adapt the sphere animation so it uses a single tween in the constructor instead the onEnterFrame method (code below). I’m embedding the application.swf in a container swf that allows the user to switch between swf’s. The animation plays correctly the first time the swf is displayed but fails if the swf is displayed again.

    >>> modified particle.as code >>>

    import mx.transitions.easing.*;
    import mx.transitions.Tween;
    class Particle extends MovieClip
    {
    function Particle ()
    {
    _x = 10;
    _y = 10;
    var tween:Tween = new Tween(this, “_y”, Strong.easeOut, 300, 65, 2, true);
    }
    }

    Monte Aspevig
  17. [...] subclasse de MovieClip como novo "ponto de entrada", Document Class. Este processo foi chamado de Natural Entry Point por Aral [...]

    {Code}Trip » Flash em ambiente Open Source
  18. I know this is really old but its been useful for my chumby project, thought id share this, i got thunderbolt logger working in the web browser with this demo using ant.

    To automate this process I created an ant build file to do this and it works great with his demo except I wanted to debug in the browser with thunderbolt because thunderbolt rocks.

    Eventually I realized I needed a way to apply thunderbolt to the swf after it was created. This is a quirk caused by the way this example is set up using mtasc to precompile the classes and swfmill to then import and link them with resources enabling a “natural” entrypoint for class instantiation. Which I like alot as well.

    Long story short, I realized using mtasc I could do just this,
    basically leave the swf unchanged using the -keep flag and adding in the thunderbolt with -trace. The beautiful part of all this is that I can ignore thunderbolt in my code writing and I can apply thunderbolt to ANY swf file. Now I can have a production version built with swfmill and a dev version produced from that swf meaning I don’t have to pull things out of my code before I do a production build.

    ++++++++++ ant build.xml +++++++++++

    loot
  19. hmm didnt keep my xml not surprised… ok so go over to the flash-thunderbolt google group and look at june 14th 2010 for the ant code example. Basically you take a swf file and run mtasc on it with the -keep flag to leave the classes as they are and use -trace to apply thunderbolt

    loot