Today I'm officially releasing OpenFL-bitfive, an alternative backend to OpenFL-html5. Similar to standard backend, OpenFL-bitfive assists you at creating HTML5 games (apart of standard Flash, Windows, Mac, Linux, Android, iOS, [...] ones) with use of comfortable Flash-like OpenFL API. A difference is that while focusing only on certain feature set, OpenFL-bitfive reaches quite higher performance and compatibility in its niche, also making it possible to develop mobile HTML5 games using the framework. This post goes in-depth about it.
A bit of story
Last month I was contacted to develop a game of interesting kind. A small game, one could say. A day worth of work actually. With one important condition though, game must be fully playable on mobile phone' browser. Oh, and there's a deadline too. But that wouldn't be much of a trouble, right?
So there go I, pretty confident about positive outcome of this. Range of tools available is not large but satisfying. Since game was going to involve tile-based levels, GameMaker: Studio was chosen.
Few hours later a prototype with core mechanic is layed out and tested on mobile device. All seems to work well. Pleased with progress I leave to have dinner while phone is still lying on the table with game open. Upon coming back I notice an interesting thing - device is practically overheated, and game is running at 5 FPS instead of required 15-20.
After another hour of investigation, issue is narrowed down to standard "render to texture" functionality doing something very uncommon, causing game performance to slowly degrade over time. So yes, another game, another bug...
Being the core component of game, substitution could not be done without awkward sacrifices. But sure, there's still some time left, maybe the bug will be fixed. Next day (July 10) I file the bug report. Example is attached, problem is described clearly, and it would look like it could get fixed fast... or so I thought. After a week of silence it becomes apparent that it probably isn't going to be fixed that fast. And so the project gets delayed, and I'm left with a thought, do I really have to wait for fixes every time?
Though what are the options? Code in many of software solutions is proprietary, and moderately to heavily obfuscated. Not something you may easily debug to aid process of bug fixing. On other hand there are Haxe frameworks like HaxePunk and HaxeFlixel, that would be a good replacement if not one thing - neither are good with mobile HTML5. HaxePunk waits for a multitude of OpenFL bug fixes to work correctly. Situation with HaxeFlixel is better, but not appealing - sounds don't quite work, and the "entry level" testing device is pausing every few seconds to collect newly arranged garbage.
It's not like OpenFL-html5 is poorly written. Pursuing the goal of fully supporting Flash API is no easy task. It is an achievement of making it go as far. But with more functions comes larger footprint (and bugs). And also that small question: does your application really need all the things included?
Ultimately, a Canvas-based HTML5 game would consist of a single <canvas> element that would only move around the page slightly to cope better with different window and screen sizes.
Of course, representing proper Flash DOM would take a couple more elements, but still, the whole extravaganza with overlapping canvases is far not always needed. Neither (generally) is the complicated system of component events and properties. Generally it did cross my mind several times that what is needed for most games I make, is, in essence, the same HTML+CSS3 DOM that is already present in browser, and close to no simulation from JavaScript side.
After a bit more time thinking about this, I decide to take the initiative and make "that one framework" that I need instead of waiting for a miracles. No strange practices, no throwing memory around, no sacrifices for the features one won't use... no bullthings, you could say.
And so, five weeks and some thousand lines of code later, I'm proud to present OpenFL-bitfive.
Principles
OpenFL-bitfive features primarily custom source code, and is built on a set of principles:
When less is more
Instead of attempting to support as much of Flash API as possible, OpenFL-bitfive focuses only on subset that is actually used in bitmap-driven games. Working with HTML5 games since 2011, I can tell that I do have a grip of what is right and what is wrong about implementing frameworks for these. When you add a Bitmap to stage, it has an actual Canvas component inside (the BitmapData). There is no redirection nor drawing overhead in this. Element transformations are processed via CSS3. In their vast majority, events that you catch are actual DOM events. Things are as simple as they need to be.
Visual DOM
If you've ever dealt with trying to figure out what is going wrong in your DOM under OpenFL-html5, you may have noticed that this part doesn't go easy. This is partially due to fact that DOM tree doesn't really look... like a tree. More like a... well, I'm not even sure:
In OpenFL-html5, on other hand, DOM remains... well, itself. If project is compiled with Debug configuration, framework will even do you a favour of labelling every element present on stage, also allowing to retrieve Haxe-side objects via node field of elements:
Memory well-fit
We've all heard horror stories about garbage collectors. Some as well did see the dark side of these when developing for mobile platforms. What is still considered "pretty OK" on desktop, may as well turn application into semi-interactive slideshow in mobile web.
OpenFL-bitfive tries to keep both memory usage and memory allocation minimal, creating instances only when needed and using pooling where acceptable.
Fancy when appropriate
Flash and HTML5 differ a lot, and each has its own quirks. This makes the process of implementing Flash API in HTML5 a hard task. However there are parts that overlap between two, and permit better implementation for specific cases of usage. OpenFL-bitfive takes advantage of these, allowing code to work just about as fast as it would in "plain" HTML5 where possible.
This means, for example, that BitmapData functions will utilize globalAlpha and globalCompositionOperation to allow alpha-related operations to be processed without using ImageData, granting noticeable performance boost and permitting simpler code.
Comparisons
Comparing OpenFL backends is no easy task, but here are a couple of graphs:
As expected, with fewer functions comes smaller filesize. I plan to further improve results here by introducing a number of flags to permit excluding unused functionality from generated code completely.
I don't know if that's the right term, but let's call it that - this is the rate at which according otherwise empty (single DisplayObject) project emits memory (as observed via profiler). Not completely sure what makes up for difference here.
Perhaps, something about rendering. And copyPixels using ImageData in OpenFL-html5, it seems.
There's something about the current implementation that browsers seem to like. Might be rounding of drawing coordinates, which has shown to improve performance earlier, despite of lack of visual difference.
There's obviously more to comparisons of two. You can contribute to repository with these tests, if you feel like it.
Some facts
- Backend components had to be debugged separately until almost the middle of development (~two weeks in), since amount of inner references was making it impossible to compile even a blank OpenFL project without implementing ~40 classes.
- As of moment of writing this post, original bug (from discovery of which development started; see above) remains unfixed. Given that supported feature set is similar, one could even say that I won some time (as opposed to waiting).
- A fair part of BitmapData source dates as early as last autumn, from time when I was attempting to contribute several improvements into main codebase, but failed for various reasons.
- Originally I was going to add "just about 20" classes that were relevant to desired project type. Currently there are 78 classes.
The future
I plan to further work and improve this project to both provide better performance and wider API coverage. Perhaps it's also worth telling that developing something for whole month (without working on other projects) has, let's say, some negative monetary effects, so I will be also developing a number of HTML5 games to keep things afloat and publishing the progress on blog. Stay in touch!
Download
Project is hosted on Github. Thus you can either clone the project (or, better, use haxelib git) or download ZIP with current version.
... and what do you think?
In the Readme for openfl-bitfive:
https://github.com/YellowAfterlife/openfl-bitfive#usage, you say:
“Navigate to application.xml of your project and add the following
before inclusion of OpenFL library: ”
In HaxeFlixel, there is no application.xml, and the closest thing to
it is Project.xml.
So I put in “” as
the first child node of the “” element.
I then run the build command, and get the following error output:
$ lime build html5
/usr/lib/haxe/lib/openfl-bitfive/2,0,1/openfl/Assets.hx:487:
characters 31-57 : DefaultAssetLibrary should be openfl.AssetLibrary
/usr/lib/haxe/lib/openfl-bitfive/2,0,1/openfl/Assets.hx:487:
characters 31-57 : For function argument ‘library’
/usr/lib/haxe/lib/lime/2,0,0-alpha,7/lime/system/System.hx:75:
characters 2-35 : Class has no field config
/usr/lib/haxe/lib/lime/2,0,0-alpha,7/lime/system/System.hx:76:
characters 2-32 : Class has no field config
/usr/lib/haxe/lib/lime/2,0,0-alpha,7/lime/system/System.hx:77:
characters 2-24 : Class has no field create
As you can see, the openfl-bitfive library gets invoked, however,
something goes wrong, and I do not understand the error messages. Do
you think you could help me to figure out what is going wrong here?
If you can, could you please add some instructions for how to use
Haxeflixel together with openfl-bitfive in the Readme file for your
project?
This is a compatibility bug with a recent update of OpenFL. I’m currently getting to fixing it.
Yeah, man. I really LOVE this thing, but with the new Haxe update, it’s currently broken. I’m about to “fork” it on my GitHub, and repair it, so whenever you’ve got some time, maybe check it out? And, if my fixes are to your liking, pull my changes into your main branch?
I’ve recently updated the library to reflect OpenFL2 changes (openfl.* – flash.* mapping), but uploaded a new version to haxelib only yesterday or so. If you know of any overlooked inconsistencies, feel free to mail me or open an issue on github.
Pingback: Introducing HÖVE! | insweater
Pingback: Presenting: Power of 2 ^ 2 – Blip Ball - 2D Heroes
This looks amazing, will try it tonight. Thanks for sharing your work.
Thank you for this, I agree optimal / minimal html5 backends for Haxe & OpenFL gamesdev are the right route – and bitfive is mostly working! I’ve just tweaked awe6 to accommodate.