Please note: This project is deprecated at Zynga and is no longer maintained.
This tool is an AIR app that scrapes the animation data from swf files using a modified Starling Library and outputs it to a ccb format that can be read and edited by CocosBuilder, an open source mobile development tool. The tool is useful for teams that have a lot of flash assets (published in swfs) created already and wish to minimize the work done to port their assets to a mobile game.
It should work with the newest version of Air, but if not, try downloading the air3-5_mac.dmg for the a working tool with Adobe AIR (if you have a higher version installed, please uninstall it and install AIR 3.5).
There is a jsfl script in the repo that you can run on your fla files to export all the movieClip symbols and to identify all the shape/shape tweens that need to be changed so the outputted swf can be used optimally with swf2Cocos. To run it, open the Flash file and do Command > Run Command and select exportAndID.jsfl. The movie clips are then exported, and the output displays the animations that will cause problems:
The air app is located here: https://github.com/zynga/swf2ccb/blob/master/flexPreviewTool/swf2ccb.air. Just download and run it.
First, there needs to be a master symbol that has the same name as the file name (check out picture below). This is to ensure that every symbol is referenced and can be more easily accessed by the tool to get the animation data. Every symbol also needs to be exported, and each animation should only animate symbols (rather than animating shapes that are in different layers). Sometimes it's not possible to get animation data from Flash Shapes (or it may be possible, and we haven't figured it out yet).
Also, the ccb files generated are just for CocosBuilder. It is at least 20x bigger than the published size of the ccbi files that are put on the device. Please do not freak out when you see that the ccb files are a few MBs, they will be much smaller on the device
For more info about prepping the flash files, please refer to this page done by the Austin Team
- After you clone the repo from GitHub (or just download the tool itself), if there are any previous versions installed, please close it (if you do not know how to use git, refer to this link, or just google it yourself). Then, start off by running the air app, which looks like this:
- Once you run it, the top of the app looks like this starting off:
- The different options are as such:
- Load File - Load a single swf
- Load Directory - Load a whole directory of swfs
- Bitmap Quality - The highest resolution that you would like your game at. This ensures that your bitmaps are at a high enough quality to not be pixelated for the highest resolution game.
- Basic Game Device - This is the lowest resolution you would like it at. CocosBuilder has the options to scale up everything for you, so assets are created with numbers to fit with the lowest resolution, and scaled up to the correct resolution. CocosBuilder doesn't scale down from 1.0
- save options:
- There are a few preset destinations you can choose to output to
- The directories that files are saved to are only saved if you want them to be saved.
- The .ccb, .star, and .json files are only saved out if you want them.
- The different options are as such:
- After you load a file, the animation is displayed on the tool (animation not shown in this screenshot). Then it asks for the location for which to save the ccb and bitmap files (if that option is unchecked).
- If your position scale and your bitmap scale were different, make sure you pick the right resolution in CocosBuilder (File > Publish Settings...). Pick it based on the resolution of the bitmaps
- Once the ccb files and bitmaps are outputted, you can view them in CocosBuilder!
- The ccb and bitmap files are where you saved them. There is also a .json file that contains all the animation data in json format if you're interested in reading that, click here
<h1 id="title-heading" class="pagetitle">
<span id="title-text">
<a name='ZyngaStarling'>Zynga Starling/Starling Output</a>
</span>
</h1>
There is a modified version of Starling that I've been developing so that animation data can be obtained from swf files so they can be rendered on GPU. The repo is here as well as included in this project.
To output the .star or .json file using the tool, just check the corresponding boxes and specify where you would like the output. Refer to Workflow for more details.
Here are some chunks of code from the tool that demonstrates how you can use Starling to get a starling object to display on GPU.
First, you initialize Starling by passing in the flash Stage on which you wish to display the starling objects.
private function init():void {
var s:Starling = new Starling(starling.display.Sprite, this.systemManager.stage);
s.makeCurrent();
Also, make sure to make a new LoaderContext object so that the bytes can be loaded correctly and the symbols saved.
private var context:LoaderContext = new LoaderContext(false, new ApplicationDomain(ApplicationDomain.currentDomain));
Given the native path of the swf file, you set up the loading process by loading a Flash URLRequest using a Flash URLLoader. This is the how swf files are loaded using the Flash Library. If this does not work, please refer to the Flash Documentation.
public function loadAssetFile(path:String):void {
clearAll();
m_currentPath = path;
m_currentFileName = getFileName(path);
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
var urlReq:URLRequest = new URLRequest("file://" + path);
loader.addEventListener(flash.events.Event.COMPLETE, loadBytes);
loader.load(urlReq);
}
The reason for the listener in the code above is that loading files in flash is an asynchronous operation, so listeners need to be used.
So, once the file is loaded, you load the bytes of the file into a ByteArray as such:
private function loadBytes(event:flash.events.Event):void {
var uloader:URLLoader = URLLoader(event.target);
var loader:Loader = new Loader();
var bytes:ByteArray = ByteArray(event.target.data);
uloader.removeEventListener(flash.events.Event.COMPLETE, loadBytes);
var loaderInfo:LoaderInfo = loader.contentLoaderInfo;
loaderInfo.addEventListener(flash.events.Event.COMPLETE, loadDone);
loader.loadBytes(bytes, context);
}
Once the bytes are loaded into the byte array, this is what you can do. I'll explain part by part
192 var asset:Asset;
193
194 // Register shared symbols
195 var url:String = m_currentPath;
196 var fileName:String = getFileName(url);
197 var rootSymbolName:String = fileName;
198 var cl:Class = context.applicationDomain.getDefinition(rootSymbolName) as Class;
199 var dispObj:flash.display.DisplayObject = flash.display.DisplayObject(new cl());
200
201 var num:Number = 2.2 * Math.pow(0.5, bitmapQ.selectedIndex);
202 if (num && num != 0) {
203 Asset.drawScale = num;
204 }
205
206 Asset.quality = Math.pow(2, mDefaultQuality - quality.value);
207
208 asset = Asset.fromDisplayObject(dispObj, fileName, s_sharedContext, m_shared, false);
209
210 registerStarlingAsset(asset);
211
212 m_asset = asset;
213
214 m_currentObject = m_asset.createInstance(asset.rootSymbolName, s_textureCache);
215
216 m_currentObject.x = width/2;
217 m_currentObject.y = height/2;
218
219 Starling.current.stage.addChild(m_currentObject);
on Line 196, getFileName gets the name of the swf file (it's a local method that's easy to write). This is so we can do the next part, which is:
context.applicationDomain.getDefinition(rootSymbolName) as Class gets the class object of the root object that refers to each symbol in the swf file. This is why you need the LoaderContext object.
Line 199 creates a new instance of the root object so that all the assets are created and can be displayed.
Line 208 is what creates an asset that keeps track of all the symbols
Line 210 registers all the asset names so that they can be referred to by symbol names.
Line 214 is how you create a Starling DisplayObject that can be put on the Starling Stage (initialized in Starling's init).
Line 219 shows you how to put it on the Starling Stage (can't put it on the Flash Stage because it's not a Flash DisplayObject)
To output the json and the bitmaps, do these commands:
m_asset.saveJson(ccbPath); m_asset.saveBinary(ccbPath);
var json:Object = m_asset.toJSON();
m_asset.saveAllBitmaps(ccbPath+origPathToBm);
saveJson saves out the json data (described below).
saveBinary saves out a binary version of the file (with .star extension). This can be loaded back into Starling to be displayed in Starling.
To load the binary file back into Starling, you can do something like below:
var loader:AssetLoader = new AssetLoader();
loader.load("…/fileName.star");
m_currentObject = loader.asset.createInstance(asset.rootSymbolName, s_textureCache);
Starling.current.stage.addChild(m_currentObject);
saveAllBitmaps saves out the bitmap files to the specified path.
Here's a basic breakdown of how the json files look. It is a dictionary of dictionaries (and of more dictionaries for certain properties). A more detailed description with a sample file will follow after this initial screenshot
So how the json file is generated is as such:
First comes the dictionary of bitmaps, with the keys being the bitmap names:
With each bitmap, there is a bitmap name that is associated with each bitmap. This is also the name of the png that is generated. That way, the asset and the ccb can refer to the pngs. The width and height of the bitmaps are included so that the correctly sized png can be generated when the pngs are generated
The next part of the json is the dictionary for all the symbols. These are the same symbol names that you see in the flash file.
In this example, you see the symbol name "RobotCharacterMc". That is the same as the export name in the flash file. There are 4 different values for the type of the symbol. "image", "text", "anim", and "sprite". An "image" is a bitmap, "text" is a textfield, "anim" means that it's a movieClip with animations, and "sprite" means that it's a normal sprite with no animations, just maybe children.
In each symbol, if there are any children, then there is an array of children. The highlighted box shows what one child entry looks like. The child entry contains a lot of the basic information needed that's not stored with its symbol (i.e. x, y coordinates, scale, skew).
The next part of each symbol entry is the animation array:
In the animation dictionary, the thing to note is how it's structured. At each index, there is a "tracks" object that keeps track of all the animation tracks associated with this symbol's children. Each animation track (highlighted in the picture) has a key that represents the property that is being changed. In each animation track, there are 2 dictionaries, one that says "start" and one that says "end". The "start" dictionary keeps track of the start keyframe and start value of each keyframe (estimated, not exactly what flash has), and the "end" dictionary keeps track of the end keyframe and end value of each keyframe. The keyframe and value in each dictionary are stored in the "values" and "frames" dictionaries, respectively.
Finally, there is basic information on the asset:
The "rootObject" entry describes information about the rootObject. The "symbolName" here should match the name of the swf file
The "fileVer" describes the version of the asset that is being used (this value is passed in).
The "isShared" property describes whether or not the bitmaps and Starling assets are kept so that they can be shared with other Starling assets that are created in different runs of the program.
<!-- end system javascript resources -->
That's more or less it. If there are any issues, please let me know!
email: etung@zynga.com
skype: zynga.edison
<!-- end system javascript resources -->