blog.Ring.idv.tw

ActionScript

「loadVariables」vs.「LoadVars」(二)

在這篇「loadVariables」vs.「LoadVars」(一)我們曾提及「loadVariables」vs.「LoadVars」資料傳送的差異,那我們該如何得知資料已載入完成了呢?是否有相對應的事件可以來協助我們呢?

「LoadVars」事件處理

利用「LoadVars」要得知資料是否已載入完成,其實是相當容易且直覺的,它提供了一個「onLoad」事件處理器來協助我們來達成實現,然而此事件是隸屬於系統事件(System Event),也就是它無法透過使用者來加以觸發的事件,而是仰賴Flash Player來觸發的,相反地,若是「onClick」等等之類的事件,則稱之為使用者事件(User Event),底下我們先來看此事件的描述:

onLoad Event Handler

public onLoad = function(success:Boolean) {}

此事件會在呼叫「LoadVars.load()」或「LoadVars.sendAndLoad()」結束時,才會由系統來加以觸發的事件,而系統會傳遞一個success參數作為判斷載入成功或失敗的變數。

範例如下:(data.txt是一個約1.8mb的文字資料,裡頭包含了「var0 ~ var99999」的變數資料,以及一個ok變數)

程式一

var data_lv:LoadVars = new LoadVars();
data_lv.onLoad = function(success)
{
	if(success)
	{
		trace("Loaded!");
		trace(this.ok);
	}else{
		trace("Failed!");
	}
}
data_lv.load("data.txt");

結果:

Loaded!
1

此「onLoad」事件的確只會在「LoadVars.load()」或「LoadVars.sendAndLoad()」結束時才會觸發的事件。

「loadVariables」事件處理

相較於「LoadVars」來說,要判斷「loadVariables」是否已完成載入資料,便顯得較為煩瑣些,雖然使用「loadVariables」會觸發「MovieClip.onData」事件,但值得注意的是並不是只有「loadVariables」才會觸發此事件,「loadMovie」也會觸發此一事件,而且還必須作些手腳來達成判斷資料是否已「完全」載入,我們先看下述這個範例:

程式二

this.loadVariables("data.txt");
this.onData = function()
{
	if(this.ok == undefined)
	{
		trace("Loading...");
	}else{
		trace("Loaded!");
		trace(this.ok);
	}
}

結果:

Loading...
Loaded!
1

從執行的結果上來觀察,我們可以知道「onData」這個事件至少被系統呼叫了「兩」次,這也就是為何筆者需要加上一個「ok」變數資料在「data.txt」文件上,那是否還有額外的方式可以處理呢?其實我們也可以利用「MovieClip.onEnterFrame」來做個輪詢的方式來偵測資料是否已載入完成,或是利用「setInterval」來協助我們達成,底下是個別的作法:

setInterval

this.loadVariables("data.txt");
function checkParamsLoaded()
{
	if(_root.ok == undefined)
	{
		trace("Loading...");
	}else{
		trace("Loaded!");
		trace(_root.ok);
		clearInterval(param_interval);
	}
}
var param_interval = setInterval(checkParamsLoaded, 100);

結果:

Loading...
Loaded!
1

MovieClip.onEnterFrame

this.loadVariables("data.txt");
this.onEnterFrame = function()
{
	if(this.ok == undefined)
	{
		trace("Loading...");
	}else{
		trace("Loaded!");
		trace(this.ok);
		delete this.onEnterFrame;
	}
}

結果:(根據你的FPS而定,筆者環境FPS=30)

Loading...
Loading...
Loaded!
1

範例下載

本文若有任何謬誤,希望請不吝地賜教,若能指正不勝感激。

2007-07-18 22:32:23 | Add Comment

「loadVariables」vs.「LoadVars」(一)

在Flash Player 6之前,當我們要傳送或接收外部的資料,或者欲整合後端的程式進行溝通時,我們無非是經由「loadVariables」或「loadVariablesNum」來協助我們達成這樣的工作,那為何還需要「LoadVars」呢?當然事出必有因,而原因不外乎利用「loadVariables」進行後端程式的溝通時,若稍有不慎,可是會將整個「MovieClip」的實體變數都傳送至後端程式,或是你想偵測目前下載的進度時,那「loadVariables」也將不敷使用,基於這些原因「LoadVars」也就此誕生。

「loadVariables」vs.「LoadVars」資料傳送

我們剛剛有提到過使用「loadVariables」進行後端程式的溝通時,會將整個「MovieClip」的實體變數都傳送至後端程式,倘若當此「MovieClip」擁有大量的實體變數時,那可會伴隨著這些變數一併都傳送至後端程式,試想這樣會多有效率呢?底下我們用了「loadVariables」和「LoadVars」來做驗證:

程式一

