Experimenting with OpenFL, DragonBones and Animate CC – simple Mobile browser game

Categories games, HTML5, OpenFL, Starling

This is what I ended up doing, and here it is on GiHub.

I am on a quest to find out how to build a mobile browser game as fast as I can, while also keeping the quality in check. For this I need an efficient production process, and if possible, I would like to keep using the tools and techniques that I am familiar with.

Quick background and current stats: I have been using Flash (now Animate CC) since the Macromedia era and Flash 5, that is more or less 14 years of flash dev. I do the code and the artwork/animation and I am currently studding how to draw better (in self thought way) at https://www.schoolism.com, they are awesome, while also experimenting with Haxe (also in self thought way). But most of my time it is spent raising my son, which is the most amassing adventure ever 🙂.

Back to work. In order to keep game production costs as low as possible, in my pipeline I need to:

  1. Be able to create 2D Animations fast, visually.
  2. Build UI visually.
  3. When there is a need to make small adjustments in UI or in the Animation, the update process should be seamless and fast.
  4. Code in a similar ActionScript 3 way, using events, objects, etc..
  5. Be able to prepare the code in such a way that modifications during the production are relatively easy to do, because you will always need to accommodate something unexpected.
  6. The code should also be scalable, so new levels or functionality are possible without breaking the entire app.
  7. The browser game (or app) should run on a mobile device, in the browser obviously.

I found Haxe to be the perfect match for my needs, while building Mr Nussbaum Boardwalk Challenge. Unfortunately Flambe was hard to bend to my will, so I am now investing my (extremely limited) energy into OpenFL.

OpenFL has a lot in common with ActionScript 3, so at times it doesn’t feel like I switched to a new language at all.

For the IDE, I used HaxeDevelop for a while, even gave Visual Studio IDE a try, but now I am back to FlashDevelop, because during my coding in HaxeDevelop there were a lot of times when the code would not compile at the first try, and only after about 3 to 5 times, without me touching the code. This obviously makes the development process extremely difficult because you never know if the fault is in your code, or the IDE is misbehaving again. So now I have switched back to FlashDevelop, and I will see if I the issues persists.

Here are the tools I use:

  1. Haxe 3.4.3, with the libs dragonbones: 5.0.0, openfl: 6.2.0, starling: 1.8.11
  2. Animate CC 2017.5 with the OpenFL Plugin 1.0.0
  3. DragonBones Pro 5.5
  4. FlashDevelop

The idea was to build a fun crossbow toy, that shoots cute arrows into bubbles of soap. From this, I will probably expand and build some simple educational game, but for production pipeline and tech testing, the simple prototype is enough. The idea to start with a toy (something fun) and build on top of that, came from reading “The Art of Game Design” by Jesse Schell, an eye opening book on how to make games.


After I was happy with the crossbow design, I started to test different animation editors, and decided to remain with Dragon Pro, in part because it had support for OpenFL, but also because it worked with AS3 and Starling, so in the case I wanted to develop the project in AS3, I would be able to reuse the artwork.

After a bit of trial and error and some YouTube watching, I was able to accomplish exactly what I wanted with the corners of the crossbow turning inside when you pull it back. So this is how the crossbow armature looks like in DragonBones, and if you want to check it out even more, you can find all the DragonBones files on GitHub.

Now we move to integrating the animation with OpenFL, and unfortunately things started to break, one after another:

First attempt, render the animation with Startling 1.8, which didn’t work. After some digging around the web, I find that in Starling 1.8 the mesh animation is not supported.

Second attempt, using the OpenFL render, it only showed parts of the animation with the mesh deformation, also on Samsung Tab A (some old version), it crashed the Chrome browser. I tried different export data options from DragonBones, neither of them worked.

But, the examples seemed to work fine, so maybe they are made with an earlier version of DragonBones and there is something funny in the newer data format. Who knows?

Third attempt, build the animation în DragonBones, export it as frame sequence (alpha png). Create a new OpenFL project in Animate CC, import the image sequence inside an MovieClip (that you export it for ActionScript), and just like that, it all worked.

This way also lets me augment the animation inside Animate CC, and also lets me build the UI in a visual way. It is kind of the perfect combination.

Here is the catch, the performance is not great, it works fine on medium to higher end mobile devices using Chrome, but Firefox won’t play nice.

So I tested on some more browsers:

  • On Chrome it works fine, but no fullscreen from the compiled project (might have to check the html file).
  • Firefox – low fps, and breaks after a while.
  • Firefox Focus – won’t show the hole app.
  • Opera – works perfectly, even the full screen
  • Opera mini – works, no fullscreen
  • Dolphin – seems to work really well, but no fullscreen
  • Cm Browser – works, but no fullscreen
  • Via Browser – works, but no fullscreen

