2013-08-14 4 views
0

У меня 2 класса. Имитация жидкости. Оба класса довольно прямые и короткие, но после 2 секунд работы симуляция становится очень медленной, похожей на утечку памяти. Но я не вижу никаких утечек в этом коде.AS3: Почему эта жидкостная симуляция работает медленнее и медленнее?

Пожалуйста, дайте мне знать, если вы можете понять, почему это происходит?

FluidLayer.as

package { 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
import flash.display.BitmapData; 
import flash.filters.BlurFilter; 
import flash.display.Bitmap; 
import flash.geom.Point; 
import flash.geom.ColorTransform; 
import flash.display.IBitmapDrawable; 
import flash.events.Event; 
import flash.display.MovieClip; 


public class FluidLayer extends MovieClip { 

    private var canvas:Sprite; 
    private var b:Bitmap; 
    private var blur:BlurFilter = new BlurFilter(20,20,3); 
    private var bmd1:BitmapData; 

    public function FluidLayer() { 
     canvas = new Sprite(); 

     for(var i:int = 0;i < 600;i++){ 

      var p:Particle = new Particle(); 
      canvas.addChild(p); 
      p.x = stage.stageWidth * Math.random(); 
      p.y = stage.stageHeight* Math.random(); 
      p.initi(stage); 
     } 

     canvas.filters = new Array(blur); 
     addEventListener(Event.ENTER_FRAME, render); 


    } 


    private function render(e:Event):void{ 

     remove(); 

     b = new Bitmap(makeFluid(canvas),"auto", true); 
     b.alpha = 0.7; 
     addChild(b); 

    } 

    private function makeFluid(o:Sprite):BitmapData{ 

     bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true); 
     bmd1.draw(o,null,null,null,null,true); 
     bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false); 

     return bmd1; 
    } 


    private function remove():void{ 
      if(numChildren > 1) 
      removeChildAt(1); 

      if(bmd1){ 
       bmd1.dispose(); 
       bmd1 = null; 
      } 
    } 

}}

Particle.as

package { 

import flash.display.MovieClip; 
import flash.events.Event; 
import flash.display.Stage; 


public class Particle extends MovieClip { 

    private var speedX:int; 
    private var speedY:int; 
    private var _s:Stage;  

    public function Particle() { 
     this.graphics.beginFill(0x00CCFF); 
     this.graphics.drawCircle(0,0,Math.random() * 30); 

     speedX = Math.random() * 10 - 5; 
     speedY = Math.random() * 10 - 5; 

     this.addEventListener(Event.ADDED_TO_STAGE, initi); 

    } 

    public function initi(s:Stage):void{ 
     this._s = s; 
     addEventListener(Event.ENTER_FRAME, render); 
    }  

    private function render(e:Event):void{ 

     this.x += Math.random()*speedX; 
     this.y += Math.random()*speedY; 


     if(this.x > _s.stageWidth || this.y > _s.stageHeight){ 

      //this.x = Math.random()*_s.stageWidth; 
      //this.y = Math.random()*_s.stageHeight; 

      removeEventListener(Event.ENTER_FRAME, render); 
      this.parent.removeChild(this); 
     } 
    } 
}} 

ответ

0

Итак, я собрал решение для моего вопроса с помощью Андреаса и адама.

Andreas - показал мне, что я забыл распоряжаться BitmapData

Adamh (очень хорошее место!) - сказал мне, чтобы определить scrollrect на холсте (увеличил производительность много!)

Но что сделал это, в конце концов, и сделало эксплуатационную жидкость, была простой ошибкой с моей стороны. Я заметил в particle.as> render(), что я только проверял, была ли частица вне границ с двух сторон (facepalm), глупой ошибкой. Когда я изменил функцию рендеринга, чтобы проверить оставшиеся 2 стороны, он исправил проблему с производительностью.

Извините за глупый вопрос :) и еще раз спасибо Andreas и adamh

финальные классы:

FluidLayer.as

