I see. That’s one of the more difficult targets, as it’s naturally a more sand-boxed environment by design (the web browser controls and restricts access). It’s also the most variable in terms of what is and isn’t supported. Not deal-breakers, just challenges.
The WebGL standard does support compressed textures, but support depends on platform and browser. Even if you do use compressed textures, as you’ve noted already, it may be necessary to test for support and supply assets specific to platform/browser support.
If you’re using a Chromium based browser, you should be able to see a list of supported GL_EXTENSIONS by putting this in the browser address bar:
I have received an initial response, but nothing yet in the way of support for the issue. Hopefully the discussion continues.
You may wish to keep your 7-day trial / 30-day refund in mind.
Purchasing a license
Is there a trial version?
Yes, a 7-day trial with full functionality is available, allowing you to evaluate the product without restrictions. After the trial ends, a license key is required to continue using all features.
Some products, like TexturePacker and SpriteIlluminator, also offer an Essential mode with limited functionality. This mode is free for non-commercial use after the trial. If you use Pro features in Essential mode, you’ll receive a warning before publishing, and some sprites may appear red in the output (TexturePacker).
My trial expired after 7 days. I need more time to evaluate all features!
Unfortunately, we can’t extend the trial period. To protect user privacy, we don’t track individual trial versions, so we’re unable to reset them.
However, we offer a 30-day money-back guarantee, so you can purchase the full version risk-free. Our refund rate is extremely low (only 0.25%–0.5%), which means most users are very happy with the product.
This is a fairly “Adobe Flash timeline” way to handle it
Rather than switching out textures in a single MovieClip, perhaps think of it this way.
You might have an Elf class (extending Sprite perhaps) that contains all properties that correspond to an Elf entity. Within that class, you’d also import all your various Elf animations as separate MovieClips, essentially layered on top of each other, but you’ll only be showing one at a time, based on the state of the Elf.
Every MovieClip that is not active will be removed from the Juggler, with it’s visible property set to false (someAnimation.visible = false). Having a display object set to visible = false tells Starling to stop doing anything with it, so there’s no performance hit.
Some of your animations may loop until interrupted, like an idle loop, or walking loop. Other ones may play once and be done, or then trigger another animation, such as an attack swing (returning to idle), or death animation (that holds on the last frame). All that logic will need to be handled of course.
This is a lightweight way of managing the various animations, and allows you to easily update and modify animations and logic, without it interfering with other animations.
The key thing you’ll need to work out, is how you’ll control the active animation at any given time. There’s a number of ways that could be approached, but it’ll largely depend on your coding style and project structure.
You’ll need to take a bit of care with naming your PNG image sequences. For example, if you name your Elf’s idle loop as:
When using assetMangager.getTextures("elf"), both of those animations might be recognised as "elf" because they both contain that string, jumbling your animations! You’ll need to ensure you reference a fully unique name. So the idle loop would need to be something like:
Now it can be referenced with the unique assetMangager.getTextures("elf-idle"). Alternatively, you can change the frame names in the atlas XML files, rather than re-naming PNG’s and re-exporting atlases.
So in terms of performance, this is very efficient.
Have a look at Delayed Calls, which act as timers:
You can also add event listeners to your movieClips, to handle when they complete (Event.COMPLETE).
I’m not sure what you mean by this. Could you clarify?
I prefer visible=true / visible=false more, because it is simple and effective. Performance wise, it’s very efficient, because the visible=false display object is ignored by Starling, and you’re putting no pressure on garbage collection. Garbage collection is an important thing to keep in mind, because when it runs as it deems necessary, your game will halt for a brief moment. If you want to avoid halts, you should use techniques that favour recycling over destroy/create, where feasible, so garbage collection is avoided.
I started in Adobe Flash, from about the late 90’s (when it was Macromedia). The introduction of ActionScript 3.0 upped things in 2007 and that’s when I started to get a bit more serious about development. I found Starling around 2012-13 I think? I started using it heavily from then on.
My first OpenFL project (back when it was called NME) was early 2013. I mostly tinkered with OpenFL/NME out of interest only for years, as most projects of mine leveraged webcam and/or video, and support for those are lacking in OpenFL. In that time, I was working heavily with AS3/AIR/Starling. Around 2019, I started to use OpenFL on more serious projects, ultimately pulling away from AS3/AIR.
I guess you could say I’ve now “converted” from AS3/AIR to Haxe/OpenFL, but I would still use AS3/AIR if the project required it. I have a lot of respect for the AIR SDK as being full featured and robust. The appeal of Haxe and OpenFL is that it’s open-source (I’m a fan) and it’s ability to target many platforms is powerful.
Not precisely, but Starling stats perhaps? You can see your draw calls, which is probably the more important indicator of performance. Remember, one spritesheet contains many textures within it. As far as the GPU is concerned, the entire spritesheet counts as one texture, even if it contains 50 individual assets. If your code is written to promote batching, this will remain very efficient.
On your Starling instance, initiated in the OpenFL context:
starling = new Starling(StarlingRoot, stage);
starling.start();
// Show stats
starling.showStats = true;
starling.showStatsAt("left", "top", 2);
While Starling reimplements the display list and event dispatcher, it doesn’t need to reimplement everything from OpenFL or Flash. You can use openfl.utils.Timer and openfl.Lib.setInterval() with Starling, if you’d like.
It has multiple timers. The delayed call juggler.delayCall(someHandler, 2) as a once-off timer, and the repeat call juggler.repeatCall(someHandler, 2) as a repeating timer. These are both a DelayedCall, just one is of a repeating type. They’re both detailed in that link above.
The juggler.repeatCall(someHandler, 2) would be equivalent to the “timerEvent setInterval” you mentioned.
The OpenFL timer leverages haxe.Timer and I would consider this an accurate traditional style timer. This is probably more accurate than Starling’s in terms of millisecond accuracy (not that I’ve measured), but Starling timers have other benefits and are perhaps more frame accurate.
The Starling delayedCall ( and repeatCall ) are well integrated with the Starling juggler, frame sync, frame advancement (juggler.advanceTime()), and stopping/starting Starling (Starling.current.stop() and Starling.current.start()).
This is particularly powerful when using a custom Juggler for different parts of your game. Perhaps you want the ability to pause the game, but leave the main interface available still (like menus and such). Your in-game elements, including animations and timers can be put in their own Juggler, and you control when and how that advances, so you can speed-up, slow-down, pause, etc.
The Haxe timer (and by extension, the OpenFL timer), would be unaware of that, and you’d need to manually handle it.
In some way, yes, it’s not unusual that a MovieClip is added to a Sprite in some manner. Even your root Starling class, likely extends Sprite, so adding a MovieClip to your root class is adding a MovieClip to a Sprite.
But, you are not obliged to explicitly create a special Sprite to add a MovieClip to. This is not necessary, unless there’s some specific reason you need to do this:
var sprite = new Sprite();
sprite.addChild(movieclip)
A legitimate reason might be that you’re using the Sprite as a container. An Elf class that extends Sprite, might also serve this function.
var container = new Sprite();
container.addChild(elf_idle);
container.addChild(elf_walk);
container.addChild(elf_attack);
// ...etc
You can now position and handle the single container, instead of needing to position and handle a bunch of MovieClips.
Be aware though, that how you organise your display tree, has a direct impact on batching, which has an impact on draw calls.
The Haxe language has many similarities to ActionScript 3.0, but the API differs in many ways, and is also quite low-level.
One of OpenFL’s primary goals, is to closely mimic the Flash/AIR API, and add those higher level API features.
So simply put, the OpenFL timer exists, to provide a Flash/AIR API style timer you can use.
It doesn’t have to be one or the other. Depending on your need, either can be readily used. You could even just use the Haxe timer. In a Starling project, I tend to use the Starling timers as they’re really simple, and have other benefits.
As a general rule for performance, you should use the simplest option available.
In Flash/AIR and OpenFL, a MovieClip extends a Sprite. So it is in effect, a Sprite+more. In this way, the two are interchangeable in many respects, because one extends the other. But, if you don’t need the features of a MovieClip, you should use the simpler Sprite.
In Starling, there is a difference. Starling’s MovieClip does not extend Sprite, it instead extends the simpler Image, which itself extends the basic Quad. A MovieClip in Starling is not interchangeable with a Sprite, they have notably different purposes.
In Starling, you use a Sprite when you need a functional display object container. You use MovieClip when you need to play a sequence of textures.