2007-06-29

Export Motion XML 相關訊息

Flash CS3 Export Motion XML Kevin Hoyt
Motion XML || XML Motion scripts for Flash CS3

Flash CS3 的程式碼提示

Flash CS3 的 Code hint 看起來不會比 Flash 8 好 =.=
另外, 在預設的情況下 stage 裡的 instances 會被自動宣告, 所以不能為了要有 code hint 而再宣告一次。
慶幸的是, CS3 和 8 一樣, 可以用多行註解 /* */ 來避開重複宣告, 又可保有 code hint 的功能。

2007-06-28

免費的 Adobe AIR 電子書

書名: Adobe Integrated Runtime (AIR) for JavaScript Developers Pocket Guide (Amazon)
相關訊息: Adobe AIR Free Book Download
下載位址

取得 FLV 內的 header 資料

依據 osFlash 裡 FLV 檔案資料格式的說明, 利用 Flash 開發「取得 FLV 檔頭資料及串流資料」的 AIR app。
要注意的是 meta 裡包含兩個 AMF packets, 所以需使用 ByteArray.readObject() 兩次。
Flash frame AS3:
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;

var file:File;
var fs:FileStream;
var flvFilter:FileFilter = new FileFilter("Flash Video", "*.flv");
var header_ba:ByteArray;
var stream_ba:ByteArray;

function bClick(e:MouseEvent):void {
var targetName:String = e.target.name;
switch (targetName) {
case "open_btn" :
file = new File();
file.browseForOpen("Open", [flvFilter]);
file.addEventListener(Event.SELECT, readFLVHeader);
break;
case "show_btn" :
readStreamHeader();
break;
case "close_btn" :
fs.close();
break;
}
}
open_btn.addEventListener(MouseEvent.CLICK, bClick);
show_btn.addEventListener(MouseEvent.CLICK, bClick);
close_btn.addEventListener(MouseEvent.CLICK, bClick);


function readFLVHeader(e:Event) {
filename_txt.text = file.nativePath;
fs = new FileStream();
fs.open(file, FileMode.READ);

// read FLV Header
header_ba = new ByteArray();
fs.readBytes(header_ba, 0, 9);
main_txt.text = "Signature: "+ header_ba.readMultiByte(3, "") +"\n";
main_txt.appendText("Version: "+ header_ba.readUnsignedByte()+"\n");
main_txt.appendText("Flags: "+ header_ba.readUnsignedByte()+"\n");
main_txt.appendText("Offset: "+ header_ba.readUnsignedInt()+"\n");
main_txt.appendText("---\n");
}
function readStreamHeader() {
stream_ba = new ByteArray();
fs.readBytes(stream_ba, 0, 15);

main_txt.appendText("PreviousTagSize: "+ stream_ba.readInt()+" ----\n");
var type:uint = stream_ba.readUnsignedByte();
main_txt.appendText("Type: "+ type +"\n");
// 取 3 bytes
var bodyLength:uint = stream_ba.readUnsignedShort()<<8 | stream_ba.readUnsignedByte();
main_txt.appendText("BodyLength: "+ bodyLength +"\n");
var timestamp:uint = stream_ba.readUnsignedShort()<<8 | stream_ba.readUnsignedByte();
main_txt.appendText("Timestamp: "+ timestamp +"\n");
main_txt.appendText("Padding: "+ stream_ba.readUnsignedInt()+"\n");
if (type == 0x12) {
var t_ba:ByteArray = new ByteArray();
fs.readBytes(t_ba, 0, bodyLength);
// 設定 AMF 的格式, 即使是 on2 VP6 應該還是舊的
t_ba.objectEncoding = ObjectEncoding.AMF0;
// 第一個 AMF 物件是事件處理器的資料
var obj:Object = t_ba.readObject();
var str:String = QopDump.go( obj );
main_txt.appendText("***\nEvent handler:"+str+"\n***\n");
obj = t_ba.readObject();
str = QopDump.go( obj );
main_txt.appendText(str+"\n");
} else {
// skip the body
fs.position += bodyLength;
}
main_txt.verticalScrollPosition = main_txt.maxVerticalScrollPosition;
}

FLV 的第一個 stream unit 應該都是 meta。較舊 FLV 的 meta 大多有問題, 沒有提供仔細而實用的資料。

較新格式的 FLV 其 Flags 通常是 13 而不是 5。


原始檔: parseFLV.fla
安裝檔: parseFLV.air

AS3 TextArea 組件的文件說明有誤

屬性沒有: scrollV, scrollH, maxScrollV, maxScrollH.
分別對應的應為:
verticalScrollPosition
horizontalScrollPosition
maxVerticalScrollPosition
maxHorizontalScrollPosition

2007-06-27

Aptana IDE: AJAX 整合開發環境

Aptana IDE 以 Eclipse 為基礎的 AJAX 整合開發環境
可以和 Flex Builder 併在一起使用
另外也支持 Adobe AIR 的開發

利用 NativeDragEvent, 以拖拉放的方式開啟檔案

參考網頁: Simple Drag and Drop AIR
依據上一篇: Adobe AIR Simple Text Editor 再加上拖曳開檔的功能
Flash frame actions:
import flash.events.NativeDragEvent;
import flash.desktop.DragManager;
import flash.desktop.DragActions;
import flash.desktop.TransferableFormats;
import flash.desktop.TransferableData;

this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER,onDragIn);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP,onDrop);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_EXIT,onDragExit);

function onDragIn(event:NativeDragEvent):void {
// acceptDragDrop() 只能在 nativeDragEnter 或 nativeDragOver 事件處理器上使用
DragManager.acceptDragDrop(this);
}

