2006年11月30日 星期四

又一新的表現端技術 F3   [+/-]

Ticore's Blog

最近看到新的 RIA 技術 F3
乍看之下有點像 processing

同樣是 Java Base
不過 F3 是一種直譯式的 Java scripting language
對於 Swing、Java 2D 支援度良好
適合用來開發 UI

F3 語法規則
The F3 Programming Language

F3 的作者已經用 F3 作了幾個 Demo
幾乎可以做到等同 Flash 網站的效果
更多的 Demo 請到 F3 觀看

現已更名為 JavaFX
Read more...

2006年11月29日 星期三

利用 Ant 編譯打包 Flash Media Server SSAS 程式   [+/-]

Ticore's Blog

以往 Flash Communication Server 執行的 Server-Side ActionScript
完全是以原始碼來執行
原始碼容易外洩,而且檔案一多,部署也比較麻煩
Flash Media Server 內附一個好用的工具
位於 FMS 安裝目錄下

C:\Program Files\Macromedia\Flash Media Server 2\tools\far.exe

可以將你的 SSAS 程式碼編譯為 bytecode,以及打包壓縮為 *.far
除了保護原始碼、容易部署以外
文件上說還可以加快 application 啟動速度

以下示範利用 Ant 來編譯打包一個 FMS Application

<?xml version="1.0" encoding="UTF-8"?>
<project name="FMS SSAS" default="package">
 
 <property name="src" location="src" />
 <property name="build" location="build" />
 <property name="dist" location="dist" />
 
 <property name="far"
 location="C:\Program Files\Macromedia\Flash Media Server 2\tools\far.exe" />
 
 <fileset id="ascFiles" dir="${build}">
  <include name="**/*.asc" />
 </fileset>

 <target name="init">
  <tstamp />
  <mkdir dir="${build}" />
  <mkdir dir="${dist}" />
 </target>

 <target name="copy" depends="init">
  <copy todir="${build}">
   <fileset dir="${src}/" />
  </copy>
 </target>
 
 <target name="compile" depends="copy">
  <apply executable="${far}" dir="${build}">
   <arg value="-compile" />
   <fileset refid="ascFiles" />
  </apply>
  <delete>
   <fileset dir="${build}" includes="**/*.asc" />
  </delete>
 </target>

 <target name="package" depends="compile">
  <exec executable="${far}" dir="${build}">
   <arg value="-package" />
   <arg value="-archive" />
   <arg value="${dist}\main.far" />
   <arg value="-files" />
   <arg value="*.ase" />
   <arg value="components\*.ase" />
  </exec>
 </target>

</project>

相關資料:

FMS LiveDocs - Archiving and compiling server-side script files

Apache Ant

Read more...

2006年11月28日 星期二

ActionScript 3.0 - Scene、FrameLabel   [+/-]

Ticore's Blog

Flash 8 (含)以前 的場景 (Scene) 全部都是模擬出來的

純粹只是為了開發上方便
不用一次處理超長時間軸

實際輸出的 SWF 資料內是完全沒有任何關於場景的資料!

舉例來說,像是 gotoAndStop("Scene 2", 3); 函式呼叫
編譯之後都會被轉成類似 gotoAndStop(6); 這樣的格式

想要在 Flash 8 以前作判斷目前場景的功能
需要自己另外用陣列或是物件去儲存場景資料
相當麻煩

至於影格標籤 (Frame Label) 雖然在執行期可以使用,但是支援度很差
無法列舉標籤,也無法直接取得目前影格上的標籤

不過 Flash 9 & ActionScript 3 已經加強對 Scene & FrameLabel 的處理能力
可以直接做到上述的功能

以下是測試程式

先照圖所示用 Flash 9 IDE 建立場景與影格標籤:

在影格一輸入測試程式:

// 列舉所有 Scene、Frame Label
for each(var scene:Scene in this.scenes) {
 trace(scene.name + ", numFrames = " + scene.numFrames );
 for each(var label:FrameLabel in scene.labels) {
  trace("t" + label.name + ", frame = " + label.frame);
 }
}

