Getting started with Starling for ActionScript 3.0

David Armstrong
Last updated:
GitHub
Getting started with Starling for ActionScript 3.0

Learn how to create a texture atlas in TexturePacker and use it in a simple Starling for ActionScript 3.0 application. You'll learn how to:

  • Set up a Starling project
  • Use TexturePacker for your texture atlas
  • Include the texture atlas in your Starling project

Full source code is available on GitHub

Introduction

In this tutorial you are going to learn how to create a texture atlas in TexturePacker and use it to create an animation of a walking character in a simple Starling application.

What skill level is expected?

Using TexturePacker is extremely easy, however the Starling implementation requires an intermediate knowledge of:

  • ActionScript 3.0
  • Starling framework
  • Object oriented programming

A texture atlas (also sometimes referred to as a sprite sheet) is typically a large bitmap image that includes multiple images. We are going to use our texture atlas to construct the frames of an animation, a background image and two buttons.

Also, if you want you can download an archive with all the project’s files from GitHub.

Let’s begin our journey with some prepping.

Preparation

Here’s what we'll need to prepare:

  1. Software Development Kit
  2. Code Editor / IDE
  3. Game Development Framework
  4. Texture Atlas creation: TexturePacker

Let’s start from the top of the list.

1. Software Development Kit

Note: For those choosing to use the older Adobe AIR SDK v32 (last release before Harman took over care of the AIR SDK), you may be able to download it from here. Adobe ceased providing support for this version in 2020. It is free to use, but may have limited or no support on modern devices.

Install AIR SDK and configure environment

You'll need to have a version of the AIR SDK installed on your system. The latest release of the Harman AIR SDK can be downloaded using the AIR SDK Manager. Grab the AIR SDK Manager from here, and install it:

When you launch the AIR SDK Manager, you'll need to choose where it will place the AIR SDK. In the example below (Windows), I've set it to save in my user account's sdks\air folder.

AIR SDK Manager AIR SDK location

Now install an AIR SDK (typically the latest), but hitting the "Install" button next to the corresponding version.

Next you need to set up an Environment Variable and ensure the AIR SDK is in your system path so build commands can be executed.

Please reference the appropriate guide to setup your Environment:

Once done, test the AIR SDK is correctly installed by opening up a terminal / command-prompt, and entering adt -version. If successful the command will execute and present the adt version you have installed. If this step fails, even after a system restart (sometimes needed after Environment update), review the above OS specific Environment guides again before continuing:

C:\Users\tutorial>adt -version
51.2.2.4

Install Java JDK

You'll also need to install the Java JDK. Check the current recommended version.

After installing that, configure the AIR SDK Manager so it's pointing to it. Do this by going to the Configuration tab and browsing to your Java installation folder. Click "Apply" to save the configuration.

AIR SDK Manager Java JDK location

Install AIR Package Manager (APM)

The AIR Package Manager is a relatively new tool, that assists with creating AIR applications, and managing AIR libraries and extensions. We'll use this later to install the Starling library.

In AIR SDK Manager, go to the "Tools" and provide a location for the AIR tools to be installed into, and then click "Install". I used C:\Users\<user-name>\bin\air-tools.

AIR SDK Manager APM location

You'll also need to add the newly installed AIR tools to your system path, by setting up an Environment Variable, much like you did for the AIR SDK. Refer to this guide for how to do that in your specific OS:

Once you've done this, check that it's working by opening the command prompt / terminal, and running apm -version:

C:\Users\tutorial>apm -version
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@                                                                                                       @
@                                                                               #######                 @
@                            //((((((((((((((\                                ############              @
@                       ((((((               ((\                             ##############             @
@                   ((((//     ____-------__((/__                           ##############              @
@                (//____-------             (/   \.                        ###############              @
@                                                                       ######     #######              @
@  ##    #    /#    ######   ##      /#    /#    ##     #          ########           ####              @
@  ##....#   /# #   ##   |#  ####   /##   /# #   # ##   #      ###########             ####             @
@  ##''''#  /# ''#  ##--##   ## ## /# #  /# ''#  #   ## #    #############             #####            @
@  #/    / /#     # #/    #\ #/   /#  / /#     # /     #/    ##############           ########          @
@                    A   S A M S U N G   C O M P A N Y        #################   ##############        @
@        (\             .../       __--''                        ################################   TM  @
@        ( ----____...**  _____----                                               ##############        @
@         \__..''''   ----                                                           ##########         @
@                                                                                                       @
@                                                                                                       @
@                                                                                                       @
@                                                Contains Adobe AIR Technology by Adobe Inc and HARMAN  @
@                                                                                                       @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2.1.0

If that hasn't worked, review the Environment setup again. You may also simply need to restart the system so those changes come into effect.

For general information on using Air Package Manager:

2. Code Editor / IDE

Note: This tutorial covers usage of Microsoft Visual Studio Code / VSCodium. For how to setup alternative IDE's such as IntelliJ IDEA, or Moonshine IDE, you might refer to this guide.

Install Visual Studio Code

Since its release in 2015, Microsoft Visual Studio Code has become the de facto standard for professional, free and open-source development. It's available on all major desktop operating systems, including Windows, Mac OS, Linux and BSD. Alternatively, VSCodium is Visual Studio Code compiled without Microsoft's telemetry.

Download either:

For simplicity, this tutorial will now only reference VS Code (Microsoft Visual Studio Code), however all of the steps that follow are identical for VSCodium.

Install AS3, MXML and SWF support

Once VS Code is installed, launch it and step through the initial setup process. Next, let's enable ActionScript 3.0 support by installing a VS Code extension pack. To do that, follow the installation instructions at this link:

That extension was created and is maintained by Josh Tynjala, one of the active contributors to Starling. For more information on how to install and use the features the extension provides, look here.

In VS Code, go to the Explorer tab (1) and Create ActionScript Project (2).

Point it to a folder location for your new project. For example, I used C:\Users\<user-name>\Documents\tutorial01\.

Create a new ActionScript project

After selecting a project folder, you'll be asked to select an AIR SDK. If you completed the the previous step, the AIR SDK should appear in the list. Select it.

Select the AIR SDK

You'll then be prompted to set this project as a desktop or mobile project:

  • ActionScript Desktop
  • ActionScript Mobile

For this tutorial, I'll be selecting ActionScript Desktop.

Test that the scaffold project builds correctly by performing these two steps (which you'll use often):

  1. Compile a debug build:

    Perform a build task.

    • Windows / Linux: Ctrl + Shift + B
    • macOS: Cmd + Shift + B

    Select "ActionScript: compile debug - asconfig.json" to perform the build task.

    Compile debug build
  2. Run Debug:

    • Windows / Linux: F5
    • macOS: Fn + F5, or just F5

All going well, the AIR application was built, and run. You should now see:

Run Debug

If this fails, review the steps so far, before proceeding.

3. Game Development Framework

Now we'll make the Starling framework available for use in our project.

Download the Starling Framework

Earlier we installed AIR Package Manager (APM). We'll use this now to install Starling. Here are the three commands you will use:

  • apm init to initialize our AIR application
  • apm search <library-name> to search for the library we need
  • apm install <library-name> to install the library

Open a command prompt / terminal, within your project folder. In my case, that's within C:\Users\<user-name>\Documents\tutorial01\. Now run apm init to initialize your AIR application. Give your application an identifier and name. For example:

C:\Users\tutorial\Documents\tutorial01>apm init
...
Creating new project definition file
Application Identifier [com.my.app]: tutorial01
Application Name [My Application]: Tutorial01
Application Version [1.0.0]:

Now your AIR application is initialized, you can install libraries using apm (AIR Package Manager). You'll need to use the correct name when referencing a library to install, so to figure out what we need to install Starling, run apm search starling:

C:\Users\tutorial\Documents\tutorial01>apm search starling
...
⣾ Searching packages for : starling
✓ Search complete
found [18] matching package(s) for search 'starling'
├──starling@2.7.0   The Cross Platform Game Engine
├──starling-source@2.7.0   The Cross Platform Game Engine
├──com.example.swc@1.0.0   SWC Template
├──feathersui@4.1.1   Cross-platform user interface components for creative frontend projects built with Starling
...

In that list, we have two suitable options: starling (the precompiled swc version), or starling-source. Personally, I prefer starling-source as it offers some flexibility if you ever need to modify Starling for your project.

Install the latest release of Starling with apm install starling-source:

C:\Users\tutorial\Documents\tutorial01>apm install starling-source
...
⣾ Finding package : starling-source@latest
✓ Found package: starling-source@2.7.0
Installing package : starling-source@2.7.0
Downloading package : starling-source@2.7.0
✓ Package retrieved from cache
⣽ extracting C:\Users\tutorial\.airsdk\cache\airpackages\starling-source\starling-source_2.7.0.airpackage
✓ extracted
Installed package : starling-source@2.7.0
⣻ Deploying package: starling-source@2.7.0
✓ Deployed: starling-source@2.7.0

Adding Starling to our project source

In VS Code, we need to let the project know where to find source files installed by apm.

In your project's root directory, there is a file called asconfig.json. Open that in VS Code and edit the "source-path" section, to also include libs_src:

{
	"config": "air",
	"compilerOptions": {
		"source-path": [
			"src",
		    "libs_src"
		],
   ...

Be sure to Save your changes.

Starling's limitations

Starling is highly focused on GPU accelerated display objects. It works exclusively with Stage3D, which has huge performance benefits. However, this means it has some limitations regarding native Flash display objects, which operate outside the GPU and do not typically utilize Stage3D. As such, Starling's display list operates separate from the standard Flash display list.

In practice, traditional Flash display objects can't be added to the stage within a Starling instance, and visa versa. When using Starling, everything within the Starling instance leverages Starling's display list, while native Flash objects sit outside it.

Below we'll update your projects main file, and add a new file called StarlingRoot.as. That new file, will represent your Starling instance.

Basic Starling test

Let's build a minimal Starling project, to ensure the Starling source has been correctly referenced. We'll build on this file as we continue, so this is simply the first step.

In your project's src\ folder, create a file called StarlingRoot.as, and provide it with the code below. This file represents the beginning (root) of your Starling context. Everything we bring into this class will not be working with native Flash display objects, they're not compatible. We'll be working purely with Starling's GPU accelerated display objects:

src\StarlingRoot.as
package
{
    import starling.display.Sprite;
    import starling.events.Event;
    import starling.text.TextField;
    import starling.text.TextFormat;

    public class StarlingRoot extends Sprite
    {
        public function StarlingRoot()
        {
            super();

            // Ensure stage is ready first.
            if (stage == null)
                addEventListener(Event.ADDED_TO_STAGE, init);
            else
                init();
        }

        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            // Create "Hello world" text field.
            var textFormat:TextFormat = new TextFormat("mini", 32, 0x0000FF);
            var textField:TextField = new TextField(320, 100, "Hello world, from Starling!", textFormat);
            textField.x = (stage.stageWidth - textField.width) / 2;
            textField.y = (stage.stageHeight - textField.height) / 2;
            addChild(textField);
        }
    }
}

To start Starling, we need to instantiate and start it, from our main project file. For me the main project file was tutorial01.as, created automatically when I created the project. Open your main project file and modify it to the following (replacing tutorial01 references with the name of your main class):

src\tutorial01.as
package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import starling.core.Starling;

    [SWF(width="640", height="960", backgroundColor="0xFFFFFF")]
	public class tutorial01 extends Sprite
	{
		public function tutorial01()
		{
			super();

			// Wait for stage.
			if (stage == null)
				addEventListener(Event.ADDED_TO_STAGE, init);
			else
				init();
		}

		private function init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);

			// Instantiate and start Starling.
			var starling:Starling = new Starling(StarlingRoot, this.stage);
			starling.start();
		}
	}
}

RenderMode

Now if right now you build (Ctrl + Shift + B) and run (F5) this, you will encounter a "Context3D not available!" error:

Context3D Error

One more setting needs to be adjusted to set the correct renderMode for Starling. An XML file named after your project (eg: tutorial01-app.xml) was automatically created in the src folder. Find your XML file and open it in VS Code.

Scroll down to the line starting with <!-- <renderMode></renderMode> --> and uncomment and set it to:

src\tutorial01-app.xml
<renderMode>direct</renderMode>

Now, rebuild (Ctrl + Shift + B) and run (F5) your project. All going well, you should now see:

Context3D Error

Preparing asset folders

We need a place to put our assets, such as our texture atlas image and its corresponding XML file when we create these later with TexturePacker.

In your project's main folder, create a new folder called assets. Inside that, create another folder called atlas. The full path within your project should be:

assets\atlas\
Assets folder

When building your AIR application, the application directory is the bin (binary) folder. As such, you need to ensure all assets needed by your application are copied into this folder.

Fortunately, there is a simple way to ensure that the entire contents of the assets folder will be copied into your bin folder automatically each time you build your project.

In VS Code, once again find the asconfig.json file in your project's main folder and edit it. We'll be adding the following property:

asconfig.json
{
  ...
  "airOptions": {
    "files": [
      {
        "file": "assets",
        "path": ""
      }
    ]
  }
}

This simply ensures that everything inside the assets folder is copied into the bin folder when you build your project. Alternatively, you could be more specific about defining which folders or files are copied over, but I've taken a broad approach here. Just be careful not to put any files that shouldn't be bundled with your application, inside the assets folder.

For reference, here my full asconfig.json file, to you can see where this new "airOptions" property is placed. Note the comma (,) that I needed to add at the end of what was previously the last property, "mainClass"...,.

asconfig.json
{
	"config": "air",
	"compilerOptions": {
		"source-path": [
			"src",
			"libs_src"
		],
		"library-path": [
			"libs"
		],
		"output": "bin/tutorial01.swf"
	},
	"application": "src/tutorial01-app.xml",
	"mainClass": "tutorial01",
	"airOptions": {
		"files": [
			{
				"file": "assets",
				"path": ""
			}
		]
	}
}

You can now save and close the asconfig.json file.

4. Texture Atlas creation: TexturePacker

TexturePacker is an application that allows us to create highly optimized texture atlas' in an extremely easy and intuitive way. If you don’t already have it installed on your computer, you can download and install a trial version from here:

Creating sprite sheets for your game

Why TexturePacker for Starling?

  • Auto-detects identical sprites to reduce atlas size and memory footprint
  • Trimming, rotation, and multipack support to maximize packing efficiency
  • Exports Starling/Sparrow data format that works out of the box

Adding sprites to your texture atlas

First, we are going to need some graphics to create our texture atlas. For your convenience, I have created an archive with all the graphics that we’ll need for this tutorial.

Download it from GitHub.

Extract the content of the archive into a folder external to your project. Go into that new folder and find the folder called graphics.

Now launch TexturePacker. In the Settings section on the right-hand side of the TexturePacker interface, choose a Framework. We'll be selecting the Sparrow / Starling framework, if it isn't already selected.

Select framework

Next, drag and drop that graphics folder into TexturePacker’s Sprites Panel.

Drop sprites in

This simple action ensures that TexturePacker picks all the images contained in your graphics folders and includes them in a single texture atlas. Moreover, whenever you need to add more images to your texture atlas, all you have to do is to add them to the graphics folder and TexturePacker will automatically add them to the same texture atlas. Sweet!

Now check the Auto Fit fix at the bottom of the window, so you can see all of your sprites at once.

Auto-fit

All our images are PNGs but TexturePacker reads many other graphics formats as well, such as JPG, PSD, SVG, BMP, TIFF, SWF and others!

At the moment, you will see every frame of the walking_guy animation displayed in the preview area, taking up roughly half the texture atlas. TexturePacker is able to do some pretty incredible things though to optimize your texture atlas', and one those is its ability to detect identical sprites.

To see that setting, and others, hit the Advanced settings button near the bottom right corner of the TexturePacker interface. Scroll down until you see Detect identical sprites and tick the check-box.

TexturePacker: Identical images stack

Instantly, that should halve the number of walking_guy sprites in your texture atlas, from 16, to 8!

Notice how some of the images have a little stack of paper icon next to them:

TexturePacker: Identical images stack

That is because some frames of our walking animation contain exactly the same bitmap information. TexturePacker is a smart puppy and when it finds identical images it stores them just once in the texture atlas: no need to include the same information twice and waste precious memory!

Setting output parameters

Before we move ahead, let me go into a tiny bit of theory to understand what we are doing next. As said earlier, a texture atlas is a very large bitmap image that includes a bunch of sprites. In order for our application to use it correctly though, we need to tell it what the boundaries of each individual image are within the texture atlas.

TexturePacker will do this for you automatically by creating two files:

  • The texture atlas (the big bitmap image)
  • An XML file that contains the information about each sprite's boundaries

This is a huge time saver. Imagine having to write a data file with every sprite's coordinates and dimensions manually! So, in the next step we tell TexturePacker where to save these two files within our project's directory structure.

First, let’s take care of the data file. Click on the Data file icon:

Data file icon

Navigate to the atlas folder in your project we created earlier ( assets\atlas\ ). In the File name field type atlas and then click on the Save button:

Data file location

The name of the Texture File is filled automatically.

File names

Now hit the Publish sprite sheet button to create the texture atlas.

Publish sprite sheet

You'll be presented a dialogue that shows you the progress of the texture atlas generation process. The speed at which this performs, will mostly depend on the size of your texture atlas and the type and strength of compression you use.

We're exporting this as a PNG-32, using the default Png Opt Level (optimization level) in TexturePacker, which is 1. That's going to be pretty quick. When generating final assets, you might consider increasing that level when using the PNG format, to produce a smaller file.

Considerations When Choosing a Texture Format

Starling is a GPU accelerated framework and the texture atlas you're creating here will be uploaded into GPU memory where it is then used. The texture format you choose to use, can make a huge difference in the amount of GPU memory your textures consume!

By default, TexturePacker has selected PNG-32 as the output texture format. PNG, like JPG, TGA, TIFF and WebP, is not a GPU texture format. Before any files in these formats are uploaded to the GPU, they're decoded into uncompressed bitmap data, which means they consume the same amount of GPU memory as a fully uncompressed image (BMP for example). I'll now refer to these common formats as conventional formats.

By default, when one of these conventional formats is uploaded to the GPU, it is first expanded to 32-bit (BGRA)ref, regardless of whether the source was 8-bit, 24-bit or 32-bit.

Let's do the maths on a 32-bit bitmap. An uncompressed 32-bit bitmap image consumes 4 bytes of memory, per pixel. So if our texture atlas was 2048 x 2048 pixels:

  • Pixels: 2048 x 2048 = 4,194,304
  • Bytes/pixel: 4 * 4,194,304 = 16,777,216 (about 16MB)

So one 2048 x 2048 texture in GPU memory consumes 16MB of GPU memory. That may not seem like a lot, but when developing multimedia rich applications such as games using sprite based animation sequences, there can easily be thousands of assets and suddenly, GPU memory consumption becomes a concern.

So with the potential problem illustrated, what are the options?

Introducing the Adobe Texture Format (ATF)

The AIR SDK supports the Adobe Texture Format (ATF), a format that is able to contain textures compressed with GPU texture compression. This is markedly different to your conventional formats such as PNG, JPG, TIFF etc, which are decompressed before being uploaded to the GPU. GPU texture compression formats are uploaded to the GPU in their compressed state, and decompressed by the GPU! That means they reside in GPU memory in their compressed state and take up much less memory!

Furthermore, because textures using GPU texture compression are uploaded to the GPU in their compressed state, the upload process is quicker!

The ATF format simultaneously supports any combination of these different GPU texture compression options:

  • DXT1/5 (S3 Texture Compression) - Used by desktop operating systems (Windows, Mac OS, Linux) and some mobile phones. DXT1 has 1-bit alpha, where as DXT5 supports full alpha. Whether you use DXT1 or DXT5 depends on your alpha needs.
  • ETC1 (Ericsson Texture Compression) - Used by mobile phones, most notably Android. Has no alpha.
  • ETC2 (Ericsson Texture Compression) - Higher quality than ETC1 and supports alpha. Used by Android and iOS mobile phones. Google claims >95% mobile support for Google Play devicesref.
  • PVRTC (PowerVR Texture Compression) - Supported by all generations of iPhone and iPadref.

TexturePacker dropped support for the ATF format after TexturePacker 6.0.1, but luckily you can still download that version, and take advantage of the benefits the ATF format has to offer. Alternatively, after creating a PNG texture atlas with the latest release of TexturePacker, you can use the png2atf command line tool that ships with the AIR SDK, to convert the PNG to ATF.

For the remainder of the tutorial, I'll be using PNG-32 as this is what is supported by the latest version of TexturePacker, but I highly recommend exploring the ATF options.

Back to coding!

Now that we have our texture atlases all set up, we are going to write a new class to use all those pretty images!

In VS Code, let's return to our StarlingRoot.as we created earlier. Let's update that file to the following:

src\StarlingRoot.as
package
{
    import flash.filesystem.File;
    import starling.assets.AssetManager;
    import starling.core.Starling;
    import starling.display.Button;
    import starling.display.Image;
    import starling.display.MovieClip;
    import starling.display.Sprite;    
    import starling.events.Event;    

    public class StarlingRoot extends Sprite
    {
        private static var _assets:AssetManager;

        private var guy:MovieClip;
        private var startButton:Button;
        private var stopButton:Button;        

        public function StarlingRoot()
        {
            super();

            // Ensure stage is ready first.
            if (stage == null)
                addEventListener(Event.ADDED_TO_STAGE, init);
            else
                init();
        }

        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            _assets = new AssetManager();
            _assets.enqueue(File.applicationDirectory.resolvePath("atlas"));  // Load all assets in this folder.
            
            // Start loading the assets, with handlers for onComplete, onError and onProgress.
            _assets.loadQueue(
                assetsLoaded, // onComplete.  A reference to the AssetManager is passed to this.
                function (error:String):void { trace("Error:", error)}, // onError
                function (ratio:Number):void { trace("Progress:", ratio)} // onProgress
            );
        }

        private function assetsLoaded(a:AssetManager):void {
            var background:Image = new Image(StarlingRoot.assets.getTexture("background"));
            addChild(background);

            guy = new MovieClip(StarlingRoot.assets.getTextures("walking_guy"), 12);
            guy.x = (stage.stageWidth - guy.width)/2;
            guy.y = 600;
            addChild(guy);

            Starling.juggler.add(guy);
            guy.stop();

            startButton = new Button(StarlingRoot.assets.getTexture("start_button"));
            startButton.name = "start";
            startButton.x = (stage.stageWidth - startButton.width)/2;
            startButton.y = 400;
            startButton.addEventListener(Event.TRIGGERED, onStartPress);
            addChild(startButton);

            stopButton = new Button(StarlingRoot.assets.getTexture("stop_button"));
            stopButton.name = "stop";
            stopButton.x = (stage.stageWidth - stopButton.width)/2;
            stopButton.y = 400;
            stopButton.visible = false;
            stopButton.addEventListener(Event.TRIGGERED, onStopPress);
            addChild(stopButton);
        }

        // Start button event handler
        private function onStartPress(e:Event):void
            {
                startButton.visible = false;
                stopButton.visible = true;
                guy.play();
            }

        // Stop button event handler
        private function onStopPress(e:Event):void
            {
                startButton.visible = true;
                stopButton.visible = false;
                guy.stop();
            }

        // Getter for access to StarlingRoot.assets
        public static function get assets():AssetManager { return _assets; }
    }
}

This is a very simple example that should be pretty self-explanatory for an average to advanced ActionScript developer.

Let’s take a quick overview, to see what each block of code does:


Here we declare the variables that represent the main objects for our scene.

src\StarlingRoot.as
private static var _assets:AssetManager;

private var guy:MovieClip;
private var startButton:Button;
private var stopButton:Button;  

Note _assets, which will be used as the AssetManager for the entire project, and so has been defined as a static (class) variable. This is accessed using the public getter (read only) function defined at the bottom of the class. This means the AssetManager created here will be accessible from any class in the project as StarlingRoot.assets.

src\StarlingRoot.as
// Getter for access to StarlingRoot.assets
public static function get assets():AssetManager { return _assets; }

The constructor simply adds an event listener that'll fire when the stage is ready. This step helps avoid issues that can occur when something that hasn't yet been added to the stage tries to do something that requires the stage.

src\StarlingRoot.as
public function StarlingRoot()
{
    super();

    // Ensure stage is ready first.
    if (stage == null)
        addEventListener(Event.ADDED_TO_STAGE, init);
    else
        init();
}

The init function fires once this class' instance has been added to the stage. The Starling AssetManager is then instantiated and the contents of the "atlas" folder enqueued, and loaded.

src\StarlingRoot.as
private function init(e:Event = null):void
{
    removeEventListener(Event.ADDED_TO_STAGE, init);

    _assets = new AssetManager();
    _assets.enqueue(File.applicationDirectory.resolvePath("atlas"));  // Load all assets in this folder.
    
    // Start loading the assets, with handlers for onComplete, onError and onProgress.
    _assets.loadQueue(
        assetsLoaded, // onComplete.  A reference to the AssetManager is passed to this.
        function (error:String):void { trace("Error:", error)}, // onError
        function (ratio:Number):void { trace("Progress:", ratio)} // onProgress
    );
}

Next, once the assets have been loaded by the AssetManager, the assetsLoaded function will fire and we can start putting them into action.

It's important to note the order in which display objects are added to the stage (addChild()). Display objects at the bottom of the visual stack need to be added first.

With that being the case, we'll add the background first. The background is a single image, so for it we'll use the simple Image display object, which is the perfect choice for presenting GPU accelerated static sprites.

src\StarlingRoot.as
var background:Image = new Image(StarlingRoot.assets.getTexture("background"));
addChild(background);

After the background was added, we then added a Starling MovieClip display object.

src\StarlingRoot.as
guy = new MovieClip(StarlingRoot.assets.getTextures("walking_guy"), 12);
guy.x = (stage.stageWidth - guy.width)/2;
guy.y = 600;
addChild(guy);

Here we created a new MovieClip called guy using the walking_guy sprites from the texture atlas. The StarlingRoot.assets.getTextures() method accesses the AssetManager and grabs all textures named "walking_guy", respecting their frame order, and populates the MovieClip with them. Lastly, when creating the MovieClip we specified a framerate of 12 for it.

Note how we don’t need to specify the name of each frame; as long as each frame is named with a sequential suffix (ie: walking_guy01 , walking_guy02 etc.), Starling will pick them all up in the exact order specified by their suffix.

src\StarlingRoot.as
Starling.juggler.add(guy);
guy.stop();

We add the newly created MovieClip to the main juggler so that it can be animated, then we immediately stop it.

For those who are not familiar with the Starling animation system, a juggler is a class in charge of animating objects (like a MovieClip , for example) which makes sure their animations are executed at the correct speed (12 fps in this case), factoring in delta time (adapts accordingly to fluctuations in framerate). The juggler also provides a centralized way of managing animation activity, such as when you might pause and resume a game.


Next we create two new buttons for starting and stopping the animation, using two sprites from our texture atlas as the graphics. Note that we reference the right textures for each button by the name of the .png file we used in the texture atlas. Also, we hide the stop button so that the start button is the only one visible initially.

src\StarlingRoot.as
startButton = new Button(StarlingRoot.assets.getTexture("start_button"));
startButton.x = (stage.stageWidth - startButton.width)/2;
startButton.y = 400;
startButton.addEventListener(Event.TRIGGERED, onStartPress);
addChild(startButton);

stopButton = new Button(StarlingRoot.assets.getTexture("stop_button"));
stopButton.x = (stage.stageWidth - stopButton.width)/2;
stopButton.y = 400;
stopButton.visible = false;
stopButton.addEventListener(Event.TRIGGERED, onStopPress);
addChild(stopButton);

An event listener was added to each button, so we can respond when the button is clicked. Each event listener is pointing to a function to handle the event, which are next:

src\StarlingRoot.as
// Start button event handler
private function onStartPress(e:Event):void
{
        startButton.visible = false;
        stopButton.visible = true;
        guy.play();
}

// Stop button event handler
private function onStopPress(e:Event):void
{
        startButton.visible = true;
        stopButton.visible = false;
        guy.stop();
}

These event listeners show and hide the respective buttons, creating a visual toggle of sorts. They also stop and start the animation of the walking guy MovieClip.

Excellent, now that we have all of our code in place, let’s compile the project and make sure it all works as it should.

In VS Code, lets build and run the project again.

Perform the build task:

  • Windows / Linux: Ctrl + Shift + B
  • macOS: Cmd + Shift + B

Select "ActionScript: compile debug - asconfig.json" to perform the build task.

Then run debug:

  • Windows / Linux: F5
  • macOS: Fn + F5, or just F5

The application will now compile and you should be able to control the walking guy animation with the stop and start buttons.

Additional Resources

Other places you will find supportive information for using ActionScript 3.0, the AIR SDK and the Starling framework are:

Conclusions

The application we've built is simple, but it demonstrates how easy it is to manage graphic assets using TexturePacker and Starling.

I hope you enjoyed this tutorial!