function onDrop(event:NativeDragEvent):void {

// 下行若沒設定, 順序會是 copy, move, link
DragManager.dropAction = DragActions.COPY;
var tfd:TransferableData = event.transferable as TransferableData;
var dropfiles:Array = tfd.dataForFormat(TransferableFormats.FILE_LIST_FORMAT) as Array;
// 只取一個檔案
var sourceFile:File = dropfiles[0];
file = new File();
file.nativePath = sourceFile.nativePath;
filename_txt.text = file.nativePath;

fs = new FileStream();
fs.open(file, FileMode.READ);
var str:String = fs.readMultiByte(fs.bytesAvailable, "utf-8");
main_txt.text = str.replace( new RegExp(File.lineEnding, "g"), "\n");
fs.close();
}
function onDragExit(event:NativeDragEvent):void {
trace("Drag exit event.");
}

原始檔: test_dragAndDrop.fla

2007-06-26

Adobe AIR Simple Text Editor


這個例子主要是用來測試 File.browseForOpen 的功能
缺點還很多, 包含只能讀寫 utf-8 編碼的檔案

Flash frame actions:
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;

var file:File;
var fs:FileStream;
var textFilter:FileFilter = new FileFilter("Text", "*.txt");
file = new File("app-resource:/temp.txt");
filename_txt.text = file.nativePath;

function bClick(e:MouseEvent):void {
var targetName:String = e.target.name;
switch (targetName) {
case "new_btn" :
file = new File("app-resource:/temp.txt");
filename_txt.text = file.nativePath;
main_txt.text = "";
break;
case "load_btn" :
file = new File();
file.browseForOpen("Open", [textFilter]);
file.addEventListener(Event.SELECT, onSelectOpenFile);
break;
case "save_btn" :
fs = new FileStream();
fs.open(file, FileMode.WRITE);
fs.writeMultiByte(main_txt.text, "utf-8");
fs.close();
break;
case "saveas_btn" :
file = new File();
file.browseForSave("Save as");
file.addEventListener(Event.SELECT, onSelectWriteFile);
break;
}
}
new_btn.addEventListener(MouseEvent.CLICK, bClick);
load_btn.addEventListener(MouseEvent.CLICK, bClick);
save_btn.addEventListener(MouseEvent.CLICK, bClick);
saveas_btn.addEventListener(MouseEvent.CLICK, bClick);

function onSelectOpenFile(e:Event) {
filename_txt.text = file.nativePath;
fs = new FileStream();
fs.open(file, FileMode.READ);
var str:String = fs.readMultiByte(fs.bytesAvailable, "utf-8");
// 替換 換行符號
main_txt.text = str.replace( new RegExp(File.lineEnding, "g"), "\n");
fs.close();
file.removeEventListener(Event.SELECT, onSelectOpenFile);
}
function onSelectWriteFile(e:Event) {
filename_txt.text = file.nativePath;
fs = new FileStream();
fs.open(file, FileMode.WRITE);
fs.writeMultiByte(main_txt.text, "utf-8");
fs.close();
file.removeEventListener(Event.SELECT, onSelectWriteFile);
}


原始檔: test_browseForOpen.fla

2007-06-23

AIR local database 測試

Flash frame AS3:
import flash.data.SQLResult;
import flash.filesystem.File;
import flash.data.SQLStatement;
import flash.data.SQLConnection;
import flash.events.SQLEvent;
import flash.events.SQLErrorEvent;
import flash.errors.SQLError;
import fl.data.DataProvider;

var dbFile:File = new File("app-resource:/test01.db");
var dbConn:SQLConnection = new SQLConnection();
var dbStatement:SQLStatement;
var insertCount:uint = 0;
dbConn.addEventListener(SQLEvent.OPEN, onDBOpened);
dbConn.addEventListener(SQLErrorEvent.ERROR, onDBError);
// 若檔案不存在, 會自動建立
dbConn.open(dbFile);

function onDBOpened(e:SQLEvent) {
trace("onDBOpened:", e);
if (e.type == SQLEvent.OPEN) {
dbStatement = new SQLStatement();
dbStatement.sqlConnection = dbConn;
dbStatement.text = "select * from Users";
dbStatement.addEventListener(SQLEvent.RESULT, onSQLResult);
dbStatement.addEventListener(SQLErrorEvent.ERROR, onSQLError);
dbStatement.execute();
}
}

function onDBError(e:SQLErrorEvent) {
trace("onDBError:", e);
}

function onSQLResult(e:SQLEvent) {
trace("onSQLResult:", e);
var d:Array = dbStatement.getResult().data;
QopDump.echo(d);
dataGrid.dataProvider = new DataProvider(d);
dbConn.close();
}

function onSQLError(e:SQLErrorEvent) {
trace("onSQLError:", e);

var err:SQLError = e.error;
trace("Error Code:", err.code);
trace("Operation:", err.operation);
trace("Error Message:", err.message, "\n");
if (err.message.indexOf("no such table") != -1) {
dbStatement = new SQLStatement();
dbStatement.sqlConnection = dbConn;
dbStatement.text = "CREATE TABLE Users "+
"(id INTEGER PRIMARY KEY, username TEXT, password TEXT);";
dbStatement.addEventListener(SQLEvent.RESULT, doInsert);
dbStatement.addEventListener(SQLErrorEvent.ERROR, onSQLError);
dbStatement.execute();
}
}

