深入理解flash重繪

Flash Player 會以SWF內容的幀頻速度來刷新需要變化的內容,而這個刷新的過程,我們通常稱爲“重繪(redraw)”,相信即便是初級的菜鳥也知道,只要使用的是Debug版本的Flash Player, 右鍵菜單裏就會有“Show Redraw Regions (顯示重繪區域)” 這個選項,當此選項打開的時候,我們就能清楚地看到此刻場景內被重繪的區域。

那麼什麼情況下會發生重繪呢??
1、最常見的是情況就是舞臺上的可視組件在形狀、位置、狀態(alpha, scale...)發生改變的時候會觸發Flash Player 的重繪。
2、當一個DisplayObject的層級(ChildIndex)發生改變的時候也會導致重繪。
3、當你將一個Sprite / MovieClip 的buttonMode 設置爲 true 的時候,即便是單幀動畫,重繪會在MouseEvent.MOUSE_DOWN的時候觸發。又或者你對DisplayObject設置層級的時候,即便DisplayObject的層級沒有發生改變,也會使得 Flash Player對此顯示對象進行重繪。
既然重繪是爲了能夠將顯示內容進行更新,那麼一個Flash應用程序就不可避免的要觸發重繪。而重繪卻是性能消耗的主要根源,一個有經驗的Flash開發人員寫出的Flash應用,其性能可能70% - 90%(甚至更高)是消耗在重繪上,那麼提高Flash應用程序的運行效率和減少重繪有着莫大的關係。
要減少重繪,首先我們需要對單位每幀重繪大小這個概念進行量化:重繪的大小應該取決於數量和麪積。數量取決(但不是完全取決)於可視範圍內的需要更新的顯示對象的數量,假設場景上有兩個閃爍的小圓點並且寬和高都爲20,那麼重繪的數量爲3,而重繪的總面積就爲: 20 * 20 * 3 = 1200 (平方像素)。
?
簡單的看看上面的公式是不是覺得重繪面積的計算很容易呢?那麼繼續估計下下面這個情況的重繪面積是多少:


如果你計算的結果是: 20 * 20 * 6 = 2400 (平方像素),那麼恭喜你,答錯了...
根據上面的介紹,重繪的大小理應就是重繪的數量 * 單個區域的面積,可是爲什麼說這個情況就錯呢?讓我們看看問題究竟出在什麼地方:


讓人覺得奇怪的地方出現了,重繪區域的數量依舊是3,而面積卻增大了不少,按照圖上給出的座標信息,我們不難算出,總重繪面積的大小爲:
20 * (70 - 20 + 20) * 3 = 4200 (平方像素),比起預先估算的 2400 (平方像素)整整大了 75%!
或許從這個地方開始,大家就開始覺得困惑了。的確,Flash Player的重繪面積並沒有按照我們之前的設想那樣來計算,但是依舊能找到一些規律,仔細來看以下幾種況:


如果你夠細心,應該不難看出每次 Flash Player 重繪的區域不會超過3個,即便舞臺上有多於三個的顯示對象需要被重繪,Flash Player 會將其中的兩個或者多個集合(根據位置來判斷)在一起,然後重繪在一個大區域裏面,至此,我們暫時可以將上面兩個重繪法則命名爲三區域法則和就近合併法則,通過總結出來的這兩個法則,我們就能更加容易地理解Flash Player 重繪的機制,以及解釋在日常調試中遇到的一些重繪現象了。比如QQ牧場裏幾個靠得比較近得小動物被放在一個區域裏面重繪,而有些動物則不然,被單獨重繪。
當我們瞭解了重繪機制後,那麼接下來就應該進一步去了解如何避免多餘的重繪,下面列舉的方法可能大部分都是被大家所熟悉的。
1、當一個帶有動畫效果的DisplayObject在不顯示的時候,不僅僅是將其 visible 屬性設置爲 false, 因爲重繪依舊會進行,這裏你可以選擇暫停掉動畫,又或者利用removeChild(displayObject) 直接將此對象移除出顯示列表。
2、不出現在可視範圍內外觀變化的顯示對象其實是不會發生重繪的,這點相信是Flash本身做了優化,也就是說我的Stage.stageWidth 和 Stage.stageHeight 都爲200的情況下,一個處在舞臺上的變化的顯示物體,座標爲(200, 200) 寬高都爲10,此時Flash Player重繪內容並不會包括此對象,新版本的Flash Player 甚至在瀏覽器窗口最小化的時候會關閉掉所有的重繪,這個時候你往往會發現CPU佔用率驟降,但是應用程序依舊在運行。
3、在設置DisplayObject的層級的時候請先做一個判斷:

if (myContainer.getChildIndex(myChild) != 0){      
 myContainer.setChildIndex(myChild, 0);
}

運氣好的話,這個判斷最高能帶來200%以上的效率提升。
4、當你的Sprite / MovieClip 設置 cacheAsBitmap = true 這個屬性的時候,當此顯示對象內很小的一個區域(甚至是被遮蓋着的物體)發生變化,會導致整個Sprite / MovieClip重繪。
5、儘量確保活動的顯示內容在非可見區域被暫停活動或者乾脆直接移除出顯示列表,這裏提到的不可視區域不僅僅是舞臺外不可見的,還包括舞臺內被其他物體遮蓋住的顯示對象。

正如之前提到的,重繪是Flash Player性能消耗的主要大戶,所以去優化減小重繪區域面積,減少不必要的重繪操作次數,往往能夠帶來比較大的性能優化回報。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章