// 偵測目前播放位置的 Scene、Frame Label、Frame Number
this.addEventListener(Event.ENTER_FRAME,
 function(event:Event):void{
  var mc:MovieClip = event.target;
  trace("Current Frame : " + mc.currentFrame,
  ", Current Label : " + mc.currentLabel,
  ", Current Scene : " + mc.currentScene.name);
 }
);

輸出範例:

Scene 1, numFrames = 19
 label 1, frame = 4
 label 2, frame = 10
 label 3, frame = 16
Scene 2, numFrames = 17
 label 4, frame = 1
 label 5, frame = 6
 label 6, frame = 11

Current Frame : 2 , Current Label : null , Current Scene : Scene 1
Current Frame : 3 , Current Label : null , Current Scene : Scene 1
Current Frame : 4 , Current Label : label 1 , Current Scene : Scene 1
Current Frame : 5 , Current Label : null , Current Scene : Scene 1
Current Frame : 6 , Current Label : null , Current Scene : Scene 1
Current Frame : 7 , Current Label : null , Current Scene : Scene 1
Current Frame : 8 , Current Label : null , Current Scene : Scene 1
Current Frame : 9 , Current Label : null , Current Scene : Scene 1
Current Frame : 10 , Current Label : label 2 , Current Scene : Scene 1
Current Frame : 11 , Current Label : null , Current Scene : Scene 1
Current Frame : 12 , Current Label : null , Current Scene : Scene 1
Current Frame : 13 , Current Label : null , Current Scene : Scene 1
Current Frame : 14 , Current Label : null , Current Scene : Scene 1
Current Frame : 15 , Current Label : null , Current Scene : Scene 1
Current Frame : 16 , Current Label : label 3 , Current Scene : Scene 1
Current Frame : 17 , Current Label : null , Current Scene : Scene 1
Current Frame : 18 , Current Label : null , Current Scene : Scene 1
Current Frame : 19 , Current Label : null , Current Scene : Scene 1
Current Frame : 1 , Current Label : label 4 , Current Scene : Scene 2
Current Frame : 2 , Current Label : null , Current Scene : Scene 2
Current Frame : 3 , Current Label : null , Current Scene : Scene 2
Current Frame : 4 , Current Label : null , Current Scene : Scene 2
Current Frame : 5 , Current Label : null , Current Scene : Scene 2
Current Frame : 6 , Current Label : label 5 , Current Scene : Scene 2
Current Frame : 7 , Current Label : null , Current Scene : Scene 2
Current Frame : 8 , Current Label : null , Current Scene : Scene 2
Current Frame : 9 , Current Label : null , Current Scene : Scene 2
Current Frame : 10 , Current Label : null , Current Scene : Scene 2
Current Frame : 11 , Current Label : label 6 , Current Scene : Scene 2
Current Frame : 12 , Current Label : null , Current Scene : Scene 2
Current Frame : 13 , Current Label : null , Current Scene : Scene 2
Current Frame : 14 , Current Label : null , Current Scene : Scene 2
Current Frame : 15 , Current Label : null , Current Scene : Scene 2
Current Frame : 16 , Current Label : null , Current Scene : Scene 2
Current Frame : 17 , Current Label : null , Current Scene : Scene 2
Read more...

2006年11月27日 星期一

ActionScript 3.0 - NetStream 未公開的 Codec 函式   [+/-]

Ticore's Blog

AS 3.0 中 flash.net.NetStream 內有三個未公開的函式

分別是

[Inspectable(environment="none")]
public function get videoCodec():uint;

[Inspectable(environment="none")]
public function get audioCodec():uint;

[Inspectable(environment="none")]
public function get decodedFrames():uint;

你也可以自行使用

trace(flash.utils.describeType(flash.net.NetStream));

看到這些函式

顧名思義,應該是取得 Video、Audio Codec 種類,以及已經解壓縮的影格數

以下是測試程式

Flash 9 Frame 1 AS:

import flash.net.*;
import flash.event.*;
import flash.utils.*;

var nc:NetConnection = new NetConnection();

