創意絕對.絕對搖滾. 校園創作競賽



在這次的專案,有三個技術點想跟大家分享(如果有更好的方法,歡迎指教討論喔),
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,場景上的影片他自己會開始跑,但是還是會頓,打開工作管理員,效能也沒有差,請問是我使用方法錯誤嗎?