So it seems that only Firefox causes problems

Devices tested:

  • iPhone 6s, it works perfectly
  • iPad 2, not usable, it has very low fps
  • Samsung Tab A, not usable very low fps (CPU 1.2 GHz)
  • Huawei nova (CPU 2 GHz), works great (except Firefox)

Other issues and limitations:

Animation on the timeline that use masks, wont show the right way in OpenFL, so don’t use mask in animations. Another big issue will be memory footprint and file size when you use a lot of animations. Probably a better way would be to build UI, and simple animations in Animate CC, and use DragonBones animations without the mesh editor for characters. Hopefully Starling 2 will be ported to OpenFL soon, and we will be able to use DragonBones without a problem with OpenFL and Starling, while keeping Animate CC for UI and other simple animations.

In conclusion, if you (or the client) are OK with the limitations, you can build a browser game or app, quite fast when you use OpenFL in combination with Animate CC and DragonBones, and because the community is really getting into it, I am pretty sure the tools will evolve fast and the remaining obstacles will fall away soon enough.

If anyone else has tried different things on Animate CC, OpenFL Dragon Bones do share with links in the comments.



I am taking on new projects, (I will be opening new projects spots in March 2018) let’s talk contact@cosmindolha.com


Share this

Quick (dirty) buttons for your Starling app

Categories Actionscript, games, Starling

Sometimes you need to control parts of you app for testing so a a quick way to build some buttons in Starling is very useful. In my case, I needed to test different parts of MathSumRun and adding an external library for this purpose only is an overkill.

buttons controll

Here is the dirty code for this:


  1. package com.cosmindolha.mathsumrun
  2. {
  3.     //import com.cosmindolha.mathsumrun.DataDispatcher;
  4.     import com.utils.Delay;
  5.     import starling.display.Canvas;
  6.     import starling.display.Sprite;
  7.     import starling.events.Touch;
  8.     import starling.events.TouchEvent;
  9.     import starling.events.TouchPhase;
  10.     import starling.text.TextField;
  11.     /**
  12.      * ...
  13.      * @author Cosmin Dolha
  14.      */
  15.     public class AppControl extends Sprite
  16.     {
  17.         //private var disp:DataDispatcher;
  19.         public function AppControl()
  20.         {
  21.             x = 1150;
  22.             y = 50;
  23.             //disp = DataDispatcher.getDisp();
  25.             button("Game Over", onGameOver, 0, 0, 75);
  26.             button("Level Done", onLevelFinished, 0, 30, 75);
  27.             button("End Game", onGameEnded, 0, 60, 75);
  28.             button("Time Up!", onTimeUp, 0, 90, 75);
  30.             incrButtons("Stage", onPrevStage, onNextStage, 120);
  31.             incrButtons("Level", onPrevLevel, onNextLevel, 150);
  32.             incrButtons("Qstn", onPrevQuestion, onNextQuestion, 180);
  35.         }
  36.         private function onPrevQuestion():void
  37.         {
  39.         }
  40.         private function onNextQuestion():void
  41.         {
  43.         }      
  44.         private function onPrevLevel():void
  45.         {
  47.         }
  48.         private function onNextLevel():void
  49.         {
  51.         }  
  52.         private function onPrevStage():void
  53.         {
  55.         }
  56.         private function onNextStage():void
  57.         {
  59.         }
  60.         private function onTimeUp():void
  61.         {
  62.             trace("on time up");
  63.         }      
  64.         private function onGameEnded():void
  65.         {
  66.             trace("on game end");
  67.         }
  68.         private function onLevelFinished():void
  69.         {
  70.             trace("level finished press");
  71.         }      
  72.         private function onGameOver():void
  73.         {
  74.             trace("game over press");
  75.         }
  76.         private function incrButtons(str:String, prevFunc:Function, nextFunc:Function, y:Number):void
  77.         {
  78.             button("< -", prevFunc, 0, y, 35);
  79.             var labelField:TextField = new TextField(35, 20, str, "Verdana", 9, 0xffffff, false);
  80.             labelField.touchable = false;
  81.             addChild(labelField);
  82.             labelField.x = 20;
  83.             labelField.y = y;
  84.             button("->", nextFunc, 40, y, 35);
  85.         }
  86.         private function button(str:String, func:Function, x:Number, y:Number, w:Number):void
  87.         {
  88.             var sp:Sprite = new Sprite();
  89.             sp.x = x;
  90.             sp.y = y;
  92.             var canvas:Canvas = new Canvas();
  93.             canvas.beginFill(0xffffff);
  95.             canvas.drawRectangle(0, 0, w, 25);
  96.             canvas.endFill();
  98.             var txt:TextField = new TextField(w, 20, str, "Verdana", 9, 0xffffff, false);
  99.             txt.touchable = false;
  100.             canvas.alpha = .2;
  102.             sp.addChild(canvas);
  103.             sp.addChild(txt);
  104.             sp.addEventListener(TouchEvent.TOUCH, onTouch);
  105.             function onTouch(e:TouchEvent):void
  106.             {  
  107.                 var touch:Touch = e.getTouch(stage, TouchPhase.BEGAN);
  108.                 if (touch == null) return
  109.                 func();
  110.                 canvas.alpha = .5;
  111.                 var returnDelay:Delay = new Delay(returnAlpha, 100);
  112.                 function returnAlpha():void
  113.                 {
  114.                     canvas.alpha = .2;
  115.                 }
  116.             }
  117.             addChild(sp);
  119.         }
  120.     }
  122. }