function doInsert(e:SQLEvent) {
insertCount++;
if(insertCount>3) return;
dbStatement = new SQLStatement();
dbStatement.sqlConnection = dbConn;
var sql:String;
switch (insertCount) {
case 1 :
sql = "INSERT INTO Users VALUES(null,'MyName','MyPassword');";
break;
case 2 :
sql = "INSERT INTO Users VALUES(null,'qop','qop543');";
break;
case 3 :
sql = "INSERT INTO Users VALUES(null,'小黑','出運了');";
break;
}
dbStatement.text = sql;
dbStatement.addEventListener(SQLEvent.RESULT, doInsert);
dbStatement.execute();
}

執行第一次的結果 (由無到有建立DB):

執行第二次的結果 (取得資料秀在 DataGrid 上):

AIR local database

AIR 內含 SQLite SQL database engine
每個資料庫都以一個檔案實體存在
官網: SQLite home page
工具: SQLite Database Browser, SQLite Control Center

2007-06-22

AirWaves: 使用 Adobe AIR 開發的 IM

相關訊息:
AirWaves
AirWaves will use XMPP / Jabber for it’s messaging

AIR 存圖測試

Flash Frame Actions:
import com.adobe.images.JPGEncoder;
import com.adobe.images.PNGEncoder;
import flash.filesystem.*;

jpg_btn.addEventListener(MouseEvent.CLICK, saveImg);
png_btn.addEventListener(MouseEvent.CLICK, saveImg);

function saveImg(e:MouseEvent):void {
var tname = e.target.name;
var file:File = File.applicationResourceDirectory;

var bpd:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
var ba:ByteArray;
bpd.draw(root);

if(tname == "jpg_btn"){
var jpg:JPGEncoder = new JPGEncoder(80);
ba = jpg.encode(bpd);
file = file.resolve("test.jpg");
}else if(tname == "png_btn"){
ba = PNGEncoder.encode(bpd);
file = file.resolve("test.png");
}

var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(ba);
fileStream.close();
}

原始檔: saveImgFile.fla (as3corelib 已經包含在原始檔內)

2007-06-21

as3corelib

as3corelib: ActionScript 3.0 library for several basic utilities.
裡面的工具都很有用, 包含常用的 JPGEncoder, JSON, MD5, PNGEncoder, SHA1.

在 Flash IDE 使用, 大多使用類別原始碼, 也可以使用 SWC. 以下是使用 SWC 的方式
1. 把 corelib.swc 放在 Flash CS3 安裝目錄的 en\Configuration\Components.
2. 開啟 Flash CS3.
3. 在 components 面板裡可以看到「standard components」>「DateFormatter」.
4. 把「DateFormatter」放在文件的元件庫即可.

2007-06-20

標籤雲的作法

中文標籤雲
Label Cloud
phydeaux3 上面有太多恐怖的東西 ...

Adobe AIR Developer Derby

AIR 開發大賽
Adobe AIR Developer Derby

package a flash app as an AIR file (for windows)

請參考 Create AIR Apps in Flash CS3 在 Flash CS3 中安裝 Test in Apollo
下載並解開 package_app_as_an_AIR_file.zip
然後將修改後的檔案蓋過
在 Flash CS3 開啟文件, 再點選「Commands」>「package app as an AIR file」即可
查看一下是否有 .air 生成
當然也可以用手動的方式, 參考 adt 的使用

AIR 存檔測試

Flash Frame Actions:
import flash.filesystem.*;
// var file:File = File.documentsDirectory; // 我的文件
var file:File = File.applicationResourceDirectory; // 應用程式所在的目錄
file = file.resolve("test.txt");
trace(file.nativePath); // 於 DOS 視窗輸出

function doSave(e:MouseEvent):void {
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.UPDATE);
// File.systemCharset 為系統編碼
//fileStream.writeMultiByte(_txt.text, File.systemCharset);
fileStream.writeMultiByte(_txt.text, "utf-8");
fileStream.close();
}
function doLoad(e:MouseEvent):void {
var fileStream:FileStream = new FileStream();
try{
fileStream.open(file, FileMode.READ);
//_txt.text = fileStream.readMultiByte(file.size, File.systemCharset);
_txt.text = fileStream.readMultiByte(file.size, "utf-8");
}catch(err:IOError){
_txt.text = "No data!";
}
fileStream.close();
sbar.update();
}
function doClear(e:MouseEvent):void {
_txt.text = "";
sbar.update();
}
save_btn.addEventListener(MouseEvent.CLICK, doSave);
load_btn.addEventListener(MouseEvent.CLICK, doLoad);
clear_btn.addEventListener(MouseEvent.CLICK, doClear);

原始檔: saveTextFile.fla

2007-06-19

Create AIR Apps in Flash CS3

AIR SDK 請安裝新的 beta
參考 Create Apollo Apps in Flash CS3 安裝「Test in Apollo.mxp」

如果之前已經安裝 apollo alpha1 sdk
1. 直接將「C:\Documents and Settings\USERID\Local Settings\Application Data\Adobe\Flash CS3\en\Configuration\Test in Apollo\config.dat」的內容改成新 SDK 的路徑, 例如:
file:///C|/air_b1_win_sdk_061107

2. 將「C:\Documents and Settings\USERID\Local Settings\Application Data\Adobe\Flash CS3\en\Configuration\Test in Apollo\apollo-app-template.xml」的內容改成:
<application xmlns="http://ns.adobe.com/air/application/1.0.M4" appId="$appId" version="$version">
<name>$name</name>
<title>$name</title>
<publisher>$publisher</publisher>
<description>$description</description>
<copyright>$copyright</copyright>
<rootContent systemChrome="standard" visible="true">[the name of your main file will be put here]</rootContent>
</application>