nc.connect(null);
var ns:NetStream = new NetStream(nc);
ns.client = {};
ns.client.onMetaData = function(infoObj:Object):void{
 for(var i:String in infoObj) {
  trace("infoObj['" + i + "'] : " + infoObj[i]);
 }
};
ns.client.onCuePoint = function(info:Object):void{};

ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR,
 function(event:Event) {
  trace("event : " + event);
  event.target.close();
 }
);

ns.play("flashVideo.flv");

var video:Video = new Video();
video.attachNetStream(ns);
this.addChild(video);

var timer:Timer = new Timer(500, 10);
timer.addEventListener(TimerEvent.TIMER,
 function(event:Event):void{
  trace("videoCodec : " + ns.videoCodec, ", audioCodec : " + 
   ns.audioCodec, ", decodedFrames : " + ns.decodedFrames);
 }
);
timer.start();

輸出範例:

infoObj['audiocodecid'] : 2
infoObj['videocodecid'] : 4
infoObj['canSeekToEnd'] : true
infoObj['width'] : 413
infoObj['audiodelay'] : 0.038
infoObj['duration'] : 60.326
infoObj['framerate'] : 29.969985961914063
infoObj['height'] : 162
infoObj['videodatarate'] : 450
infoObj['audiodatarate'] : 96

videoCodec : 4 , audioCodec : 2 , decodedFrames : 11
videoCodec : 4 , audioCodec : 2 , decodedFrames : 26
videoCodec : 4 , audioCodec : 2 , decodedFrames : 41
videoCodec : 4 , audioCodec : 2 , decodedFrames : 56
videoCodec : 4 , audioCodec : 2 , decodedFrames : 71
videoCodec : 4 , audioCodec : 2 , decodedFrames : 86
videoCodec : 4 , audioCodec : 2 , decodedFrames : 101
videoCodec : 4 , audioCodec : 2 , decodedFrames : 116
videoCodec : 4 , audioCodec : 2 , decodedFrames : 132
videoCodec : 4 , audioCodec : 2 , decodedFrames : 147

分別用來播放 On2 VP6、Sorenson Spark Codec Flash Video

可以發現

videoCodec = 0:No Video Codec
videoCodec = 2:Sorenson Spark Codec
videoCodec = 4:On2 VP6 Codec

至於 audioCodec 只有出現 0、2,2 應該就是 mp3 了

相同的功能也可以從 onMetaData 事件 info 物件中取得

infoObj['audiocodecid'] : 2
infoObj['videocodecid'] : 4

未來也許可能會支援其它的 Codec 也說不定

相關連結:
Flash Player 9 Update 支援 H.264
Flash Player MovieStar 與 NetStream.VideoCodec 代碼

Read more...

2006年11月26日 星期日

ActionScript 3.0 - DisplayObjectContainer 相關操作   [+/-]

Ticore's Blog

ActionScript 3.0 的 DisplayObject 泛指所有在畫面上呈現圖像的物件
Shape、MorphShape、Video、Bitmap 等,都是 DisplayObject

而 DisplayObjectContainer 便是可以容納其它 DisplayObject 的容器
MovieClip、Sprite、Stage 等,都是 DisplayObjectContainer

DisplayObject 繼承圖:

DisplayObjectContainer 與 AS 2 的 MovieClip 類似
具有 parent、child 的階層關係,以及疊加的特性
不過關於深度的操作上更加方便

感覺上有點像是在操作一個會自動縮併的陣列
只要移除掉陣列內某一位置的元素
該陣列便會自動縮短

這樣一來,只要在合法的索引範圍內取用 child
永遠不會取到 null
也不用像 AS 2 的列舉方式,還要自己判定物件型別

※列舉 DisplayObjectContainer 內的 DisplayObject

var container:DisplayObjectContainer = this;
for(var i:Number = 0 ; i < container.numChildren ; ++i) {
 trace(container.getChildAt(i));
}

※交換 DisplayObject 深度

※自 DisplayObjectContainer 內移除 DisplayObject

※將子 DisplayObject 重新加入 DisplayObjectContainer