package { 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
import flash.display.BitmapData; 
import flash.filters.BlurFilter; 
import flash.display.Bitmap; 
import flash.geom.Point; 
import flash.geom.ColorTransform; 
import flash.display.IBitmapDrawable; 
import flash.events.Event; 
import flash.display.MovieClip; 
import flash.geom.Rectangle; 


public class FluidLayer extends MovieClip { 

    private var canvas:Sprite; 
    private var b:Bitmap; 
    private var blur:BlurFilter = new BlurFilter(20,20,3); 
    private var bmd1:BitmapData; 

    public function FluidLayer() { 
     canvas = new Sprite(); 
     canvas.scrollRect = new Rectangle(0,0,1010,550); 
     for(var i:int = 0;i < 600;i++){ 

      var p:Particle = new Particle(); 
      canvas.addChild(p); 
      p.x = stage.stageWidth * Math.random(); 
      p.y = stage.stageHeight* Math.random(); 
      p.initi(stage); 
     } 

     canvas.filters = new Array(blur); 
     addEventListener(Event.ENTER_FRAME, render); 


    } 


    private function render(e:Event):void{ 

     remove(); 

     b = new Bitmap(makeFluid(canvas),"auto", true); 
     b.alpha = 0.7; 
     addChild(b); 

    } 

    private function makeFluid(o:Sprite):BitmapData{ 

     bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true); 
     bmd1.draw(o,null,null,null,null,true); 
     bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false); 

     return bmd1; 
    } 


    private function remove():void{ 
      if(numChildren > 1) 
      removeChildAt(1); 

      if(bmd1){ 

       bmd1.dispose(); 
       bmd1 = null; 
      } 
    }}} 

Particle.as

package { 

import flash.display.MovieClip; 
import flash.events.Event; 
import flash.display.Stage; 


public class Particle extends MovieClip { 

    private var speedX:int; 
    private var speedY:int; 
    private var _s:Stage;  

    public function Particle() { 
     this.graphics.beginFill(0x00CCFF); 
     this.graphics.drawCircle(0,0,Math.random() * 30); 

     speedX = Math.random() * 10 - 5; 
     speedY = Math.random() * 10 - 5; 

     this.addEventListener(Event.ADDED_TO_STAGE, initi); 

    } 

    public function initi(s:Stage):void{ 
     this._s = s; 
     addEventListener(Event.ENTER_FRAME, render); 
    }  

    private function render(e:Event):void{ 

     this.x += Math.random()*speedX; 
     this.y += Math.random()*speedY; 


     if(this.x > _s.stageWidth || this.y > _s.stageHeight || this.x < 0 && this.y < 0){ 

      this.x = Math.random()*_s.stageWidth; 
      this.y = Math.random()*_s.stageHeight; 

      //removeEventListener(Event.ENTER_FRAME, render); 
      //this.parent.removeChild(this); 
     } 
    } 
}} 
0

Вы должны вызвать bmd1.dispose(); перед тем, как восстановить его или он не выпустит растровое изображение из памяти.

Edit:

После просмотра кода очень внимательно, оптимизировать его, и очистки некоторые вещи, я пришел к выводу, что ваша симуляция уже не работает медленнее и медленнее.

Проблема заключалась в том, что вы могли бы рассчитать скорость частиц x и y. По существу, это уменьшалось бы в скорости, пока не остановилось бы все вместе. В дополнение к массивному размытию высокого качества, которое вы разместили, и отсутствию освобождения растровых изображений, ваш фильм будет казаться и на самом деле медленным сканированием.

Вот ваш код, который я изменил. Я сравнил его, и он не достиг пика выше 10% процессорного или 40-килобайтного объема памяти через 15 минут.

Particle.as

package { 

import flash.display.MovieClip; 
import flash.events.Event; 
import flash.display.Stage; 


public class Particle extends MovieClip { 

    private var speedX:int; 
    private var speedY:int; 
    private var deleted:Boolean = false; 

    public function Particle() { 
     this.graphics.beginFill(0x00CCFF); 
     this.graphics.drawCircle(0,0,Math.random() * 30); 

     //The max prevents particle speed from rounding to zero. 
     speedX = Math.ceil(Math.random() * 10 - 5); 
     speedY = Math.ceil(Math.random() * 10 - 5); 
    }  

    public function render():void{ 
     //It originally appeared to be slowing down. In-fact, it was. 
     x += Math.random() * speedX; 
     y += Math.random() * speedY; 

     deleted = (x > FluidLayer.w || y > FluidLayer.h); 
     //Comment this below if you want particles to be removed once they go out of bounds. 
     if(deleted) { 
      x = Math.random() * FluidLayer.w; 
      y = Math.random() * FluidLayer.h; 
      deleted = false; 
     } 
    } 

    public function isDeleted():Boolean { 
     return deleted; 
    } 
} 
} 