如果從未安裝「Test in Apollo.mxp」, 安裝之後, 如上述第2點修改 apollo-app-template.xml 即可。

漏掉了一件事, playerglobal.swc 也要更新。

  1. Download Flex 3 SDK 3 beta 1 and unzip it

  2. Copy the airglobal.swc from the frameworks\libs\air folder of the Flex 3 SDK 3 beta 1

  3. Paste it into the \en\Configuration\ActionScript 3.0\Classes folder of your Adobe Flash CS3 installation

  4. Delete the playerglobal.swc file that is inside of that same folder

  5. Rename the airglobal.swc file to playerglobal.swc

Adobe Extension mxi 於 Windows 存放的路徑

路徑在:
C:\Documents and Settings\USERID\Application Data\Adobe\Extension Manager\Configuration\Extensions
以 Flash CS3 為例, mxi 中指的 $flash 為:
C:\Documents and Settings\USERID\Local Settings\Application Data\Adobe\Flash CS3\en\Configuration

2007-06-18

元件會自動轉換為類別

沒有設定連結的元件, 和設定連結的元件類似, 可能會被轉換為類別
如果元件內沒有 frame actions, 元件實體會屬於 MovieClip 類型
如果元件內包含 frame actions, 則轉換為「元件名_X」的類別, 其中 X 為 z-order index
參考原始檔: symbol_to_class.fla
既然為類別, 元件內定義的 functions (不論在哪一影格定義), 在實體出現時即可被呼叫
當然也可以由類別建立物件
參考原始檔: symbol_to_class_2.fla

DisplayObjects 的 frame actions 執行順序

Flash AS3 中, frame actions 執行順序和 AS1/AS2 一樣
父物件的 frame actions 先執行, 再執行子物件的 frame actions

Z-order Index (part 2)

移除 DisplayObject 時, 其原本所佔用的 index, 會被後面的物件所遞補
參考 設定連結的元件會變成類別 原始檔
Frame actions :
var ar:Array = new Array();
var s:Symbol1;
for (var i:int=0; i<6; i++) {
s = new Symbol1();
s.x = s.width*i;
s.y = 100;
s._txt.text = String(i+1);
s.name = 's'+(i+1);
s.addEventListener(MouseEvent.CLICK, cOnClick);
this.addChild(s);
ar.push(s);
}

function cOnClick(e:MouseEvent):void {
var t_mc:MovieClip = e.currentTarget as MovieClip;
t_mc.parent.removeChild(t_mc);
trace('子物件數目:', this.numChildren);
for (var i:int=0; i < ar.length; i++) {
if (this.contains(ar[i])) {
trace(ar[i].name, ':', this.getChildIndex(ar[i]) );
}
}
}

點按1號物件後的輸出結果:
子物件數目: 5
s2 : 0
s3 : 1
s4 : 2
s5 : 3
s6 : 4

若欲取得某 DisplayObject 的所有子物件, 可以搭配使用:
for(var k:int=0; k < this.numChildren; k++){
var d:DisplayObject = this.getChildAt(k);
trace(d.name);
}

Z-order Index (part 1)

在 AS2, 稱為 depth; 在 AS3, 稱 z-order index
有兩個方法可以改變 z-order index:
swapChildren(child1:DisplayObject, child2:DisplayObject):void
swapChildrenAt(index1:int, index2:int):void

兩者的參數必須是合法的 DisplayObject (已存在的子物件)
或者合法的 index (已存在子物件的索引)

因此, 所有已被使用的 indexes 必定是連號的
(例如: 0,1,2,3,4,5,6)
不會有中間空號沒被使用的情形
(不會發生: 0,1,2, 4,5,6,7)

2007-06-16

Loading External module-SWF

參考 ActionScript 3 Tip of the Day: Loading External Classes with ApplicationDomain

載入模組測試
load_module_loadee01.fla 包含 linkaged symbol: Symbol1
load_module_loader01.fla
var my_this = this;
var ldr:Loader = new Loader();
var ldrContext:LoaderContext = new LoaderContext();
// 使用 loader 的類別域
ldrContext.applicationDomain = ApplicationDomain.currentDomain;
ldr.load(new URLRequest("load_module_loadee01.swf"), ldrContext);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);

function onComplete(e:Event):void{
/*
var Symbol1:Class =
ApplicationDomain.currentDomain.getDefinition('Symbol1')
as Class;
*/
var Symbol1:Class = getDefinitionByName('Symbol1')
as Class;

var s:MovieClip = new Symbol1();
this.addChild(s);
}

原始檔: load_module_01.zip

2007-06-15

載入 SWF 後的物件關係 (AS3)

loadee.fla :
a_mc.alpha = 0.5;
trace('a_mc.parent:',
a_mc.parent, "::",
a_mc.parent.name);
trace('a_mc.parent.parent:',
a_mc.parent.parent, "::",
a_mc.parent.parent.name);
trace('a_mc.parent.parent.parent:',
a_mc.parent.parent.parent, "::",
a_mc.parent.parent.parent.name);
trace('a_mc.parent==root :', a_mc.parent==root);
trace('------------');

loader.fla :
var my_this = this;
var ldr:Loader = new Loader();
ldr.load(new URLRequest("loadee.swf"));
addChild(ldr);

b_mc.addEventListener(MouseEvent.CLICK, function():void{
trace(ldr.content.name);
ldr.content['a_mc'].rotation = 30;
});

loadee.fla 裡內有一個 MovieClip「a_mc」
loader.fla 裡內有一個 MovieClip「b_mc」
執行 loader.swf 後, 再按 b_mc 後的結果:
a_mc.parent: [object MainTimeline] :: instance4
a_mc.parent.parent: [object Loader] :: instance3
a_mc.parent.parent.parent: [object MainTimeline] :: root1
a_mc.parent==root : true
------------
instance4

