Blog posts about as3

  • How to use Spine with Starling/AS3

    May 10, 2013 | Tags: Game development, Tools, Starling, AS3, Flash

    Hats off to the guys over at Esoteric Software. Not only did they live up to the Kickstarter promise to deliver generic AS3 runtime for their excellent 2d animation tool Spine, they also added a Starling version as a bonus! This post shows how to get going using Spine animation in your AS3/Starling project.

    Updated 2015-03-22 Since this post was originally written the Spine runtime has undergone a bit of refactoring. To reflect the changes the post was updated using the latest runtime for Spine as well as the latest Starling library (1.6 at time of writing).
     
    Spine is currently the most promising solution for 2d skeleton animation, featuring a lot of powerful features such as individual keyframing, skinning and more. The major advantages over traditional sprite sheets are that using skeletal animation uses far less memory and provides smoother animations and the ability to seamlessly shift from one animation to the next - something that makes your animations more vivid. Spine is currently offered for $60 and is definitely worth every cent of it. If you want to give it a try there's a export-disabled trial version for download. There are a couple of alternatives to Spine, but nothing comes close to its functionality. It's currently the most powerful 2d skeletal animation tool.

    Currently Spine does not have a texture packer built-in, so we will be using TexturePacker developed by Andreas Löw. It's a great tool that recently got even better with a content protection feature. If you haven't already you should definitely check it out!

    Setup the project

    Setup a new AS3 project inside FlashDevelop (or the IDE of your choice) and check under project properties so that it compiles for the latest Flash player version. (Or you can download the project here.)

    Download the latest version of Starling and place starling.swc in the lib-folder of your project. Right click on the file and select Add To Library.
     
     
    Download the latest Spine runtimes and copy the content of both spine-as3/src and spine-starling/src into your src folder:
     
     
     
    We've now created our project. Lets get some data into it and then return to do some coding.
     
     

    Export data from Spine

    Lets start by preparing the data. Once you've created your animations you need to get them out of Spine and into your project. This is done using the Export function.


    Be sure to use JSON as the data format and set the output path to src in your AS3 project:

     
     
     

    Create the sprite sheet using  TexturePacker

    Okay, so now we got the animation data, but we'll also need the body part graphics as a texture atlas. This is where TexturePacker comes in to do the job.

    Start TexturePacker, select all the images from your Spine project (we're using the Spineboy sample project for this demo)..


    .. drag and drop them into the Sprites panel of TexturePacker (you could also use the "Add Sprites" option inside of TexturePacker):


    In the TextureSettings panel, select "Sparrow / Starling" as Data Format and place both the Data file and Texture file in the src-path of your AS3 project:



    Lets write some code!

    Lets start by adding Starling into our Main class:
    package {
    import flash.display.Sprite;
    import flash.events.Event;
    import starling.core.Starling;

    public class Main extends Sprite {
    private var _starling:Starling;

    public function Main():void {
    if (stage)
    init();
    else
    addEventListener(Event.ADDED_TO_STAGE, init);
    }

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

    _starling = new Starling(MyStarlingApp, stage);
    _starling.start();
    }
    }
    }
    Next step is to add the MyStarlingApp class that we used as a constructor argument for Starling. Create a new class named MyStarlingApp and make it inherit from starling.display.Sprite.

    Embed the data files using [Embed(source="..",mimeType="application/octet-stream")] inside the class.

    Here's the complete code, I'll return to some of the more specific parts:
    package {
    import flash.utils.setTimeout;
        import spine.animation.AnimationStateData;
        import spine.starling.SkeletonAnimation;
        import spine.starling.StarlingAtlasAttachmentLoader;
        import spine.SkeletonData;
        import spine.SkeletonJson;
        import starling.core.Starling;
        import starling.display.Sprite;
        import starling.textures.Texture;
        import starling.textures.TextureAtlas;

    public class MyStarlingApp extends Sprite {
    [Embed(source="spineboy.xml",mimeType="application/octet-stream")]
    static public const SpineBoyAtlasXml:Class;

    [Embed(source="spineboy.png")]
    static public const SpineBoyAtlasTexture:Class;

    [Embed(source="spineboy.json",mimeType="application/octet-stream")]
    static public const SpineBoyJson:Class;

            private var _skeleton:SkeletonAnimation;

    public function MyStarlingApp() {
    var texture:Texture = Texture.fromBitmap(new SpineBoyAtlasTexture());

    var xml:XML = XML(new SpineBoyAtlasXml());

    var atlas:TextureAtlas = new TextureAtlas(texture, xml);
                var attachmentLoader:StarlingAtlasAttachmentLoader = new StarlingAtlasAttachmentLoader(atlas);
                var json:SkeletonJson  = new SkeletonJson(attachmentLoader);

    var skeletonData:SkeletonData = json.readSkeletonData(new SpineBoyJson());

    var stateData:AnimationStateData = new AnimationStateData(skeletonData);

    // Setup how to morph between different animation sets
    stateData.setMixByName("walk", "jump", 0.3);
    stateData.setMixByName("jump", "walk", 0.4);
    stateData.setMixByName("jump", "jump", 0.2);

    _skeleton = new SkeletonAnimation(skeletonData, false, stateData);
    _skeleton.x = 400;
    _skeleton.y = 460;
    _skeleton.state.setAnimationByName(0, "walk", true);

    setTimeout(makeJump, 3000);

    addChild(_skeleton);
    Starling.juggler.add(_skeleton);
    }

    private function makeJump():void {
    _skeleton.state.setAnimationByName(0, "jump", false);
    _skeleton.state.addAnimationByName(0, "walk", true, 2); // delay next animation by 2 seconds
    }
    }
    }
    All animations are referred to by the name given in Spine. For the Spineboy demo project there's two animations: "walk" and "jump".

    One of the powerful features of Spine is the smooth transitions between animations. This is made by defining "mixes" on the AnimationStateData object using the setMixByName function. The first parameter is the name of the animation that the transition will be made from, the second the animation that will be switched to and the third parameter is the transition time. In the code above the transition between "walk" and "jump" is set to 0.3 seconds. If no mixes have been defined the change in animation will occur instantly. To make the animations smoother you should set up mixes for all animation changes that can occur.

    To start an animation call the setAnimationByName function of the SkeletonAnimation object's state property. The first parameter is track, the second is the name of the animation and the third is if the animation should be looped.

    If you wish to play one animation and immediately after another, use addAnimationByName after setAnimationByName in order to stack animations that will be played after each other.

    Download source codeThe FlashDevelop project except the Spineboy data, which you can get from the Spine runtime download.

     

    Runtime sourceThe runtimes are undergoing continues updates, so the one used in the archive above may differ from the one available at http://esotericsoftware.com/spine-runtimes/.

  • Preserve textformat when changing text in Flash / AS3

    April 09, 2013 | Tags: Actionscript, AS3, Troubleshooting, Flash, Snippet
    Notice that the textformat that was defined for your TextField mysteriously disappears when you just change the text? A bit annoying, but the reason is that the format is not applied to the TextField itself but the text in it. Replace the text and you replace the textformat as well.

    This can however be solved by storing away the textformat before you change the text and then re-apply it like this:

    // Save the old textformat before changing the text
    var textFormat:TextFormat = buttonText.getTextFormat();

    // Change the text
    buttonText.text = "New text goes here";

    // Re-apply the textformat
    buttonText.setTextFormat(textFormat);


  • Correct font names in TextFormat.font (AS3)

    April 03, 2013 | Tags: Actionscript, AS3, Troubleshooting, Flash
    If you want to use TextFormat in order to set which font family and style you wish to use on a component in your Flash project you just might be a bit puzzled on how to express both family and style in just one field - TextFormat.font.

    The problem

    If you plan to use the regular version of the font family ("Veto Com" in the sample, but could be "Arial", "Verdana" or the font of your choice), you'll just go with:
    import flash.text.TextFormat;

    var textFormat:TextFormat = new TextFormat();
    textFormat.font = "Veto Com";
    But if you want to use the Light style instead of Regular it's a bit trickier, because you need to know the font name including both family and style. Unfortunately there are no standards so it might differ between font sets.

    The solution

    There are two ways to get the correct font name:

    1. In Windows, locate the font file and open it to display the font information window. It will look something like this and the correct font name to use will be displayed in upper left corner:


    2. Add a textfield to your project and give it an instance name. Set both the Family and Style properties to the font you want. Then in code access the font property of the textfield and trace it using trace(myTextField.getTextFormat().font);
    Source for this solution: http://blog.erikphansen.com/actionscript-textformatfont-values/

    Enter the font name that you get from either of the methods above in your code:
    import flash.text.TextFormat;

    var textFormat:TextFormat = new TextFormat();
    textFormat.font = "Veto Com Light";


  • Must have tools for Flash developers

    March 24, 2013 | Tags: Game development, AIR, Tools, Open source, AS3, Flex, Flash
    There are plenty of good tools to use when developing Flash games and applications. Here I list some of my favourite ones.

    FlashDevelop

    This is the open-source develop environment to use for Flash development. Boosted with code generation and some refactoring options. Use together with Flex/AIR to add compilation right into FlashDevelop reducing the need to have Adobe Flash Professional. You'll find instructions on how to install FlashDevelop with Flex/AIR here. Plenty of 3rd party plugins also available.
    Get FlashDevelopUse together with Flex/AIR as a stand alone IDE.

    Citrus Engine

    This open-source framework brings some of the most powerful  frameworks on the market together. Combining frameworks such as Starling and Away3D with physics engines such as Box2D, Nape and AwayPhysics. Use this framework to really get a kick start in your project. Common platformer game objects are available right out of the box.
    Get Citrus EngineWith Starling, Away3D, DragonBones, Box2D, Nape and AwayPhysics.

    Adobe Scout

    As part of the Adobe Gaming SDK - Adobe Scout is a very powerful profiling tool that even adds the possibility to profile on your mobile devices. Currently available for free on Creative Cloud. To use this profiler fully you need to enable advanced telemetry in your swf-file, something that hasn't been available out-of-the-box with FlashDevelop. To solve this you can use a 3rd party AT-plugin in FlashDevelop or this Python script.
    Get Adobe ScoutRequires free Creative Cloud account.

    TexturePacker

    If you aim to use Starling for development you'll need to use sprite sheets/texture atlases in order to effectively utilize the graphics processor required to get good performance on mobile devices. TexturePacker is your choice for this. Compile your sprite sheet by adding images, swf-files or Photoshop files (.psd) and select the export format. Plenty of output formats available to cater for most game engines out there, also supporting advanced image formats like PVR.
    Get TexturePackerPowerful sprite sheet creator. Try it for free.

    DragonBones

    This is currently my primary choice of 2d skeletal animation tools. I'm really looking forward to start using Spine, but since it not yet have an AS3 runtime DragonBones will be my choice in the meantime. There's also Spriter to consider if you don't have Flash CS 5.5 or later (required by DragonBones as the animator is a plugin panel). Find further information about the three different tools here.
    Get DragonBonesRequires Adobe Flash Professional CS5.5 or later.

    PhysicsEditor

    Defining advanced shapes manually to use with physics engines can be a real hassle. Thankfully there exists tools like PhysicsEditor that will allow you to define even the most complex shapes with ease and export as code (both Box2D and Nape supported). Start by auto tracing your sprites and - if necessary - tweak the shapes manually, set the parameters for your physics object (based on your choice of physics engine) and export the code. Supports most major game engines out there (not limited to Flash).
    Get PhysicsEditorCreate physics objects with ease. Try it for free.

    Feathers

    Feathers is an open-source project that works on top of Starling to add highly responsive UI components that will work from mobile devices to desktops. Great for building nice looking user interfaces.
    Get FeathersUse together with Starling.

    Tiled

    Versatile map editor that beside tiles (both normal and isometric) support creation of vectors such as polygons, rectangles and ellipses which makes it ideal to use for defining static physics objects such as platforms, sensors (coins, signs, etc). Citrus Engine (mentioned above) has a loader for the Tiled map-format.
    Get TiledPowerful and free map editor.

  • Multi resolution development with Flash

    March 08, 2013 | Tags: Game development, Actionscript, AS3, Flex, Flash

    This is the second post aimed at app development using Flash. The previous post showed how to create a simple app with Flash.This post will explain how to develop for multiple resolutions, something that is necessary on the mobile market where the screen resolution may vary from 426x320 pixels up to full HD. Not only does the screen resolution vary, the screen ratio does also vary ranging from 16:9 to 4:3.


    The theory

    So, how does one cater for all these resolutions? Simply put, you develop based on the lowest resolution and then scale upwards. This way you only have one code base and instead trust the graphics engine to get it right.

    But wouldn't scaling low-res graphics onto a full HD screen look extremely fuzzy? Yes, it would. And that's why you need to provide multiple sets of graphics. Although we are going to develop for the smallest resolution up scaling graphics hundreds of percentage is not a good idea. Instead we will provide graphics in multiples of the smallest resolution and use the ones that best matches the display. For instance, if we need to display an image twice the size compared to the smallest resolution that we develop for we will use graphics that is twice the size.

    The difference is displayed below:

    One of the decisions that we need to make is how we want to handle different ratios. Let say that we choose to develop for a 3:2 format (let say basing our project on the original iPhone size 320x480). How do we wish it to scale onto a 4:3 or 16:9 display? We have two choices; either we'll scale to fit all or we'll scale so that there's no borders:

    Decision time

    We decide to develop for 320x480, a 3:2 aspect ratio. We will provide graphics in 1x, 2x and 3x. That means that we will have pixel perfect graphics for 320x480, 640x960, 960x1440. Any resolution in between will display scaled graphics.

    All code we write will assume that we're on a 320x480 screen, and the graphics engine will handle all scaling for us. If we for instance place an image sized 32x32 at position 10, 20 - it will appear on a 640x960 screen as a 64x64 image at 20, 40, as the scale factor between 320x480 and 640x960 is 2.

    As we're more interested in that all our content is displayed properly than that the complete screen is used all the time we will select the scale-to-fit mode. This ensures that everything is visible even if it means adding borders to the left and right or above and beneath.

    Let's write some code!

    It's time to test this out. We'll do the development in FlashDevelop using Starling as the framework of choice. We'll be using our last project - which you find here to download (or this complete project already done here to save some time).

    Let´s start by writing the main class. Compared to the last project we'll add a little bit more code in the Starling setup. We'll set a viewport - which is the largest work area that matches our requested ratio against the screen size - and stage size to a predefined value, in this case 320x480.

    Main.as:
    package {
    import flash.desktop.NativeApplication;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.geom.Rectangle;
    import starling.core.Starling;
    import starling.utils.RectangleUtil;
    import starling.utils.ScaleMode;

    public class Main extends Sprite {
    private static const STAGE_WIDTH:int = 320;
    private static const STAGE_HEIGHT:int = 480;

    private var _starling:Starling;

    public function Main():void {
    // Tell Flash not to scale, that will be done by Starling instead
    stage.scaleMode = StageScaleMode.NO_SCALE;
    stage.align = StageAlign.TOP_LEFT;

    // Trigger an event handler when application looses focus (see note in handler).
    stage.addEventListener(Event.DEACTIVATE, deactivate);

    setupStarling();
    }

    private function setupStarling():void {
    // Get the preferred stage size based on our smallest target resolution
    var stageArea:Rectangle = new Rectangle(0, 0, STAGE_WIDTH, STAGE_HEIGHT);

    // Get the fullscreen size available
    var fullscreenArea:Rectangle = new Rectangle(0, 0, stage.fullScreenWidth, stage.fullScreenHeight);

    // Fit the stage to the full screen. ScaleMode.SHOW_ALL ensures that everything will be visible (not croping will occur).
    var viewport:Rectangle = RectangleUtil.fit(stageArea, fullscreenArea, ScaleMode.SHOW_ALL);

    // Create a new instance and pass our class, the stage and the wished viewport
    _starling = new Starling(MyStarlingApp, stage, viewport);

    // Show debug stats
    _starling.showStats = true;

    // Define level of antialiasing,
    _starling.antiAliasing = 1;

    // Set to our preferred stage size
    _starling.stage.stageWidth = STAGE_WIDTH;
    _starling.stage.stageHeight = STAGE_HEIGHT;

    _starling.start();
    }

    private function deactivate(e:Event):void {
    // Auto-close the application when it looses focus. This is what you want
    // to do if you don't want that your application continues to run in the
    // background if the user switch program, answer a call or anything else
    // that would cause your application to lose focus.
    //
    // If you want to keep it running you should at least pause it until the
    // user returns. That's achieved by calling _starling.stop(). You should
    // also add an event listener for the Event.ACTIVATE event that will
    // trigger _starling.start() once the application get's focus again.
    //
    NativeApplication.nativeApplication.exit();
    }
    }
    }

    As we selected to work from the 320x480 resolution and scale it to fit - the top left corner is always at 0, 0 and the bottom right at 320, 480.

    We go over to MyStarlingApp.as and add three images to use for 1x (320x480), 2x (640x960) and 3x (960x1440). We will read the value in Starling.contentScaleFactor to get the scale factor and chose the appropriate image. Up to scale factor 1.5 we'll use 1x, 1.5 to 2.5 we'll use 2x and for anything above 3x.

    We'll also add a TextField to display some text.

    MyStarlingApp.as:
    package {
    import flash.display.Bitmap;
    import starling.core.Starling;
    import starling.display.Image;
    import starling.display.Quad;
    import starling.display.Sprite;
    import starling.events.Event;
    import starling.text.TextField;
    import starling.textures.Texture;

    public class MyStarlingApp extends Sprite {

    [Embed(source="/../assets/1x/Happy.png")]
    private static const MyImage1x:Class

    [Embed(source="/../assets/2x/Happy.png")]
    private static const MyImage2x:Class

    [Embed(source="/../assets/3x/Happy.png")]
    private static const MyImage3x:Class

    private var _image:Image;

    public function MyStarlingApp() {
    super();

    addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }

    private function onAddedToStage(e:Event):void {
    removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    addEventListener(Event.ENTER_FRAME, onEnterFrame);

    createAndShowImage();
    addTextField();
    }

    private function addTextField():void {
    // Add a textfield containing some text
    var textContent:String = "Our scale factor is " + Math.round(Starling.contentScaleFactor);
    var textfield:TextField = new TextField(300, 120, textContent, "Arial", 32);
    textfield.autoScale = true;
    textfield.x = 10;
    textfield.y = 360;
    textfield.hAlign = "center";
    textfield.vAlign = "center";
    addChild(textfield);
    }

    private function createAndShowImage():void {
    // Create bitmap instance and use it to create an image
    _image = getCorrectImageForThisDisplay();

    // Change images origin to it's center
    // (Otherwise by default it's top left)
    _image.pivotX = _image.width / 2;
    _image.pivotY = _image.height / 2;

    // Where to place the image on screen
    _image.x = stage.stageWidth / 2;
    _image.y = stage.stageHeight / 2;

    // Add image to display in order to show it
    addChild(_image);
    }

    private function getCorrectImageForThisDisplay():Image {
    // Get the scaling factor (1, 2, 3 etc)
    var scalingFactor:int = Math.round(Starling.contentScaleFactor);

    if (scalingFactor == 1) {
    return Image.fromBitmap(new MyImage1x(), false, 1);
    }
    else if (scalingFactor == 2) {
    return Image.fromBitmap(new MyImage2x(), false, 2);
    }
    else {
    return Image.fromBitmap(new MyImage3x(), false, 3);
    }
    // If you have a 4x version of the graphics, here is the place to add some code..
    }

    private function onEnterFrame(e:Event):void {
    // Rotate slightly each frame
    _image.rotation -= 0.01;

    // Side-note: The value for rotation is in radians not degrees.
    // If you want to use degrees you convert them to radians like this:
    //
    // radians = degrees * Math.PI / 180
    }
    }
    }
    Don't use EmbedWe're using Embed to add images to our project but in a real project you should use a loader instead. By using Embed all the content is read into memory when the application loads, this will occupy valuable memory which could be better used. Especially phones have limited memory, so best practice is to only load the things you need.

    Set debugger size

    We'll start out running this on a smaller screen that will use our 1x version of the image. Open Run.bat in the project root and set SCREEN_SIZE to iPhone. This will run the application in a 320x480 sized window.


    Hit F5 to run the application. The text should say that we're using the 1x version of the image.

    Exit the application and edit Run.bat again. This time change SCREEN_SIZE to iPhoneRetina. This will run the application in a 640x960 sized window.

    Once again hit F5 to run the application. The text should now have changed to say 2x.

    Test out your project with a couple other screen sizes, you find a comprehensive list of available SCREEN_SIZE variables here.

    Epilogue

    We've now updated our project to work on all kinds of resolutions. We can now develop without worrying over what screen resolution our application will run under and place images and other objects at static pixel positions and let Starling handle the scaling.

    In this example we chose to scale to fit so that none of our content would be out of view regardless of which ratio the screen resolution have. The downside of this is that we might get borders on some screens. For games you might want to use the complete screen and scale to fill instead. Important to remember in that case is to define a safe zone on the screen that you know always will be visible regardless if the screen is 4:3, 16:9 or any other ratio.

    Next tutorial will be aimed at gaming and introducing the use of a physics engine. Until then, happy coding!

    Download source codeThe complete FlashDevelop project. You'll need to change the paths in bat\SetupSDK.bat to match your development environment.