※將 DisplayObject 插入 DisplayObjectContainer

相關連結:
Flash Player 9 Sprite 交換階層 Bug

Read more...

2006年11月25日 星期六

SWF9 與 SWF8 之間的溝通方式   [+/-]

Ticore's Blog

Flash SWF 9 格式出來之後
由於其內部 AVM 2 執行方式大改
與 AVM 1 差異頗大

以至於使用 SWF 9 Movie 讀取 SWF 8 Movie 之後
無法像以前一樣可以直接用 ActionScript 呼叫

必須要透過 LocalConnection 或是 ExternalInterface 進行溝通
方式如下

LocalConnection:
Adobe Flex TechNote - Using Flash 8 SWFs with Flex 2 Applications
Peter Ent - Using ActionScript 2 SWFs with Flex 2

ExternalInterface:
trace(this).com - SWF9 to SWF8 Communication - EI not LC - Part 1
trace(this).com - SWF9 to SWF8 Communication - EI not LC - Part 2

兩種方式各有優缺點
LocalConnection 是非同步呼叫,沒有辦法很即時反應結果
但是它可以在非瀏覽器的模式下執行

ExternalInterface 可以做到同步呼叫,但是不能在獨立播放器下執行


其實用 Local SharedObject 也是可以做到 SWF 9、SWF 8 資料傳遞
不過可能要用 Pulling 的方式執行~~~


相關連結
ActionScript 3.0 未公開的函式 AVM1Movie.call、addCallback

2007/06/17 更新
Jesse Warden 提出利用 _global 共通的特性
用一個個 SWF8 版本的 Proxy.swf 集中控制
Jesse Warden dot Kizz-om - Controlling Flash Player 8 SWFs in Flash Player 9 SWFs
Jesse Warden dot Kizz-om - Flex Controlling Flash

Read more...

2006年11月23日 星期四

ActionScript 3.0 未公開的函式 AVM1Movie.call、addCallback   [+/-]

Ticore's Blog

在 flash.display.AVM1Movie 下面還有兩個沒有文件的函式

可以用 trace(describeType(flash.display.AVM1Movie)); 看到

// method declared by : flash.display::AVM1Movie
public function call(String):*; public
function addCallback(String, Function):void;

很像是用來做 SWF9 與 SWF8 Movie 溝通用途

可是實際去測試卻會出現 Error

Error: Error #2014: 此時功能無法使用。
at Error$/throwError()
at flash.display::AVM1Movie/call()
at Timeline0_4798d4e77790a84ca4c6bae94891cad/::frame9()

不知道是少做了什麼步驟還是現在的 Player 根本不支援

很多人應該都為了 SWF9、SWF8 溝通很頭痛
雖然有 LocalConnection、ExternalInterface 可以用
但是非常麻煩

假如這 AVM1Movie.call、addCallback 可以用就很方便了
Read more...

2006年11月22日 星期三

ActionScript 3.0 未公開的函式 MovieClip.addFrameScript   [+/-]

Ticore's Blog

AS 3.0 還有許多未公開的函式
以下是關於 MovieClip 的新功能

MovieClip.addFrameScript(frame:uint,notify:Function)

FlashGuru Consulting - Undocumented Actionscript 3

可以對指定的影格加上事件

與 EventDispatcher 不太一樣的是
它只能容納一個 listener
後加入的會把之前的取代

function output():void {
 trace(this + " : " + this.currentFrame);
}
var i:Boolean = true;

addFrameScript(10, output);
// 影格要拉到 11 格以上

FlashGuru 指出停止事件的方式為

addFrameScript(10, output, false, false);

可是我測試都是失敗

發現以下的方式可以成功移除事件

addFrameScript(10, null);

 

2006/11/23 補充
senocular 在該文回應
其實 addFrameScript 是接受不定長度的 影格數目與 function 組合

e.g.

function output():void {
  trace(this + " : " + this.currentFrame);
}
addFrameScript(0, output, 1, output, 2, output);

這樣就可以一次設定多個影格事件

Read more...

Flash Player 9 AS 2.0 LocalConnection GC Bug   [+/-]