由結果可知 :
1. loader root -> ldr -> loadee root -> a_mc
(上式 -> 表示包含子物件)
2. 每個 swf 裡的 root 參照是固定的, 不因被載入而改變

使用匿名偵聽函式該注意

1. 若有 frames loop, 會註冊多個偵聽器
2. 匿名函式內的 this 指向一 Global 物件
a_btn.addEventListener(
MouseEvent.CLICK,
function(e:MouseEvent):void{
trace(this, ':', e.target.name);
}

);

Output:
[object global] : a_btn

由物件取得類別名

由物件取得類別名, 使用 getQualifiedClassName()
由物件取得類別資料, 使用 describeType()
由類別名取得類別物件, 使用 getDefinitionByName()
例:
var sprite:Sprite = new Sprite();
// 取得物件的類別資訊
trace(getQualifiedClassName(sprite));
// 取得物件所屬類別的父類別資訊
trace(getQualifiedSuperclassName(sprite));
// 由字串取得類別
var c:Class = getDefinitionByName("flash.display::Sprite") as Class;
var s:Sprite = new c();
trace(getQualifiedClassName(s));
trace(getQualifiedSuperclassName(s));

AS3 FlashVars

Flash AS3 用
root.loaderInfo.parameters // 或 stage.loaderInfo.parameters

Flex 2 用
Application.application.parameters

在 HTML/JavaScript 中修改
if (AC_FL_RunContent == 0) {
alert("This page requires AC_RunActiveContent.js.");
} else {
AC_FL_RunContent(
'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0',
'width', '550',
'height', '400',
'src', 'flashvars_test',
'quality', 'high',
'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
'align', 'middle',
'play', 'true',
'loop', 'true',
'scale', 'showall',
'wmode', 'window',
'devicefont', 'false',
'id', 'flashvars_test',
'bgcolor', '#ffffff',
'name', 'flashvars_test',
'menu', 'false',
'allowFullScreen', 'false',
'allowScriptAccess','sameDomain',
'movie', 'flashvars_test',
'flashvars', 'a=777', // shinder added
'salign', ''
); //end AC code
}

順帶一提, Flash 檔名請符合變數命名規則, 也應避免使用 _ (underscore)

設定連結的元件會變成類別

設定元件的連結

若無定義類別, Flash 會自動幫你產生一個
在這個例子裡, Symbol1 裡有一個動態文字物件 _txt
AS3 已經沒有 attachMovie() 可用
複製 MovieClip 時,使用 new 和 addChild
var s:Symbol1;
for (var i:int=0; i<6; i++) {
s = new Symbol1();
s.x = s.width*i;
s.y = s.height/2*i;
s._txt.text = String(i+1);
addChild(s);
}

結果:

原始檔

Flash CS3 的 AS3 components 無 bindings

暈 ... 福樂包比不上麥香包 ( fl 套件比不上 mx 套件 )

2007-06-14

AS3 Event Phases

ActionScript 3 的事件物件傳遞方式
Adobe ActionScript Article: Introduction to event handling in ActionScript 3.0

Event Object 由外傳至內(capture phase), 達到標的物件(target phase)後, 再往外傳(bubbling phase)
addEventListener() 的第三個參數 (useCapture) 就是用來決定,
偵聽器是否在 capture phase 時偵聽事件並觸發
useCapture 預設值為 false, 因此事件在 target phase 或 bubbling phase 可以被偵聽。
以下是個說明的例子:
var m1:MovieClip = new MovieClip();
m1.graphics.beginFill(0xFF9900);
m1.graphics.drawRect(100, 100, 200, 200);
m1.graphics.endFill();
m1.name = 'm1';
var m2:MovieClip = new MovieClip();
m2.graphics.beginFill(0x99FF00);
m2.graphics.drawRect(140, 140, 120, 120);
m2.graphics.endFill();
m2.name = 'm2';

addChild(m1);
m1.addChild(m2);

function mHandler(e:MouseEvent) {
switch (e.eventPhase) {
case EventPhase.CAPTURING_PHASE :
trace('capture');
break;
case EventPhase.AT_TARGET :
trace('at target');
break;
case EventPhase.BUBBLING_PHASE :
trace('bubbling');
}
trace('currentTarget: ' +e.currentTarget.name + e.currentTarget);
trace('target: ' + e.target.name + '\n');
}
stage.addEventListener(MouseEvent.CLICK, mHandler);
root.addEventListener(MouseEvent.CLICK, mHandler);
m1.addEventListener(MouseEvent.CLICK, mHandler);
m1.addEventListener(MouseEvent.CLICK, mHandler); // 重複註冊偵聽器
m2.addEventListener(MouseEvent.CLICK, mHandler);
stage.addEventListener(MouseEvent.CLICK, mHandler, true);
root.addEventListener(MouseEvent.CLICK, mHandler, true);
m1.addEventListener(MouseEvent.CLICK, mHandler, true);
m2.addEventListener(MouseEvent.CLICK, mHandler, true); // 這一行沒有作用

用滑鼠擊點 m2 後的結果:
capture
currentTarget: null[object Stage]
target: m2

capture
currentTarget: root1[object MainTimeline]
target: m2

capture
currentTarget: m1[object MovieClip]
target: m2

at target
currentTarget: m2[object MovieClip]
target: m2

bubbling
currentTarget: m1[object MovieClip]
target: m2

bubbling
currentTarget: root1[object MainTimeline]
target: m2

