創意絕對.絕對搖滾. 校園創作競賽
在這次的專案,有三個技術點想跟大家分享(如果有更好的方法,歡迎指教討論喔),
1. 自製網頁的ScrollBar
要寫一個ScrollBar不會很難, 但要配合隨視窗縮放的ScrollBar就不是那麼簡單。
在這兒我使用的是bit-101大叔的 minimalcomps 組件裡的VSlider。
該組件的特色,就是有個setSize的函式, 能讓你動態更改組件大小且不會變型。
基本用法如下:
完成(誤)
設計師當然不會用這樣的樣計樣式, 好在該特組件在建立元件時, 會執行addChildren函式
我們只要去override後,加入自己的元件,然後把對映的變數重新指過去就可以了
先在flash做好ScrollBar元件,並取好名稱
在這我不使用flash直接compile,因為太慢, 而是使用Embed把該swf裡的元件重新加進來。
再使用FlexSDK來做compile的動作。
自製ScrollBar的程式碼
在這個案子裡,主視覺有二種模式, 一般模式(要完全罝中)
資訊打開模式(配合第一點的ScrollBar數值來作定位)
我想第一般模式很簡單, 直接對stage做Resize偵聽, 然後就完全置中
而第打開模式,其實也不難,反正ScrollBar裡的value預設就是0到100。
當ScollBar value 在0時, 主視覺物件的y軸也在0,
當ScrollBar value 在100時,主視覺物件的y軸就等於 (主視覺物件的高度-場景高*負1)
(keyVisual.height-stage.stageHeight*-1)
好了,公式出來了,剩下的應該不難。
先直接看效能未優化版(僅供demo用, 活動資訊請以正式網址為主)
你可以看到整個網站在進場播放動畫時,是非常lag, 且整個網站的fps非常的低。
二者有非常明顯的差別(如果你的電腦配備超好的話,應該看不出來)
二個版本用的fla檔都是同一個。
先了解一下flash吃效能的幾個點。
flv:影片播放是很吃效能的,不管是外載還是匯入到flash裡,都非常吃效能,特別在大畫面時更明顯。
決解方法:用檔案k數來換, 把影片轉成序列圖檔
序列圖檔:能用jpg當然是最好的,但要有透明度的話,就一定要用PNG
在使用PNG時要特別注意, 假設你的圖片是600x400, 但真正有圖型的大小可能只有300x200, 其他的部份都是透明色塊, 請記得。打散他, 然後把用不到的透明色塊給delete掉, 這樣可以省下很多不必要的運算(經人體實驗是有效的)。
大畫面物件+多物件移動+序列圖檔:
就像這次的案子遇到的問題一樣,設計師做好美美的動畫,做完發現跑起來很lag,本來是想減少動畫量,但就少了一種感覺, 而我使用的方法就是 BitmapData
嘿嘿,想到了嗎
使用 BitmapData 類別,把該動畫所有的影格,事前畫成BitmapData, 在存在Array裡
當要播放動畫時,就去指定的Array裡把BitmapData拿出來。
這樣不管畫面上有多少物件,都視同只有一個BitmapData, 等到動畫播完時,在把Array裡的BitmapData Dispose掉,這樣動畫也順了,效能也有了。
但使用時還是需要注意幾個點:
一開始要把一個MovieClip裡的全部影格畫成BitmapData, 表示一瞬間會消耗大量的CPU,此時使用者的電腦可能會停頓一下,那可不可以改成邊播MovieClip邊畫呢,答案是這樣做的效能沒什麼差
所以我的作法是把整段動畫分階段去畫,一開始可能先畫20個影格,當動畫播到20個影格時,再去畫另外的20個影格
等到動畫全部播完後,再整個Dispose掉。
在這次的專案,有三個技術點想跟大家分享(如果有更好的方法,歡迎指教討論喔),
1. 自製網頁的ScrollBar
要寫一個ScrollBar不會很難, 但要配合隨視窗縮放的ScrollBar就不是那麼簡單。
在這兒我使用的是bit-101大叔的 minimalcomps 組件裡的VSlider。
該組件的特色,就是有個setSize的函式, 能讓你動態更改組件大小且不會變型。
基本用法如下:
new VSlider(要加入到那個容器裡, x座標, y座標, change偵聽函式);決解ScrollBar的程式,再補上偵聽stage的Resize事件, 和偵聽stage的MouseWheel事件
完成(誤)
設計師當然不會用這樣的樣計樣式, 好在該特組件在建立元件時, 會執行addChildren函式
我們只要去override後,加入自己的元件,然後把對映的變數重新指過去就可以了
先在flash做好ScrollBar元件,並取好名稱
在這我不使用flash直接compile,因為太慢, 而是使用Embed把該swf裡的元件重新加進來。
再使用FlexSDK來做compile的動作。
自製ScrollBar的程式碼
/** * @author milkmidi * @see http://milkmidi.blogspot * @version 1.0.1 * @date created 2010/03/24/ */ package milkmidi.tutorials.absolut.cast { import com.bit101.components.VSlider; import flash.display.*; import flash.events.*; [Embed(source='../../../../../assets/Assets.swf',symbol="Scroll_mc")] public class SliderMC extends VSlider{ public var thumb_mc :MovieClip; public var track_mc :MovieClip; private var _addWheelListener:Boolean = false; public function SliderMC(pParent:DisplayObjectContainer = null, pX:int = 0 , pY:int = 0, pChangeHandler:Function = null) { super(pParent, pX, pY, pChangeHandler); } override protected function addChildren():void { _handle = thumb_mc; _handle.buttonMode = true; _handle.addEventListener(MouseEvent.MOUSE_DOWN, onDrag); } private function _mouseWheelHandler(e:MouseEvent):void { if(e.delta>0) value += 15; else value -= 15; onSlide(e); } override public function get value():Number { return super.value; } override public function set value(value:Number):void { super.value = value; onSlide(null); } public function get addWheelListener():Boolean { return _addWheelListener; } public function set addWheelListener(value:Boolean):void { _addWheelListener = value; if (_addWheelListener) stage.addEventListener(MouseEvent.MOUSE_WHEEL , _mouseWheelHandler); else stage.removeEventListener(MouseEvent.MOUSE_WHEEL , _mouseWheelHandler); } override protected function drawBack():void { track_mc.height = height; } override protected function drawHandle():void { positionHandle(); } } }主程式測試碼
/** * @author milkmidi * @see http://milkmidi.blogspot * @version 1.0.1 * @date created 2010/04/07/ */ package { import com.bit101.components.HBox; import com.bit101.components.HSlider; import com.bit101.components.VSlider; import flash.display.*; import flash.events.Event; import milkmidi.tutorials.absolut.cast.SliderMC; public class A01SliderMCDemo extends Sprite { private var _scroll:SliderMC; public function A01SliderMCDemo() { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE , init); } private function init(e:Event=null):void { removeEventListener(Event.ADDED_TO_STAGE, init); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener(Event.RESIZE , _resizeHandler); _scroll = new SliderMC(this, 0, 0, _slidrChangeHandler); _scroll.addWheelListener = true; _scroll.setSliderParams(0, 100, 50); _resizeHandler(null); //以下是測試用的 new VSlider(this, 0, 0, _slidrChangeHandler); } private function _resizeHandler(e:Event):void { _scroll.x = stage.stageWidth - 40; _scroll.setSize(200, stage.stageHeight); } private function _slidrChangeHandler(e:Event):void{ trace(e.currentTarget.value) } } }2. 主視覺要隨視窗大小作定位
在這個案子裡,主視覺有二種模式, 一般模式(要完全罝中)
資訊打開模式(配合第一點的ScrollBar數值來作定位)
我想第一般模式很簡單, 直接對stage做Resize偵聽, 然後就完全置中
而第打開模式,其實也不難,反正ScrollBar裡的value預設就是0到100。
當ScollBar value 在0時, 主視覺物件的y軸也在0,
當ScrollBar value 在100時,主視覺物件的y軸就等於 (主視覺物件的高度-場景高*負1)
(keyVisual.height-stage.stageHeight*-1)
好了,公式出來了,剩下的應該不難。
package { public class A02KeyVisualDemo extends A01SliderMCDemo{ private var _keyVisual:KeyVisual_mc = new KeyVisual_mc(); public function A02KeyVisualDemo() { addChild(_keyVisual); } override protected function _onScrollChange(pValue:int):void { pValue = 100 - pValue; //因為VSlider拉到底是0, 跟我們需要的值是相反的, 所以要倒過來 var _rang:int = (_keyVisual.height - stage.stageHeight) * -1; _keyVisual.y = _rang * pValue / 100; } } }3. 效能問題
先直接看效能未優化版(僅供demo用, 活動資訊請以正式網址為主)
你可以看到整個網站在進場播放動畫時,是非常lag, 且整個網站的fps非常的低。
二者有非常明顯的差別(如果你的電腦配備超好的話,應該看不出來)
二個版本用的fla檔都是同一個。
先了解一下flash吃效能的幾個點。
flv:影片播放是很吃效能的,不管是外載還是匯入到flash裡,都非常吃效能,特別在大畫面時更明顯。
決解方法:用檔案k數來換, 把影片轉成序列圖檔
序列圖檔:能用jpg當然是最好的,但要有透明度的話,就一定要用PNG
在使用PNG時要特別注意, 假設你的圖片是600x400, 但真正有圖型的大小可能只有300x200, 其他的部份都是透明色塊, 請記得。打散他, 然後把用不到的透明色塊給delete掉, 這樣可以省下很多不必要的運算(經人體實驗是有效的)。
大畫面物件+多物件移動+序列圖檔:
就像這次的案子遇到的問題一樣,設計師做好美美的動畫,做完發現跑起來很lag,本來是想減少動畫量,但就少了一種感覺, 而我使用的方法就是 BitmapData
嘿嘿,想到了嗎
使用 BitmapData 類別,把該動畫所有的影格,事前畫成BitmapData, 在存在Array裡
當要播放動畫時,就去指定的Array裡把BitmapData拿出來。
這樣不管畫面上有多少物件,都視同只有一個BitmapData, 等到動畫播完時,在把Array裡的BitmapData Dispose掉,這樣動畫也順了,效能也有了。
但使用時還是需要注意幾個點:
一開始要把一個MovieClip裡的全部影格畫成BitmapData, 表示一瞬間會消耗大量的CPU,此時使用者的電腦可能會停頓一下,那可不可以改成邊播MovieClip邊畫呢,答案是這樣做的效能沒什麼差
所以我的作法是把整段動畫分階段去畫,一開始可能先畫20個影格,當動畫播到20個影格時,再去畫另外的20個影格
等到動畫全部播完後,再整個Dispose掉。
package milkmidi.display { import flash.display.*; import flash.events.Event; import flash.geom.Matrix; import flash.net.URLRequest; import flash.utils.clearInterval; import flash.utils.clearTimeout; import flash.utils.setTimeout; public class BitmapDataSequence extends Sprite { public static const END_FRAME:String = "endFrame"; private var _target :MovieClip; private var _targetWidth :int; private var _targetHeight :int; private var _fps :uint; private var _totalFrames :uint; private var _bitmap :Bitmap = new Bitmap(); private var _bmdArray :Array = []; private var _frame :int = 1; private var _inter :int; private var _drawMatrix :Matrix; private var _sequenceTime :Number; public function BitmapDataSequence(pTargetMC:MovieClip, pWidth:Number = 320, pHeight:Number = 240, pFps:Number = 30):void { _fps = pFps; _targetWidth = pWidth; _targetHeight = pHeight; _target = pTargetMC; _totalFrames = _target.totalFrames; addChild(_bitmap); } public function startSequence(pTime:Number = 0 ):void { _sequenceTime = pTime; convert(); } public function prevFrame():void { _frame--; _frame = _frame < 1 ? 1 :_frame; showFrameBitmapData(_frame); } public function nextFrame():void { _frame++; _frame = _frame > _totalFrames ? _totalFrames : _frame; showFrameBitmapData(_frame); } public function play():void { showFrameBitmapData(_frame); if (_frame == _totalFrames) { dispatchEvent(new Event(END_FRAME)); } _frame %= _totalFrames; _frame++; _inter = setTimeout(play, 1000 / _fps); } public function stop():void { clearTimeout(_inter); } public function gotoAndStop(pFrame:uint):void { stop(); _frame = pFrame; showFrameBitmapData(_frame); } public function gotoAndPlay(pFrame:uint):void { stop(); _frame = pFrame; play(); } private function convert():void { _target.gotoAndStop(_frame); var _mtr:Matrix = new Matrix(); var _bmp:BitmapData = new BitmapData(_targetWidth, _targetHeight, true, 0x00000000); _bmp.draw(_target, _drawMatrix); _bmdArray.push(_bmp); _frame++; //trace(_frame, _bmdArray.length); if (_frame > _totalFrames) { stop(); _frame = 1; showFrameBitmapData(1); dispatchEvent(new Event(Event.COMPLETE)); return; } if (_sequenceTime == 0) convert(); else setTimeout( convert, _sequenceTime * 1000); } private function showFrameBitmapData(pFrame:uint):void { _bitmap.bitmapData = _bmdArray[pFrame - 1]; } public function get totalFrames():uint { return _totalFrames; } public function get currentFrame():uint { return _frame; } public function get drawMatrix():Matrix { return _drawMatrix; } public function set drawMatrix(value:Matrix):void { _drawMatrix = value; } public function destroy():void { clearInterval(_inter); for each (var _bmp:BitmapData in _bmdArray) { _bmp.dispose(); } } } }SourceCodeDownload
留言
請問老師這個是怎麼做的阿?
?是這樣嗎?
這樣畫面就被清掉了
如果要不斷播放
就不dispose嗎
還是不斷play() > dispose();
那個效能較好
不好意思,我很想學奶綠老師分享的這支程式,所以想問清楚~
如果A02KeyVisualDemo是視覺顯示區那個元件的class,那不用embed該元件嗎?!
而那個主要的視覺元件,我是使用swc
你可以看到Assets.swf是有被加入到FlashDevelop專案裡,且是藍色的
所以我在上方new的KeyVisual_mc就是swc裡的元件
是日本AS大師roxik自已原創的3D Engine
我只知道大概的方法,但沒辦法做到像他這麼順。
dispatchEvent(new Event('END_FRAME'));
這指的是什麼呢??
動畫全部播就就dispose, 是因為動畫就只播過一次就不要,所以最後才把他整個dispose掉
那換句話說 我可以直接讓視覺元件直接去link A02KeyVisualDemo 嗎?!
不好意思..麻煩您了 我是不太懂swc和embed的方式。
swc:是可以包含設覺元件和程式碼的元件
可以把一堆as檔,包裝成一個swc,
你可以想成是把他zip起來。
怎麼產生swc呢, 只要在發佈面版裡, 將swc選項打勾, 發佈後, 就會幫你產生swc檔, 要注意喔, 只有元件庫裡有勾選成類別的才會匯出在swc裡。
怎麼用呢:FlashCS4,Flex,FlashDevelop都可以直接使用swc元件,只有FlashCS3不能。
在我的A02KeyVisualDemo這隻,我有去new一個KeyVisual_mc類別, 這個類別就是憂在Assets.fla裡製作的。
而Embed是將外部的元素匯入到swf檔,有點像是將檔案匯到flash的元件庫裡。
Embed是由Flex來的, 因為Flex沒有元件庫的概念, 所以才有這個語法可以使用
但要注意一下,使用Embed swf檔時,該swf裡的程式碼都會消失喔。
希望這樣對你有幫助
我有寫出來了~ 大開心!
會一開始就把全有的影格的BitmapData劃完
如果影格數很長, 此時會非常吃效能,然後整個停住
加這個變數是用來告訴flash幾毫秒要劃一張。
var seq_bg:BitmapDataSequence=new BitmapDataSequence(designers_bg)
seq_bg.startSequence()
然後我原本設定STOP,場景上的影片他自己會開始跑,但是還是會頓,打開工作管理員,效能也沒有差,請問是我使用方法錯誤嗎?