var foo = 10;
var bar = 20;
this.loadVariables("http://localhost/loadVariables.jsp","GET");

var data_lv:LoadVars = new LoadVars();
data_lv.foo = 10;
data_lv.sendAndLoad("http://localhost/LoadVars.jsp",data_lv,"GET");

結果:

Error opening URL 'http://localhost/loadVariables.jsp?foo=10&bar=20'
Error opening URL 'http://localhost/LoadVars.jsp?foo=10'

從錯誤訊息中,我們就可以驗證「loadVariables」會將所擁有全部的實體變數傳送出去(不包含$version),而我們利用「LoadVars」則僅會將我們所定義在此實體的變數值傳送而已(data_lv.foo),所以既然了解「loadVariables」有此特性,所以我們必然要使用較佳的方案來達成:

程式二

var foo = 10;
var bar = 20;

this.createEmptyMovieClip("data_mc",1);
data_mc.foo = 30;
data_mc.loadVariables("http://localhost/loadVariables.jsp","GET");

結果:

Error opening URL 'http://localhost/loadVariables.jsp?foo=30'

從結果上來看,若是需要利用「loadVariables」來進行資料交換的話,上述程式會是較好的作法,畢竟獨立一個「MovieClip」會較容易拿捏與掌握它。

範例下載

本文若有任何謬誤,希望請不吝地賜教,若能指正不勝感激。

2007-07-18 18:13:06 | Add Comment

從元件庫(Library)附加你的元件(一)-「attachMovie()」

「attachMovie()」-從字面上所表徵的意思,「attach」可以解釋為「貼上」或「附加」等意思,加上後面的「Movie」便知大意為「附加上你的影片片段」,也就是說,當我們想要從元件庫(Library)附加上「元件」時,即可利用這個方法來幫助我們達成。

剖析之前的預備動作

前置處理

在開始剖析之前,我們必須先做一些前置處理,這裡我們先利用「Rectangle Tool」等工具,在Stage上任意繪製形狀,並將此形狀轉成「MovieClip」元件,接著將此元件內的形狀刪除,意即為保留此「MovieClip」為「空」的狀態,以便容易剖析。

貼上元件的識別名稱(Identifier)

開啟元件庫,將剛剛所建立的元件給予它一個「識別名稱(Identifier)」,如此才能利用「attachMovie()」來達成動態附加元件庫中的元件,如圖所示:

簡單的驗證程式

最後在此元件內的Frame[1]寫入下述程式:

trace(this);

剖析「attachMovie()」的運用方式

根據ActionScript 2.0 Language Reference的說明,在開始運用「attachMovie()」之前,我們來觀察一下必須運用的參數有哪些?

Parameters

id:String — 對應元件庫中的識別名稱。

name:String — 給予它一個「實體名稱(instance name)」。

depth:Number — 深度值,可參考「Layer」、「Level」和「Depth」之間的三角關係(四)

initObject:Object (optional) — 在Flash Player 6之後才被支援的參數,可用來初始化此實體的一些屬性。

了解上述參數的意義為何之後,我們直接寫個簡單的測試程式(如下所示),將剛剛前置作業所準備的元件來加以運用:

_root.attachMovie("rect","rect_mc",1);

結果:

_level0.rect_mc

從結果中就可以知道,原本必須在「Properties Panel」中才能設定的「實體名稱」,現在則利用「attachMovie()」便可直接來作設定了,那Flash Player是如何達成這樣的動態處理呢?

剖析深藏在元件庫(Library)中的元件

我們將剖析上述程式的bytecode,來觀察Flash Player所發佈「swf」的檔案結構,來觀看一下端倪之處。

在藍色區塊的部份是屬於「rect」元件的bytecode,而紅色區塊部份則是利用「ExportAssets」這個「Control Tag」來描述「rect」元件的「識別名稱(Identifier)」,也就是說,只要當我們設定好處於元件庫中的元件「識別名稱」,並且在發佈成「SWF」檔案之後,此檔案便內含了描述此元件的「識別名稱」,進而達成動態地從元件庫中來控制特定元件。

初探「attachMovie()」的「initObject」參數

最後我們來玩玩在Flash Player 6之後才被支援的參數「initObject」,然而在開始之前我們先來想像一個情境,當我們在呼叫「attachMovie()」之後,我們想要讓此元件固定在某特定的座標位置上,那該如何處理呢?

基本上有兩種做法,一種是直接利用「initObject」參數,另一種則是採用「實體名稱」的方式來加以控制,但相對來說,第一種的做法較有執行優先權的優勢:

利用「initObject」參數

var obj = new Object();
obj._x = 50;
obj._y = 50;
_root.attachMovie("rect","rect_mc",_root.getNextHighestDepth(),obj);

採用「實體名稱」的方式

_root.attachMovie("rect","rect_mc",_root.getNextHighestDepth());
rect_mc._x = 50;
rect_mc._y = 50;

