Flash AS3 Tutorial: Embedding Symbols From External .swf Files
This is one of my favorite features in flash but the documentation is pretty much non-existent and what little I’ve found is completely crappy. In developing a large flash game you’ll find you have a TON of symbols, buttons and images that you need to use in various classes throughout your game. So the question is, how can you put all of those assets into a .swf file and just reference them when necessary? Embedding is the answer. I’ve created a little clicking game to show you how it’s done.
First You’ll Need To
Download the Embedding Symbols Tutorial Game Code
Create & Organize Your Assets
Create an assets.fla file. This will hold all of your graphics, buttons, screens and user interface symbols. If you have a lot of these I suggest you break them into several different files (ie by level, scene or type) so loading doesn’t take quite so long. I typically put all of the .swf files in a graphics or assets folder so they’re easy to find and manage later on down the road.
Now in your assets.fla file create a new MovieClip symbol. Inside this symbol draw a square. When you’re done right click on the symbol in your library > select properties > then export the square for actionscript as.
Create two more symbols, both of them Buttons. One button will start the game and another will restart the game.
Now create one last MovieClip symbol. This will be your interface for the little game we’re making. Add both of your buttons somewhere in the interface symbol. In the properties panel give each of them an instance name so we can reference them later.
Next we want a way to keep score of how many times our shape has been clicked. Add two text fields somewhere on the screen. One of them should contain static textfield that says the word “Score:” and the other should be a dynamic text field that will hold the user’s score as they play. Make sure the dynamic textfield has an instance name so we can reference it later on.
Exporting Your Assets
Unfortunately we can’t embed a .fla file so before we can use the graphics in our assets.fla file we need to export them to a .swf. Any time you update your assets.fla file you will need to re-export it to a .swf file in order to see the changes. Once we have our assets.swf file we’re ready to start building our game.
Create Your Main .fla File
Before we can start putting our game together we need to create another flash file that will import our game classes, create a game instance, add our game to the stage and then start rendering our game. Create a file called embedding.fla. Import your main game class, create an instance of it, then call the run function once it’s been added to the stage. You’ll end up with the following:
//import your game logic class
import com.design1online.puzzle.GameLogic;
//create the game instance
var blockGame = new GameLogic();
//check to see if the game has been added to the stage before you run it
//otherwise you'll get errors
blockGame.addEventListener(Event.ADDED_TO_STAGE, init);
//add the game to the stage
addChild(blockGame);
//once the game has been added to the stage the event listener
//will call this init function
function init(e:Event)
{
//now we start our game logic
blockGame.run();
}
Create Your Game Logic & Embed Your Files
So this little game I made up is nothing fancy. All it does is take a block and randomly place it around the screen with random alpha values. Each time you click on the square it places it at a new random location and increases your score. It’s nothing fancy, it’s just to show you how everything fits together.
/** * File: com.design1online.puzzle.GameLogic.as * Author: jade@design1online.com * Created: 12/19/2010 * Purpose: game logic for a demo puzzle game * in order to show how embedding works **/ package com.design1online.puzzle { import flash.display.Bitmap; import flash.display.MovieClip; import flash.display.SimpleButton; import flash.events.Event; import flash.events.MouseEvent; import flash.text.TextField; public class GameLogic extends MovieClip { /** * Source: the path to the file containing our square symbol * which must is relative to where this GameLogic.as file is located * Symbol: contains the name you've given the symbol when you chose to * export it for actionscript * Public Var {name}: Finally we associate this symbol to a class named * block. You can call your class whatever you want but you must have a * different class name for each symbol you're embedding. **/ [Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class; [Embed(source='../graphics/assets.swf', symbol='interfaceUI')] public var Interface:Class; public var block = new Square(); public var ui = new Interface(); public var score:int; /** * Default Constructor **/ public function GameLogic() { score = 0; } public function run() { //add the user interface ui.x = 400; ui.y = 200; ui.btnReset.visible = false; ui.addEventListener(MouseEvent.CLICK, mouseClick); addChild(ui); //format the block if necessary block.alpha = Math.random(); block.visible = true; block.x = 340; block.y = 150; block.alpha = 1; block.width = block.height = 34; block.name = "squareBlock"; //you can even add event listeners to the embedded object block.addEventListener(MouseEvent.CLICK, mouseClick); //now display the block on the screen addChild(block); } private function mouseClick(e:Event) { switch (e.target.name) { /** * If they click on the block increase their score * and update the score text box in the embedded InterfaceUI object * then reset the block **/ case "squareBlock": //check to see if the instructions are still up if (ui.instructions_txt.visible) { score = 0; ui.instructions_txt.visible = false; ui.btnStart.visible = false; ui.btnReset.visible = true; resetBlock(); } //they are actively playing the game else { score++; ui.score_txt.text = score; resetBlock(); } break; /** * If they hit the reset button on the ui screen * it will be caught here and restart the game **/ case "btnReset": score = 0; ui.score_txt.text = score; resetBlock(); break; /** * If they hit the start button or the instructions screen hide * the instructions screen and start the game **/ case "btnStart": ui.instructions_txt.visible = false; ui.btnStart.visible = false; ui.btnReset.visible = true; resetBlock(); break; } } /** * Purpose: scramble the blocks opacity, size and position **/ private function resetBlock() { block.x = (Math.random() * 600); block.y = (Math.random() * 400); block.alpha = Math.random(); } } }
Troubleshooting &
Frequently Asked Questions
Why do I get Error #2044: Unhandled ioError?
You have the incorrect path to your assets.swf file. You must embed the files relative to where you’re using the [Embed] command. For this reason I typically include the assets in com.design1online.graphics folder which is only one level removed from my game logic folder.
Why do I get Unable to Transcode errors?
Sometimes Flash CS4 has a small memory leak and when you export your assets.fla file to get assets.swf it doesn’t show you the compiler errors. Other times your assets.swf file is corrupted. Regardless of which is happening you need to restart Flash and re-export your assets.fla to get a clean/uncorrupted assets.swf file.
Why does it say I’m missing something from the Flex SDK? I’m not using Flex.
Embedding is a part of the Flex SDK. Even if you aren’t using Flex you need to have the Flex SDK in your library path in order for embedding to work correctly. Sometimes you’ll be prompted to add the correct application path when you save your main .fla file but you can always add it manually by doing the following:
Go to Document > Preferences. Click on the Settings… button next to the Actionscript 3.0 in the flash version drop down box. Click on the Library path tab. Click on the plus sign at the bottom and add the following:
($AppConfig)/Actionscript 3.0/libs/flex_sdk_3/
I’ve embedded my symbol but it still doesn’t show up. What’s wrong?
- Check to make sure you have the correct path to your assets.swf file.
- Make sure you’re embedding a .swf file and not a .fla file.
- Make sure your symbol is visible. You can use instanceName.visible = true to force it to show up.
- Make sure your symbol is on a visible part of the stage. Try setting the x and y values to the middle of the stage.
- Make sure your symbol has a height and a width property. It may be showing up but it’s just not visible to the naked eye.
- Make sure your symbol has an alpha value higher than 0.
- Make sure you’re referencing the correct name in your symbol=”symbolNameHere”. In your assets.fla file make sure the symbol has symbolNameHere in the export link identifier. Otherwise you need to export your symbol for actionscript.
How do I make an embedded symbol publicly accessible to all functions in a class?
Once you embed the symbol you need to define a public variable that instantiates your symbols class. This instantiated variable will then be accessible to all class functions. For instance:
package.name.here { public class.name { [Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class; private var mySquare = new Square(); //default constructor has access to mySquare public function class.name():void { var myNewSquare = new Square(); addChild(mySquare); addChild(myNewSquare); resize(50); } //all other function also have access to mySquare private function resize(amount:int):void { mySquare.height += amount; mySquare.width += amount; /* this will not work, myNewSquare is out of scope myNewSquare.height += amount; myNewSquare.width += amount; */ /* this will not work, Square is not instantiated, it's just a class definition Square.height += amount; Square.width += amount; */ } //end resize } //end class } //end package
Why do I get Class Is Not A Compiled Type errors?
Embedded symbols use a dynamic class, meaning the class is created at compile time. If you try to create a variable with a type of your symbol’s class name you’ll get an error. The way around that is to declare your variable without a type association. Then it can be dynamically bound.
For instance, this is incorrect:
package.name.here {
public class.name {
[Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class;
private var mySquare:Square = new Square();
//default constructor has access to mySquare
public function class.name():void {
}
} //end class
} //end package
This is correct:
package.name.here {
public class.name {
[Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class;
private var mySquare = new Square();
//default constructor has access to mySquare
public function class.name():void {
}
} //end class
} //end package
Do I need a new class name for every symbol I embed?
Yes. You’ll get class definition conflicts if you try to give two embedded symbols the same class name.
How do I access symbols within my embedded symbol?
First take a look at the interface in the tutorial files. You’ll notice that it has several different symbols within it. Each of these symbols has been given an instance name in the assets.fla file while only the InstanceUI symbol is being exported to actionscript.
In order to access symbols within embedded symbols they must have an instance name. Then you can access them via dot syntax using their instance name.
package.name.here {
public class.name {
[Embed(source='../graphics/assets.swf', symbol='interfaceUI')] public var Interface:Class;
private var ui = new Interface();
//default constructor hides the reset button symbol inside of the embedded interface symbol
public function class.name():void {
/**
* Notice that in assets.fla the reset button is not being
* exported for actionscript. instead it has an instance
* name of resetBtn
**/
ui.btnReset.visible = false;
}
} //end class
} //end package