bubbling
currentTarget: null[object Stage]
target: m2

2007-06-13

由 URL 取得 Domain Name (AS2 版)

在測試和發佈 Flash Remoting 專案時還滿有用的
原始檔 MyDomain.as
/**
* author: shinder lin
* email: shinder.lin@gmail.com
*/
class MyDomain {
static var defaultDomain = "http://localhost";
static function getDomain() {
var url_str = _root._url;
if (url_str.indexOf("http://") == 0) {
var s_index = url_str.indexOf("/", 10);
return url_str.substring(0, s_index);
} else {
return defaultDomain;
}
}
}

SDDump - Dump 的 AS2 版

原始檔 SDDump.as
/**
* author: shinder lin
* email: shinder.lin@gmail.com
*/
class SDDump {
static var n:Number = 0;
static var str:String = '';
static function echo(a) {
trace(go(a));
}
static function go(a) {
str = '';
dumpIt(a);
str = str.slice(0, str.length-1);
return str;
}
static function dumpIt(a) {
if (a instanceof Array) {
dumpArray(a);
} else if (a instanceof Object) {
dumpObject(a);
} else {
appendStr(a);
}
}
static function dumpArray(ar:Array):Void {
n++;
for (var o in ar) {
if (ar[o] instanceof Object) {
appendStr("["+o+"]:");
dumpIt(ar[o]);
} else {
appendStr("["+o+"]:"+ar[o]);
}
}
n--;
}
static function dumpObject(obj:Object):Void {
n++;
for (var o in obj) {
if (obj[o] instanceof Object) {
appendStr(o+":");
dumpIt(obj[o]);
} else {
appendStr(o+":"+obj[o]);
}
}
n--;
}
static function appendStr(s):Void {
str += getSpaces()+s+'\n';
}
static function getSpaces():String {
var s:String = '';
for (var i = 1; i < n; i++) {
s += " ";
}
return s;
}
}

2007-06-12

Adobe AIR beta

之前代號為 Apollo, 現在正式稱為 Adobe AIR
釋出 public beta Adobe Integrated Runtime (AIR)
相關新聞: Adobe推Apollo平台測試版 正名AIR
Flex 3 也 beta 了, 請看 Adobe Labs

AS3 frame actions 可以定義 setter/getter functions

Flash CS3 AS3 的 frame actions 可以用 setter/getter 囉
雖然不能使用 private 宣告變數
但是可以定義 setter/getter functions 就很方便了
var t:Number = 10;
function set test(n:Number):void {
t=n;
}
function get test():Number {
return t;
}
trace('t='+t);
test = 99;
trace('t='+t);

2007-06-11

The rules of frame actions converting to a class definition ?

承上一篇: Frame Action 的 Function literal 裡的 Scope
個人「純猜測」可能轉換成類別定義:
package {
import flash.display.MovieClip;

public class TestMC8 extends MovieClip {
public var me:Object = this;
public var o:Object = {};
public var i:Number = 6;

public function TestMC8() {
addFrameScript(0, frame1);
}

internal function frame1():void {
o.a = function():void{
this.c = function():void{
};
};
o.b = function():void{
trace(i);
trace(this.i);
trace(me.i);
};
o.a();
o.b();
}
}
}

然而 frame1 應該不是 class member, 所以應該比較像這樣:
package {
import flash.display.MovieClip;

public class TestMC8a extends MovieClip {
public var me:Object = this;
public var o:Object = {};
public var i:Number = 6;

public function TestMC8a() {
function frame1():void{
o.a = function():void{
this.c = function():void{
};
};
o.b = function():void{
trace(i);
trace(this.i);
trace(me.i);
};
o.a();
o.b();
trace(this);
}

addFrameScript(0, function(){
frame1.apply(me);
}
);
}
}
}

紅色字的部份應該是在 addFrameScript() 裡面運作

Frame Action 的 Function literal 裡的 Scope

之前在 mmug 的討論: Flash CS3 - AS3 又一影格程式問題
老方式用 describeType() 去檢查. 以 literal 方式定義的 function objects, 其內部的變數若不是以 this 為開頭, 皆會被轉換為 影格所在MovieClip 物件的屬性。
Frame Actions:
var me:Object = this;
var o:Object = {};
o.a = function():void{
var i:Number = 6;
this.c = function():void{
var k;
};
};
o.b = function():void{
trace(i);
trace(this.i);
trace(me.i);
};
o.a();
o.b();
trace(describeType(this));

結果:
6
undefined
6
...
<variable name="k" type="*"/>
<variable name="i" type="Number"/>
<variable name="me" type="Object"/>
<variable name="o" type="Object"/>
...

MainTimeline Frame Functions -> Class Methods

Flash CS3 裡 MainTimeline frame actions 定義的 functions (not literal)
如何轉換成 class methods 的定義呢 ?
測試了一下, 無論在哪一格定義, 全都變成 public class methods

Frame 1:
b();
a();
function a():void {
trace('a');
}

Frame 6:
stop();
function b():void {
trace('b');
}
trace(describeType(this));

輸出結果:
b
a
<type name="Untitled_fla::MainTimeline" base="flash.display::MovieClip" isDynamic="true" isFinal="false" isStatic="false">
...
<method name="a" declaredBy="Untitled_fla::MainTimeline" returnType="void"/>
<method name="b" declaredBy="Untitled_fla::MainTimeline" returnType="void"/>
...

2007-06-10

AS3 未公開的類別和方法

