Frage

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;
    }

}
War es hilfreich?

Lösung

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 allowSmooting will help rendering the bitmapData if it's resized or/and rotated, but will slow down the rendering as smooting counts as a filter.

Andere Tipps

This answer was made possible with thanks to @Creative Magic.

I have changed Tile from a Shape into a Bitmap which makes reference to a shared BitmapData instance. This is beneficial because it avoids duplicating the same image data multiple times (once for each sprite instance).

When a particular type of tile is instantiated for the very first time, its bitmap data is generated from SVG data which is then cached. The tile image can then be changed merely by adjusting its bitmapData reference to the artwork of another tile:

package ;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import format.SVG;
import openfl.Assets;

// Tile is now a Bitmap
class Tile extends Bitmap {

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

    // Lookup cached version of tile bitmap.
    private static function lookupBitmapData(tile:String):BitmapData {
        var data:BitmapData = tileImageMap.get(tile);
        if (data == null) {
            // Render tile from SVG into temporary sprite.
            var svg:SVG = new SVG(Assets.getText("img/" + tile + ".svg"));
            tempSprite.graphics.clear();
            svg.render(tempSprite.graphics, 0, 0, 56, 56);

            // Extract bitmap data from temporary sprite and cache.
            data = new BitmapData(56, 56, true, 0x00FFFFFF);
            data.draw(tempSprite);
            tileImageMap.set(tile, data);
        }
        return data;
    }

    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;
            // Merely adjust reference of bitmap data.
            bitmapData = lookupBitmapData(value);
        }
        return _tile;
    }

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

        this.tile = tile;
    }

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top