flashspritehaxeopenfl

Creating multiple instances of sprites in OpenFL?


I am loading my sprite images using SVG images so that they smoothly scale to match device resolutions. Currently I am naively rendering the SVG data for each sprite, but I would like to reduce memory overhead and improve performance by sharing the rendered image across multiple sprite instances.

How can this be achieved using OpenFL / Haxe?

For example:

The tile implementation below is wasteful since SVG image is rendered for each tile upon creation.

// Each of the following tile sprites contain copies of the same image.
var xyz1:Tile = new Tile("xyz");
var xyz2:Tile = new Tile("xyz");
var xyz3:Tile = new Tile("xyz");

Tile Implementation

package;

import flash.display.Shape;
import format.SVG;
import openfl.Assets;

class Tile extends Shape {

    // Static cache of SVG data to avoid loading asset each time.
    private static var tileImageMap:Map<String, SVG> = new Map<String, SVG>();

    private static function lookupSVG(tile:String):SVG {
        var svg:SVG = tileImageMap.get(tile);
        if (svg == null) {
            svg = new SVG(Assets.getText("img/" + tile + ".svg"));
            tileImageMap.set(tile, svg);
        }
        return svg;
    }

    public var tile(get,set):String;

    private var _tile:String;

    private function get_tile():String {
        return _tile;
    }

    private function set_tile(value:String):String {
        if (value != _tile) {
            _tile = value;

            // Render tile SVG to tile sprite.
            // How can this be cached and reused by multiple tile instances?
            graphics.clear();
            lookupSVG(value).render(graphics, 0, 0, 56, 56);
        }
        return _tile;
    }

    public function new(tile:String) {
        super();

        cacheAsBitmap = true;

        this.tile = tile;
    }

}

Solution

  • With all regard to a good question and your approach, I personally find it too complex and unnecessary sophisticated.

    If you never resize the tile, why not make a bitmapData that you could reuse unlimited number of times with great rendering performance? Just render the SVG once before and make a bitmapData:

    var bd:BitmapData = new BitmapData( tileWidth, tileHeight );
    bd.draw(tile);
    // add the bd to some array of your tile set or assign it to a tile skin variable
    

    It's later easy to reuse it with the graphics object (bitmapFill) or by making a Bitmap object. You can even animate in Bitmap object by changing the bitmapData property!

    If you do plan to resize it, I would make a few size variations of the tile set and scale it. If you'll use this method please note that using allowSmoothing will help rendering the bitmapData if it's resized or/and rotated, but will slow down the rendering as smoothing counts as a filter.