網路上的資源:
Ticore's Blog: ActionScript 3.0 未公開的函式 AVM1Movie.call、addCallback, ActionScript 3.0 未公開的函式 MovieClip.addFrameScript
Experimenting with AS3 ,Apollo and HaXe: ActionScript3中未公开的一些方法和类

在 Flash CS3 開個 AS3 新文件, 輸入 Frame Actions
trace(describeType(this));

得到的結果, 可以找到
<method name="addFrameScript" declaredBy="flash.display::MovieClip" returnType="void">
<metadata name="Inspectable">
<arg key="environment" value="none"/>
</metadata>
</method>

依照 metadata 標籤又可以找到
<accessor name="accessibilityImplementation" access="readwrite" type="flash.accessibility::AccessibilityImplementation" declaredBy="flash.display::InteractiveObject">
<metadata name="Inspectable">
<arg key="environment" value="none"/>
</metadata>
</accessor>

addFrameScript 和 AccessibilityImplementation 都是 undocumented.

Colin Moock - actionscript 3.0 and flash cs3

Colin Moock - 演講大綱
actionscript 3.0 and flash cs3
explains how to integrate ActionScript 3.0 code with content created in the flash cs3 authoring tool.

AS3 與 AMFPHP 1.2 part 3 - Credentials

AS3 沒有 setCredentials() 了
而是利用 NetConnection.addHeader(), 下兩行是 Help 裡說明
Adds a context header to the AMF packet structure.
This header is sent with every future AMF packet.

Flash AS3:
var nc:NetConnection = new NetConnection();
nc.objectEncoding = ObjectEncoding.AMF0;
nc.connect('http://localhost/amfphp/gateway.php');
nc.addHeader("Credentials", false,
{userid:'kitty', password:'kitty'});

var responder:Responder = new Responder(onResult, onError);
nc.call('myremoting.DataOp_6.isLogin', responder);

function onResult(re:Object):void {
QopDump.echo(re);
}
function onError(er:Object):void {
QopDump.echo(er);
}

AS3 與 AMFPHP 1.2 part 2

後台傳送資料表至前端的「格式」
DataOp_2.php 原始碼
< ?php
class DataOp_2
{
var $dbhost = "localhost";
var $db = "test";
var $table = "tbl_address_book";
var $user = "root";
var $password = "admin";

function DataOp_2(){
mysql_connect($this->dbhost, $this->user, $this->password);
mysql_query("SET NAMES 'utf8'");
mysql_select_db($this->db);

$this->methodTable = array(
"getAllData"=>array(
"access"=>"remote"
)
);
}

function getAllData(){
$sql = sprintf("select * from `%s`", $this->table);
return mysql_query($sql);
}
}
?>

Flash AS3
import QopDump; // just prompt

var nc:NetConnection = new NetConnection();
nc.connect('http://localhost/amfphp/gateway.php');
var responder:Responder = new Responder(onResult, onError);
nc.call('myremoting.DataOp_2.getAllData', responder);

function onResult(re:Object):void {
QopDump.echo(re);
}
function onError(er:Object):void {
QopDump.echo(er);
}

正常執行的結果:
serverInfo:
version:1
id:
serviceName:PageAbleResult
initialData:
[0]:
[0]:3
[1]:哈利
[2]:0987654321
[3]:台北市大安區
[1]:
[0]:4
[1]:凱蒂貓
[2]:0987654322
[3]:宜蘭縣礁溪鄉
[2]:
[0]:6
[1]:小叮噹
[2]:0987654323
[3]:台東縣知本溫泉旁
columnNames:
[0]:id
[1]:name
[2]:phone
[3]:address
cursor:1
totalCount:3

方法名稱錯誤的結果:
line:171
description:The method {getAll} was not declared in the meta data for class {DataOp_2}.
level:User Error
details:C:\wamp163\www\amfphp\amf-core\app\Actions.php
code:AMFPHP_UNDECLARED_METHOD

AS3 與 AMFPHP 1.2 part 1

AS3 object serialization 預設為 AMF3, 後台若使用 AMFPHP 1.2
且要由 AS3 送資料紿後台時, 記得要設定成 AMF0 的格式溝通
var nc:NetConnection = new NetConnection();
// 設定為 AMF0, 預設值為 AMF3
nc.objectEncoding = ObjectEncoding.AMF0;
nc.connect('http://localhost/amfphp/gateway.php');

2007-06-09

QopDump - Dump 的 AS3 版

改寫以前 AS2 的 Dump
使用方式
var a:Object = ["sd","tg","rt",{a:"1", b:"23", c:"11"}];
// 取得字串資料用 QopDump.go(a)
// 直接 trace
QopDump.echo(a);

執行結果:
[0]:sd
[1]:tg
[2]:rt
[3]:
c:11
a:1
b:23

原始檔 QopDump.as
/**
* author: shinder lin
* email: shinder.lin@gmail.com
*/
package {
import flash.utils.describeType;
public class QopDump {
static var n:int = 0;
static var str:String;
// trace
public static function echo(o:Object):void {
trace( go(o) );
}
// return the result string
public static function go(o:Object):String {
str = "";
dump(o);
// remove the lastest \n
str = str.slice(0, str.length-1);
return str;
}
static function dump(o:Object) {
var type:String = describeType(o).@name;
if(type == 'Array') {
dumpArray(o);
} else if (type == 'Object') {
dumpObject(o);
} else {
appendStr(o);
}
}
static function appendStr(s:Object) {
str += s + '\n';
}
static function dumpArray(a:Object):void {
n++;
var type:String;
for (var i:String in a) {
type = describeType(a[i]).@name;
if (type == 'Array' || type == 'Object') {
appendStr(getSpaces() + "[" + i + "]:");
dump(a[i]);
} else {
appendStr(getSpaces() + "[" + i + "]:" + a[i]);
}
}
n--;
}
static function dumpObject(o:Object):void {
n++;
var type:String;
for (var i:String in o) {
type = describeType(o[i]).@name;
if (type == 'Array' || type == 'Object') {
appendStr(getSpaces() + i + ":");
dump(o[i]);
} else {
appendStr(getSpaces() + i + ":" + o[i]);
}
}
n--;
}
static function getSpaces():String {
var s:String ="";
for(var i:int = 1; i < n; i++){
s += " ";
}
return s;
}
}
}

