====== Starling 2 - Migration Guide ====== The majority of the changes in Starling 2 are happening completely behind the scenes; for many projects, it should be very easy to upgrade to the new version. There are two exceptions, though: * The way to write custom rendering code (e.g. shaders) has completely changed. * Some third-party libraries that rely on Starling might not have been updated yet. In such cases, it might be better to just stick with the old version for the time being. I will continue to support it with bugfixes, so there's no immediate need to upgrade. Never change a running system, right? For any new projects, though, I highly recommend switching to Starling 2. This document gives long-time Starling users a quick overview about some gotchas they might encounter during the migration. My recommendation: check in (or save away) your current project version (just to be sure), then replace the old Starling SWC with the new one. After that, it's just a matter of fixing all the errors and warnings your compiler will throw at you. :-) ===== TextField ===== ==== TextFormat ==== The ''TextField'' is finally accompanied by a ''TextFormat'' class. The setup is quite similar to the classic Flash classes — but without the pain of constantly having to re-assign the format for changes to show up. In Starling, when you change the TextField's format, it's going to be updated right away! Furthermore, the ''HAlign'' and ''VAlign'' classes were merged into one ''Align'' class that contains constants for both directions. // old version: textField = new TextField(width, height, "Lorem Ipsum", "Arial", 12); textField.hAlign = HAlign.LEFT; // new version: textField = new TextField(width, height, "Lorem Ipsum"); textField.format.setTo("Arial", 12); textField.format.horizontalAlign = Align.LEFT; ==== Native Filters ==== The old ''nativeFilters'' property on the ''TextField'' class is gone for good, I'm afraid. That property was introduced before Starling had filters, and I figured that my time would be better spent enhancing the filter API than porting this over. (Using those native filters was actually not as straight-forward as one would assume, because they might change the bounds of the text area.) My recommendation: use the new filters that are coming with Starling. For best performance, call ''filter.cache()'' right away. That will yield the same performance as before! Call ''cache()'' again when the text changes. ===== Button ===== Since the ''Button'' class contains an optional ''TextField'' as well, it made sense to add such a format property to it, too. It's called ''textFormat''. // old version: var button:Button = new Button(texture); button.fontSize = 20; button.fontName = "Arial"; // new version: var button:Button = new Button(texture); button.textFormat.size = 20; button.textFormat.font = "Arial"; ===== ClipRect property ===== In Starling 1.x, you could use the ''clipRect'' property on sprites to trim the rendered area to the bounds of a stage-aligned rectangle. This property was removed altogether; instead, just use the ''mask'' property (introduced in Starling 1.7) with a ''Quad''. var sprite:Sprite = new Sprite(); // old version: sprite.clipRect = new Rectangle(10, 10, 50, 50); // new version: sprite.mask = new Quad(50, 50); sprite.mask.x = sprite.mask.y = 10; Different to the old property, that works on all display objects (not just sprites) and even supports rotations. Performance-wise, it's just as fast: Starling automatically recognizes that the mask has a rectangular shape and uses Stage3D's scissor rectangle, just like the "clipRect" did in previous versions. ===== Texture repeat ===== The ''repeat'' property on the Texture class is no more. The problem with that concept was that you're working with atlas textures most of the time, and there's no way to get them to repeat correctly. However, there's now a much more powerful replacement: the ''tileGrid'' property on the ''Image'' class. Feathers users will find this familiar: it mimics / replaces Feather's ''TiledImage''. If you assign a Rectangle to this property, the image will be divided into a grid that displays the current texture in each and every cell. The assigned rectangle points to the bounds of one cell; all other elements will be calculated accordingly. A zero or negative value for the rectangle's width or height will be replaced with the actual texture size. Thus, you can make a 2x2 grid simply like this: var image:Image = new Image(texture); image.tileGrid = new Rectangle(); image.scale = 2; Alternatively, there's also a ''textureRepeat'' property on the ''Image'' class now that does work just like the old ''repeat''. However, it doesn't work for all kinds of textures, so you're generally better off with the ''tileGrid''. ===== No more "flatten" ===== Starling 2 introduces a render cache, which automatically recognizes all objects that have //not// been modified since the last frame and draws them from the cache. This is extremely efficient and takes a huge burden off the CPU, especially for business-apps or menu screens that contain mostly static objects. Thus, the usefulness for the old "flatten" feature was drastically decreased; especially since performance critical scenarios are better solved by using the new ''MeshBatch'' class directly (which replaces the old ''QuadBatch''). It was also often misunderstood for a ''cacheAsBitmap'' replacement, and thus used in cases that actually hurt performance. The feature might come back one day — but for now, just remove all those calls. ===== Changes in the Juggler ===== You might be aware that some of the juggler's methods use object pooling internally. For example, when you call ''juggler.tween()'' or ''juggler.delayCall()'', the methods will take the ''Tween'' and ''DelayedCall'' instances from a pool for maximum efficiency. However, they previously also returned instances to those objects, even though they were disguised as instances of ''IAnimatable''. The problem: if anybody kept those instances and used them after the juggler was already finished with them, they might point to objects already used elsewhere! This lead to bugs that were extremely hard to track down. For this reason, the Juggler now returns ''uint'' handles instead. They are unique and can be used to remove objects from the juggler via ''removeByID'', avoiding any of those side effects. // old version: var tween:IAnimatable = juggler.tween(hero, 2, { x: 100 }); Starling.juggler.remove(tween); // new version: var tweenID:uint = juggler.tween(hero, 2, { x: 100 }); juggler.removeByID(tweenID); ===== VertexData ===== The ''VertexData'' class was completely rewritten and is now much more flexible than before. The new version can store arbitrary data, making it one of the fundamental building blocks of Starling's new rendering architecture. You can almost use it like before, though, if you just modify your method calls a little. var position:Point = new Point(); var texCoords:Point = new Point(); // old version: vertexData.getPosition(0, position); vertexData.setPosition(0, 320, 200); vertexData.getTexCoords(0, texCoords); vertexData.setTexCoords(0, 0.5, 0.5); // new version: vertexData.getPoint(0, "position", position); vertexData.setPoint(0, "position", 320, 200); vertexData.getPoint(0, "texCoords", texCoords); vertexData.setPoint(0, "texCoords", 0.5, 0.5); ===== Removed Vector- and Array-Util ==== Those classes had a very short life-time, being introduced only in Starling 1.7. With AIR 19, Adobe added the ''insertAt'' and ''removeAt'' methods directly to the Vector- and Array-classes, making those helper classes obsolete. Be careful, though, if you made use of negative indices with Starling's implementations, e.g. ArrayUtil.insertAt(array, "test", -1); Starling's code would insert "test" at the end of the array; Adobe's code at the next-to-last index. Doesn't make any sense IMHO, but well ... that's another story. Just keep the difference in mind. ===== QuadBatch → MeshBatch ===== The ''QuadBatch'' is no more. The replacement is the new ''MeshBatch'' class, which works with all types of meshes, which includes ''Quad'' and ''Image'', of course. Usage is almost identical. ===== Moved or renamed Methods ===== One of the first things I did when I started with the new version was a clean-up of the "utils"-package. Thus, some of the functions now moved into container classes. utils.formatString() => utils.StringUtil.format() utils.cleanMasterString() => utils.StringUtil.cleanMasterString() utils.getNextPowerOfTwo() => utils.MathUtil.getNextPowerOfTwo() Furthermore, some properties and methods were renamed slightly, for better consistency or just because I felt like doing so, hehe. ;-) image.smoothing => image.textureSmoothing ===== Skipping unchanged Frames ===== There's one very useful new feature in Starling that I want to mention here, because I think it's relevant for anyone upgrading to the new version. That's the new property ''skipUnchangedFrames'' on the Starling instance. If enabled, Starling will recognize if the stage hasn't changed since the last frame and won't do any rendering in that case. This can potentially save the users of your app a LOT of battery time! The only side effect: if you're using ''RenderTexture'' or ''VideoTexture'' instances, you have to take a little special care (you need to call ''starling.setRequiresRedraw()'' when their contents is changed). That's also the reason why I didn't activate the feature by default. An easy way to see if you're benefiting from this change: enable the ''statsDisplay'' and have a look at its color: whenever it turns from black to dark green, the majority of the last couple of frames has been skipped. ===== KeyboardEvents are no longer broadcast ===== Previously, you could add ''KeyboardEvent.KEY_DOWN/KEY_UP'' events to any display object: those events were broadcast to all objects on the stage. However, that lead to performance issues if people had lots of objects on the screen. For this reason, I'm now dispatching them only to the stage. The easiest way to listen to those events now is like this: Starling.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); It's very important that this event handler is removed when the current object is removed from the display list. Thus, I actually recommend doing it the following way: // in the class constructor: stage.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); stage.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage); // instance methods private function onAddedToStage():void { stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); } private function onRemovedFromStage():void { stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); } That way, it can't happen that the object still listens to those events, even if it has been removed from the stage. That will avoid any memory leaks, too. ===== Misc ===== Here are some more changes that didn't quite fit into their own category. * The default profile in Starling's constructor is now "auto" * All ''mipMap'' arguments now default to ''false'' * Premultiplied alpha is now **always** activated, even ATF textures are converted to PMA on rendering. This makes sure that textures always behave identically, no matter the format. * The minimal required version of AIR / Flash Player is now "19". * The property ''Starling.handleLostContext'' was removed. This means that context losses are now always taken care of. * Starling no longer differentiates between tinted and untinted meshes, so colored quads no longer break batching. If you're using the old ''alpha = 0.999'' trick, you can safely remove that. Those should be the most important gotchas! If anyone finds something worth mentioning that I forgot, feel free to add that below. Thanks in advance! //Room for other notable differences.//