Ticore's Blog

這問題在之前的 ActionScript WeakReference 介紹中曾經有提過

當使用 Flash Player 9 執行 AS 2.0 程式
利用 LocalConnection 物件進行連線
該 LC 物件與其它物件形成隔絕狀態
將會造成 LC 物件無法被回收

FMS SSAS 程式不需要撰寫
只需要命名一個空白文字檔為 main.asc
部署於 nc_gc_app application 下即可

Flash ActionScript 測試程式:

function doTest():Void {
 var nc:NetConnection = new NetConnection();
 nc.connect("rtmp:/nc_gc_app");
 var lc:LocalConnection = new LocalConnection();
 lc.connect("lc" + Math.random());
 lc.nc = nc;
 nc.lc = lc;
 delete lc;
 delete nc;
}
setInterval(doTest, 200);

分別使用 Flash Player 8、9 就會發現
Flash Player 9 累積到 500 條連線都不會回收
Flash Player 8 則是每達到一定量
就會回收一次

以上的 Bug 直到 Flash Player 9.0.124.0 還是存在

Read more...

2006年11月21日 星期二

AS 2.0 關於函式範圍鏈與垃圾回收的問題   [+/-]

Ticore's Blog

測試原理:

利用 NetConnection 與 FMS 連線
透過 FMS Console 觀察 NetConnection 活動數量
藉以測試函式範圍鏈內物件回收的情況

FMS 程式:

FMS SSAS 程式均不需要特別撰寫
只需要命名一個空的文字檔為 main.asc
部署在 nc_gc_app application 內

 

測試一:

var ary:Array = [];
function getFun():Function {
 var nc:NetConnection = new NetConnection();
 nc.connect("rtmp:/nc_gc_app");
 return function ():Void {
 };
}
function doTest():Void {
 ary.push(getFun());
}
setInterval(doTest, 100);

// Ticore's Blog - http://ticore.blogspot.com/

 

測試二:

var ary:Array = [];
function getFun():Function {
 var nc:NetConnection = new NetConnection();
 nc.connect("rtmp:/nc_gc_app");
 return function ():Void {
  nc;
  // 明確引用到範圍鏈內的物件,會造成物件無法回收
 };
}
function doTest():Void {
 ary.push(getFun());
}
setInterval(doTest, 100);

// Ticore's Blog - http://ticore.blogspot.com/

 

測試三:

var ary:Array = [];
function getFun():Function {
 var nc:NetConnection = new NetConnection();
 nc.connect("rtmp:/nc_gc_app");
 return function ():Void {
  eval("");
  // 只要有 eval 出現,Scope Chain 內的物件都會被 hold 住
 };
}
function doTest():Void {
 ary.push(getFun());
}
setInterval(doTest, 100);

// Ticore's Blog - http://ticore.blogspot.com/

 

測試程式大略以 Flash Player 6 ~ 9 測試

在此不直接 PO 出結果了,有興趣的話可以自行測試看看

從結果中可以發現

1.在匿名函式中,明確引用到範圍鏈內的物件時,會造成該物件無法被回收。
(其它在範圍鏈內沒有被明確引用到的物件是可以被回收的)

2.在匿名函式中,使用到 eval 時,即使沒有明確引用到任何範圍鏈內的物件,也會造成範圍鏈內的物件無法被回收

其實 Flash Player 可能並沒有像 Scope Chain and Memory waste in Flash MX 一文中所述,會造成大量記憶體浪費。

也有可能是前 Macromedia 後來改善了~~

要視明確引用的物件數量多寡,以及是否使用到 eval 而定

碰巧該文假定 eval 對 GC 沒有影響,利用 eval 來作測試

 

以上假如有誤,請指正,謝謝~

 

相關參考資料:
Scope Chain and Memory waste in Flash MX
Flash MX 中的範圍鏈 (scope chain)與記憶體浪費
ActionScript Weak Reference 介紹
AS 3.0 利用function scope 暫存變數
AS 2.0 將參數與 function 綁在一起

Read more...

2006年11月20日 星期一