2007-06-08

describeType() 是判斷型別的好工具

flash.utils.describeType() 是判斷型別的好工具
Flash AS3:
var a:Object = 123;
var b:Object = 1e-1;
var c:Object = {a:1,b:2};
var d:Object = [5,4,3];
var e:Object = 'sss';
trace(describeType(a).@name);
trace(describeType(b).@name);
trace(describeType(c).@name);
trace(describeType(d).@name);
trace(describeType(e).@name);

Output:
int
Number
Object
Array
String

AS3 堆疊溢位

AS2 的遞迴限制是 255 次
AS3 顯然好多了, 我測試的結果是 6898 次
不知道是否跟系統資源相關
function sum(n:int):int{
trace(n);
if(n < 2)
return 1;
else
return n+sum(n-1);
}
trace(sum(6900));

Error #1023: 發生堆疊溢位

Adobe CS3 中文版於 7/12 發表

Adobe CS3中文版將於七月發表
CS3 中文版上市日程
於7月12日
假 THCC 台大醫院國際會議中心舉辦

把 JavaScript 當作 temporary data pool (AS3 和 AS2 溝通)

將 SWF9(from Flex2)收到的 Flashvars 變數, 傳給 JS
SWF8 需要時或被載入後再由 JS 取出
SWF9: AS3
private var paramObj:Object;
private function init():void{
paramObj = Application.application.parameters;
ExternalInterface.call('setMyVars', paramObj);
}

JavaScript:
var myVars;
function setMyVars(v){
myVars = v;
/*
var s='';
for(var i in v){
s+= i+' : '+v[i]+'\n';
}
alert(s);
*/
}
function getMyVars(){
return myVars;
}

SWF8: AS2
import flash.external.ExternalInterface;
var myVars = ExternalInterface.call('getMyVars');

JavaScript 的 alert() 有時也是個很好的除錯工具

AS3 和 AS2 溝通

Adobe CS3 才上市不久, 大部份的人對 Flash CS3 不是頂熟稔
若要使用 ActionScript 3 的新功能, 卻又想以熟悉的 Flash 8 開發
遇到的最大問題就是 ActionScrip 3 和 ActionScript 2 的溝通
目前常用的作法有兩種: LocalConnection 和 ExternalInterface

在使用 SWF 9 (from Flex 2) 載入 SWF 8 (from Flash 8) 的情況下, 使用文字資料做測試
LocalConnection 每次只能傳送低於 40K 的資料
透過 ExternalInterface 則可以傳遞超過 1M 的資料給 JavaScript

LocalConnection 明顯只適用於傳遞少量資料
缺點: 接收的 SWF 實體只能有一個 (第二個實體之後是收不到資料的)
優點: 不限實體的執行形式 (EXE, flash player, flash plugin)
ExternalInterface 的缺點是必須要有 plugin container 當中介的角色

之前遇到的一個情況是 SWF9 載入兩支 SWF8 (a 和 b)
● SWF8a 負責和使用者互動, 讓使用者編輯
● SWF8b 負責產生上傳的圖片
● SWF9 負責將 SWF8b 的內容上傳
SWF8a 透過 EI 傳遞 XML 給 SWF8b 產生圖片
SWF8b 完成圖片後, 透過 EI 叫 SWF9 上傳圖片

SWF8a: AS2
import flash.external.ExternalInterface;
ExternalInterface.call("toRender", _xml.toString());

JavaScript:
function toRender(str){
if(navigator.appName.indexOf("Microsoft") != -1){
window.room_planner.renderPic(str);
}else{
window.document.room_planner.renderPic(str);
}
return true;
}
function uploadImage(){
if(navigator.appName.indexOf("Microsoft") != -1){
window.room_planner.uploadImage();
}else{
window.document.room_planner.uploadImage();
}
return true;
}

SWF8b: AS2
import flash.external.ExternalInterface;
var successRegist = ExternalInterface.addCallback("renderPic", null, render);
//
function render(d_str) {
// loading objects ...
onEnterFrame = sdEnterFrame;
}
function sdEnterFrame() {
var all_loaded = true;
for (var i = 0; i < loadee_ar.length; i++) {
if (loadee_ar[i].c_mc.getBytesLoaded() < 10) {
all_loaded = false;
break;
}
}
if (all_loaded) {
resizeToUpload();
ExternalInterface.call('uploadImage');
delete this.onEnterFrame;
}
}

SWF9: AS3
private function init():void{
// ...
ExternalInterface.addCallback('uploadImage', uploadImage);
}
private function uploadImage():void{
pop = PopUpManager.createPopUp(this, MyMsgWin, true);
pop.x = 440;
pop.y = 296;

var timer:Timer = new Timer(500, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, doUploadImage);
timer.start();
}

換用免錢的暴露閣

Shinder's List 已經停擺許久了
最近又想寫點東西, 但懶得處理垃圾廣告, 所以轉到 Blogger
Shinder's List 可能會無預警倒站
部份文章會在這改寫再重貼

FB 留言