And the Delay class:


  1. package com.utils
  2. {
  3.     import flash.events.TimerEvent;
  4.     import flash.utils.Timer;
  5.     public class Delay
  6.     {
  7.         private var timer:Timer;   
  8.         private var delayedFunction:Function;
  9.         public function Delay(functionToDelay:Function, delayMilisec:Number)
  10.         {
  11.             this.delayedFunction = functionToDelay;
  12.             timer = new Timer(delayMilisec, 1);
  13.             timer.addEventListener(TimerEvent.TIMER_COMPLETE, callDelayedFunction);
  14.             timer.start();
  15.         }  
  16.         private function callDelayedFunction(event:TimerEvent):void
  17.         {
  18.             timer.removeEventListener(TimerEvent.TIMER_COMPLETE, callDelayedFunction);
  19.             delayedFunction();
  20.         }
  21.     }
  22. }
Share this

Starling Particle Designer – HackTM2015

Categories Actionscript, games

This weekend I went to HackTM2015 and started the development of my Starling Particle Designer.


This tool will be used to make better Particle Effects for my MathSumRun game.

The scope is to design the particle effects directly on my iPad, so I can push the effects to the limits, while still achieving good FPS.

The Starling Particle Designer source sits on GitHub at: ParticleDesigner

To test it on your iPad, you need to have a Jailbreak device and get the ipa file from here.
To install it on my iPad I use ifunbox.

Development is done for iPad 2 with iOS 6. Support for retina devices will be added at a later time.

Share this

If you upgraded to Starling 1.7 and your app is broken, check your assets manager

Categories Actionscript

After updating to Starling 1.7, my game stopped compiling. After a quick debugging, I found the problem in the assets manager. Narrowing it down, it seems that the getTexture returns null if I try to load an atlas texture.

To fix it, change:


  1. var elemTexture:Texture = resources.assets.getTexture("elements");         
  2. var elemXml:XML = new XML(resources.assets.getXml("elements"));
  3. var elemAtlas:TextureAtlas = resources.assets.getTextureAtlas("elements");



  1. var elemAtlas:TextureAtlas = resources.assets.getTextureAtlas("elements");

My assets are named: “elements.png” and “elements.xml”

In my game resources is a separate class that just loads all the elements, and the assets var is set to public, it looks like this:


  1. package com.cosmindolha.mathrun
  2. {
  3.     import flash.events.TimerEvent;
  4.     import flash.filesystem.File;
  6.     import starling.events.Event;
  7.     import starling.utils.AssetManager;
  9.     /**
  10.      * ...
  11.      * @author ... Cosmin Dolha ~ contact@cosmindolha.com
  12.      */
  13.     public class Resource
  14.     {
  15.         public var assets:AssetManager;
  17.         private var disp:DataDispatcher;
  19.         public function Resource(dd:DataDispatcher)
  20.         {
  21.             disp = dd;
  23.             assets = new AssetManager();
  25.             assets.keepAtlasXmls = true;
  27.             var appDir:File = File.applicationDirectory;
  29.             assets.enqueue(appDir.resolvePath("assets"));
  31.             assets.addEventListener(Event.IO_ERROR, onError)
  33.             assets.loadQueue(function(ratio:Number):void
  34.             {
  35.             if (ratio == 1.0)
  36.             {
  37.                 //trace("asstes loaded");
  38.                 disp.assetsLoaded();
  39.             }
  40.             });
  41.         }
  43.         private function onError(e:Event):void
  44.         {
  45.                 trace(e.data);
  46.         }
  48.     }
  50. }
Share this