FluidLayer.as

package { 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
import flash.display.BitmapData; 
import flash.filters.BlurFilter; 
import flash.display.Bitmap; 
import flash.geom.Point; 
import flash.geom.ColorTransform; 
import flash.display.IBitmapDrawable; 
import flash.events.Event; 
import flash.display.MovieClip; 


public class FluidLayer extends MovieClip { 

    private var canvas:Sprite; 

    private var bitmap:Bitmap; 
    private var bitmapData:BitmapData; 

    private var particleArray:Array = new Array(); 

    public static const w:uint = 550; 
    public static const h:uint = 400; 


    public function FluidLayer() { 
     addEventListener(Event.ADDED_TO_STAGE, initialize); 
    } 

    //By only one event handler to render, we prevent the overhead of 599 bubbling events. 
    private function render(e:Event):void { 
     for each(var p:Particle in particleArray) { 
      p.render(); 
      //uncomment below if you want particles to become removed when they navigate out of bounds. 
      //if(p.isDeleted()) { 
       //canvas.removeChild(p); 
       //particleArray.splice(particleArray.indexOf(p),1); 
      //} 
     } 
     bitmapData.fillRect(bitmapData.rect, 0); //clear the bitmapdata 
     bitmapData.draw(canvas,null,null,null,null,true); 
     bitmapData.threshold(bitmapData, bitmapData.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false); 
    } 


    //We call initialize once the fluid layer has been added to stage 
    //or else stage values will be null. 
    private function initialize(e:Event):void { 
     canvas = new Sprite(); 


     //You DEFINITELY want to lower the blur amount here. 
     //This is what is ultimately slowing your SWF down to a crawl. 
     //canvas.filters = new Array(new BlurFilter(20,20,1)); 

     for(var i:uint = 0; i < 600; i++) { 
      var p:Particle = new Particle(); 
      p.x = Math.random() * w; 
      p.y = Math.random() * h; 
      canvas.addChild(p); 
      particleArray.push(p); 
     } 

     //The bitmap and bitmapData only need to be initialized once 
     bitmapData = new BitmapData(w, h, true); 

     bitmap = new Bitmap(bitmapData, "auto", true); 
     bitmap.alpha = 0.7; 
     addChild(bitmap); 

     addEventListener(Event.ENTER_FRAME, render); 
    } 


} 
} 
+0

Tha nks Андреас, действительно хороший момент. Он действительно не решает мою проблему, все еще замедляя работу. –

+0

@ MichellMorsø См. Мой отредактированный ответ. – Andreas

+0

Большое спасибо за то, что нашли время, чтобы сделать это Андреас! Определенно некоторые интересные идеи о структуре кода. Я понял решение, почему оно замедляется, и это было размыто. см. мой ответ. –

0

оригинальный спад, как представляется, фильтр размытия на холсте. (Прокомментировать фильтр, чтобы увидеть доказательство)

Автоматическое создание растровых изображений с помощью флэш-памяти (CacheAsBitmap & Буфер битмарта) для рендеринга фильтра, вероятно, вызывает утечку памяти, и это может быть связано с постоянно изменяющимся размером холста, к движению частиц.

Попробуйте добавить эту строку после создания холста для быстрого исправления:

canvas.scrollRect = new Rectangle(0,0,stage.stageWidth,stage.stageHeight); 

Ограничивая размер холста с scrollRect мы остановив перераспределению.

Однако жидкость больше не идет к краям сцены. Это можно было бы обработать в подпрограммах распределения ничьей и растровым изображением, увеличивая размеры и компенсировать, я позволю вам пойти на это, но его частично связать с суммой фильтра размытия.

Я бы предложил адаптировать эти идеи с очень хорошими идеями в коде Андреаса.

+0

Спасибо Адаму! это очень помогло исполнению! см. мой ответ. :) –

+0

не беспокоится, отличный эффект BTW – adamh

+1

спасибо :) Im планируя преобразование этого эффекта в html5 –

Смежные вопросы