Низкая производительность (?) с 200 движущимися кругами в Starling

У меня есть этот код, который рисует анимацию, похожую на дождь, с 200 кругами. По сути, 200 кругов со случайными x, y, радиусом и скоростью, которые идут сверху вниз и сбрасываются обратно наверх случайно x (опять же), когда он существует на экране ... на LG G2 я получаю 26 кадров в секунду с 200 кругами, и я подозреваю, что делаю что-то не так, так как знаю, что Старлинг может НАМНОГО лучше, чем это...

Основной:

[SWF(width="640", height="960", frameRate="60", backgroundColor="#ffffff")]
public class ParticleTest extends Sprite
{
    private var _starling:Starling;

    public function ParticleTest()
    {
        var screenWidth:int  = stage.fullScreenWidth;
        var screenHeight:int = stage.fullScreenHeight;
        var viewPort:Rectangle = new Rectangle(0, 0, screenWidth, screenHeight)

        _starling = new Starling(Particle, stage, viewPort);
        _starling.stage.stageWidth  = 640;
        _starling.stage.stageHeight = 960;
        _starling.showStats = true;
        _starling.start();
    }
}

Частица:

private var particles:Array = [];

    public function Particle()
    {
        addEventListener(Event.ADDED_TO_STAGE, init);
    }

    private function init(event:Event):void {
        for (var i:int=0;i<200;i++) {
            particles[i] = new Circle();
            addChild(particles[i]);
        }

        addEventListener(Event.ENTER_FRAME, update);
    }

    private function update(event:Event):void {
        for (var i:int=0;i<particles.length;i++) {
            particles[i].update();
        }
    }

Круг:

private var _x:int = 0;
    private var _y:int = 0;
    private var _speed:int = 0;
    private var _radius:int = 0;
    private var _color:uint = 0x000000;

    private var MIN_RADIUS:int = 2;
    private var MAX_RADIUS:int = 14;
    private var MIN_SPEED:int = 8;
    private var MAX_SPEED:int = 14;
    private var COLORS:Array = [0xff7729, 0x1ab58a, 0xffebca, 0xff2151, 0xffad29];

    private var _shape:Shape = new Shape();
    private var _graphics:Graphics = _shape.graphics;
    private var _bmpData:BitmapData;
    private var _image:Image;

    public function Circle()
    {
        shuffle();
        init();
        draw();
    }

    private function shuffle():void {
        this._radius = Math.floor(Math.random() * this.MAX_RADIUS) + this.MIN_RADIUS;
        this._color = this.COLORS[Math.floor(Math.random() * this.COLORS.length)];
        this._speed = Math.floor(Math.random() * this.MAX_SPEED) + this.MIN_SPEED;
        this._x = Math.floor(Math.random() * Starling.current.nativeStage.stageWidth);
        this._y = Math.floor(Math.random() * Starling.current.nativeStage.stageHeight) - Starling.current.nativeStage.stageHeight;
    }

    private function init():void {
        this._graphics.clear();
        this._graphics.beginFill(this._color, 1);
        this._graphics.drawCircle(this._radius, this._radius, this._radius);
        this._graphics.endFill();

        this._bmpData = new BitmapData(this._radius*2, this._radius*2, true, 0x000000);
        this._bmpData.draw(this._shape);

        this._image = Image.fromBitmap(new Bitmap(this._bmpData, "auto", true));
        addChild(this._image);
    }

    private function draw():void {
        this._image.x = this._x;
        this._image.y = this._y;        
    }

    public function update():void {
        this._image.x = this._x;
        this._image.y += this._speed;
        if (this._image.y > Starling.current.nativeStage.stageHeight) {
            shuffle();
            draw();
        }
    }

Я делаю это неправильно? Есть ли лучший способ добиться того же эффекта?

Спасибо!