範例下載

本文若有任何謬誤,希望請不吝地賜教,若能指正不勝感激。

2007-07-09 17:42:44 | Comments (2)

「Number()」vs.「parseInt()」(一)-效率測試

基本上我們欲將字串轉成數值來加以處理的方式,大致上有:「Number()」、「parseInt()」和「Number Object」等方式,由於使用字串轉成數值的機會相當多,例如:從「TextField」取值來處理、利用「loadVariables()」來載入外部的資料等…,究竟那種方式是最有效率的呢?

善用「Number()」來加以轉換

我們直接寫入下列程式來加以檢測:

「Number()」:

function test()
{
	for(var j = 0 ; j < 100000; j++)
	{
		Number("10000");
	}
}
var start = getTimer();
test();
trace(getTimer()-start);

結果:(取決於電腦速度而有所不一)

202

「parseInt()」:

function test()
{
	for(var j = 0 ; j < 100000; j++)
	{
		parseInt("10000");
	}
}
var start = getTimer();
test();
trace(getTimer()-start);

結果:(取決於電腦速度而有所不一)

314

從結果中我們不難發現,「Number()」在字串轉成數值的處理速度,的確比「parseInt()」較為快速~究竟是如何造成的呢?兩者不是都為「Global Function」?我們可從bytecode來觀察一下兩者究竟是如何處理的。

為何「Number()」速度較快

我們直接寫入下述程式在Frame[1],以方便驗證:

var a_num = Number("1.5");
var b_num = parseInt("1.5");

從bytecode中可得知,「Number()」是利用ActionCode「0x4a」(ActionToNumber)來處理的,而「parseInt()」則是採用ActionCode「0x3d」(ActionCallFunction)來處理之,重點在於前者只需要一個指令(Instruction),而後者卻仍需仰賴呼叫AVM(ActionScript Virtual Machine)所內建的函數。

範例下載

本文若有任何謬誤,希望請不吝地賜教,若能指正不勝感激。

2007-07-06 18:04:15 | Add Comment

「Target Path」命中你的目標實體(四)

在一系列的「Target Path」命中你的目標實體()所曾提及過的「_root」、「_parent」和「this」,在本文中我們將配合著這些觀念來加以活用。

「_root」絕對路徑 vs. 「_parent」相對路徑

這裡我們設計一個簡單的範例來說明,我們在Stage上放置兩個「MovieClip」,一個名為「red_mc」的紅色矩形,另一個為「blue_mc」的藍色矩形,並在「red_mc」裡面附上一個「Button」,同時為此「Button」寫入下述程式:

on(release)
{
	trace(this);
}

結果:

_level0.red_mc

從結果中我們可以發現,寫在「Button」上的「on」事件處理程式,「this」所參考到的是此「Button」所處在的「MovieClip」(red_mc)而非此「Button」本身,這是因為「this」只能參考到一個「Object」或是一個「MovieClip」,反之寫在「MovieClip」上的「on」事件處理程式,便是參考到此「MovieClip」本身。

接著我們再將上述程式加點額外的控制,假設我們想在此「Button」上控制一個處在於Stage上的「blue_mc」,並將它的透明值改為50%,我們其實可以利用「_root」或是「_parent」的寫法:

相對路徑的寫法

on(release)
{
	_parent.blue_mc._alpha = 50;
}

絕對路徑的寫法

on(release)
{
	_root.blue_mc._alpha = 50;
}

上述兩種寫法都可以達到同樣的作用,一個是從元件內部往上一層實體去達成,另一個則是直接從「_root」實體去控制,倘若遇到較多層結構的寫法時,例如:「_parent._parent._parent.blue_mc.alpha = 50;」和「_root.blue_mc._alpha = 50;」,兩者相形之下,若不考慮元件間的相依性,絕對路徑的寫法相較而言簡潔了許多,當然這兩種寫法均仰賴著設計者如何去取捨,。

「_root」和「_parent」的取捨

無論使用「_root」或「_parent」的確都可達到相同的作用,那該如何去取捨這兩種用法呢?筆者建議你採用「高內聚力(High Cohesion)、低耦合力(Low Coupling)」的設計準則來加以取捨,因為使用「_parent」的作法,必然會造成元件之間相依性的提高,所以若沒有適當地切割元件與元件間的相依性,那往往會造成「牽一髮而動全身」的情況發生,採用此設計準則無非是希望元件能更具有彈性與獨立性。

範例下載

2007-07-02 22:40:33 | Add Comment

Next Posts~:::~Previous Posts
Copyright (C) Ching-Shen Chen. All rights reserved.

::: 搜尋 :::

::: 分類 :::

::: 最新文章 :::

::: 最新回應 :::

::: 訂閱 :::

Atom feed
Atom Comment