ActionScript 3.0 - 自行定義事件   [+/-]

Ticore's Blog

由於 ActionScript 3.0 語法變得相當嚴謹
事件處理上也是
不像以前 AS 2.0 隨便 new 一個物件都可以當作事件 (Event) 發佈出去
flash.events.Event 本身不是一個 dynamic class

也沒有一般性的資料欄位可供使用
想要在自訂事件裡面傳遞一些額外資料變得比較困難
必須要自行繼承 Event
以下示範如何自訂一個事件

Read more...

AS 2.0 將參數與 function 綁在一起   [+/-]

Ticore's Blog

程式碼:

function doFun(arg:Number):Void {
 trace("doFun : " + arg);
}
function createFun(arg):Function {
 return function () {
  doFun(arg);
 };
}
btn1.onPress = createFun(1);
btn2.onPress = createFun(2);

相關參考資料:
利用function scope 暫存變數
Scope Chain and Memory waste in Flash MX
Flash MX 中的範圍鏈 (scope chain)與記憶體浪費

Read more...

2006年11月16日 星期四

好用的 Flex 2 除錯指令 - flash.debugger.enterDebugger   [+/-]

Ticore's Blog

Flex 2、ActionScript 3.0 出來到現在
其實還有很多功能文件上並沒有列出來
像是 flash.debugger.enterDebugger
這對於 Flex 2 開發人員非常方便

比設立中斷點的方式更具有彈性
可以由程式的直接結果動態決定是否要進入除錯模式

Read more...

第一個 ActionScript 3.0 反編譯工具出來了~   [+/-]

Ticore's Blog

拜 Adobe 捐出 AVM 原始碼給 Mozilla 基金會所賜
已經有人作出簡單的 AS3 反編譯程式
A first decompilor AS3
不過目前並不能完整還原程式碼
只能得到中間語言 (intermediate language)

AS3 Decompiler 下載位置

以下是簡單的輸出結果:

另外 Mozilla Tamarin 下面還有 AS3 的直譯器在開發中
有興趣的人可以下來玩玩看

Read more...

2006年11月9日 星期四

動態讀取外部 PNG 作為 Alpha Mask   [+/-]

Ticore's Blog

看到邦邦的問題,測試出來的結果如下:



SWF URL:
http://riafiles.googlepages.com/gradientMask.swf

PNG URL:
http://riafiles.googlepages.com/gradientMask.png

關鍵應該是在設定 mask.cacheAsBitmap 的時機

ActionScript:

var maskURL:String = maskURL == null ? "gradientMask.png" : maskURL;

import flash.geom.*;

var maskee:MovieClip = this.createEmptyMovieClip("maskee", 100);
var masker:MovieClip = this.createEmptyMovieClip("masker", 200);

with (maskee) {
    colors = [0xFF0000, 0x0000FF];
    fillType = "radial"
    alphas = [100, 100];
    ratios = [0, 0xFF];
    spreadMethod = "reflect";
    interpolationMethod = "linearRGB";
    focalPointRatio = 0.9;
    matrix = new Matrix();
    matrix.createGradientBox(100, 100, Math.PI, 0, 0);
    beginGradientFill(fillType, colors, alphas, ratios, matrix, 
        spreadMethod, interpolationMethod, focalPointRatio);
    moveTo(0, 0);
    lineTo(550, 0);
    lineTo(550, 200);
    lineTo(0, 200);
    lineTo(0, 0);
    endFill();
}


var mcLoader:MovieClipLoader = new MovieClipLoader();
var mcLisObj:Object = {};
mcLisObj.onLoadInit = function(evtObj):Void{
 masker.cacheAsBitmap = true;
 masker.onPress = function():Void{
  startDrag(this);
 };
 masker.onRelease = masker.onReleaseOutside = function():Void{
  stopDrag();
 };
 maskee.cacheAsBitmap = true;
 maskee.setMask(masker);
};
mcLoader.addListener(mcLisObj);
mcLoader.loadClip(maskURL, masker);
// Ticore's Blog - http://ticore.blogspot.com/
Read more...