person trueicecold    schedule 08.09.2014    source источник
comment
Вы создаете уникальные данные bitmapData для каждого круга, что означает, что вы заставляете Старлинг рисовать 200 раз перед рендерингом, что слишком много.   -  person BotMaster    schedule 08.09.2014
comment
БотМастер прав. Для каждого нового BitmapData требуется вызов отрисовки. Также рекомендую прочитать статью Старлинга об оптимизации - wiki.starling-framework.org/manual/performance_optimization   -  person Crabar    schedule 08.09.2014
comment
Спасибо вам обоим, но я думаю, что все еще что-то упускаю (даже после прочтения страницы оптимизации)... Я предполагаю, что есть способ повторного использования одного bitmapData или, альтернативно, заставить его рисовать все 200 кругов одновременно, но я не мог придумать, как это сделать... Есть ли шанс на подсказку или направление?   -  person trueicecold    schedule 08.09.2014
comment
Подумайте о передаче одного BitmapData всем вашим объектам Circle. Затем посмотрите на использование одного объекта Graphics для выполнения всего рисунка — вы значительно улучшите производительность, если сможете избежать всех этих вызовов addChild().   -  person Brian    schedule 09.09.2014
comment
Этот последний совет не имеет значения, так как вы все равно получите 200 вызовов отрисовки. Вам нужен только один Image.fromBitmap для всего вашего круга, используйте белый цвет, затем измените этот цвет с помощью свойства tint объекта Starling. Вы должны получить только один вызов отрисовки для любого количества кругов.   -  person BotMaster    schedule 09.09.2014


Ответы (1)


Вы не можете копировать и вставлять старый код из классического AS3 в Starling, вам нужно использовать новую логику для оптимизации и использования преимуществ.

  private var particles:Array = [];
  private var speeds:Array = [];

 private var MAX_SPEED = 10;
 private var MIN_SPEED = 1;

private var filter0:ColorMatrixFilter = new ColorMatrixFilter();
private var filter1:ColorMatrixFilter = new ColorMatrixFilter();
private var filter2:ColorMatrixFilter = new ColorMatrixFilter();
private var filter3:ColorMatrixFilter = new ColorMatrixFilter();
private var filter4:ColorMatrixFilter = new ColorMatrixFilter();
private var COLORS:Array = [filter0, filter1, filter2, filter3, filter4];


 // Embed the texture:
 [Embed(source="circle.png")]    //<---- EMBED A CRICLE PNG
  public static const Circle:Class;

public function Particle()
{
    addEventListener(Event.ADDED_TO_STAGE, init);
}

var texture:Texture = Texture.fromBitmap(new Circle());
private function init(event:Event):void {
    filterRed.tint(0xff7729, 1);
    filterRed.tint(0x1ab58a, 1);
    filterRed.tint(0xffebca, 1);
    filterRed.tint(0xff2151, 1);
    filterRed.tint(0xffad29, 1);

    for (var i:int=0;i<200;i++) {
        particles[i] = new Image(texture);

        shuffle(i);


        addChild(particles[i]);
    }

    addEventListener(Event.ENTER_FRAME, update);
}

private function update(event:Event):void {
    for (var i:int=0;i<particles.length;i++) {
        update(i);
    }
}

public function update(imageID:int):void {
    particles[imageID].x = x;
    particles[imageID].y += speeds[imageID];
    if (_image.y > Starling.current.nativeStage.stageHeight) {
        shuffle(i);
    }
}

public function shuffle(i:int):void {
    particles[i].scaleX = particles[i].scaleY = Math.floor(Math.random() * this.MAX_RADIUS/particles[i].width) + this.MIN_RADIUS/particles[i].width;
    particles[i].filter = this.COLORS[Math.floor(Math.random() * this.COLORS.length)];
    speeds[i] = Math.floor(Math.random() * this.MAX_SPEED) + this.MIN_SPEED;
    particles[i]._x = Math.floor(Math.random() * Starling.current.nativeStage.stageWidth);
    particles[i]._y = Math.floor(Math.random() * Starling.current.nativeStage.stageHeight) - Starling.current.nativeStage.stageHeight;
}
person esdebon    schedule 17.10.2014