2012年3月28日 星期三

[AS3] 取得FUNCTION 的名稱

其實我只是在想一個可以偷懶得好方法~
這樣在 LOG檔可以不用寫太多東西~

來簡介一下~
目前我會的取得FUNCTION NAME的名稱的方法


public function getFunctionName(f:Function, root:*):String
{
var t:Object = root;
var methods:XMLList = describeType(t)..method.@name;
for each (var m:String in methods)
if (t.hasOwnProperty(m) && t[m] != null && t[m] === f) return m;          
return null;
}
而且還要配合
trace(getFunctionName(arguments.callee, this));

這樣子來使用!
非常麻煩 而且還有限定 是公開 非靜態的方法

雖然很早就在 Ticore 大的BLOG 上拜見過這招
不過我都一直沒想到可以拿來應用!

直到我看到某個範例

public static function getName():String {
var error:Error = new Error();
var stackTrace:String = error.getStackTrace();     // entire stack trace
if(stackTrace == null) return 'null';
var startIndex:int = stackTrace.indexOf("at ", stackTrace.indexOf("at ") + 1); //start of second line
var endIndex:int = stackTrace.indexOf("()", startIndex);   // end of function name
var lastLine:String = stackTrace.substring(startIndex + 3, endIndex);
var functionSeperatorIndex:int = lastLine.indexOf('/');
var functionName:String = lastLine.substring(functionSeperatorIndex + 1, lastLine.length);
return functionName;
}

這招 BUG 到逆天了
不管是靜態 公開 私用 等等的FUNCTION
通通都可以抓的到
更扯的是可以抓到上一層 上上一層
雖然還是有使用限制!
在非 debug 或是 ADL的環境下無法使用!
因為 getStackTrace 會是 null
不過跟原來的那招比~
好用很多了

更扯的是!


getFunctionName函數執行1000次 消耗的時間為2057毫秒
getName函數執行1000次 消耗的時間為45毫秒
不過直接輸出字串 約 1毫秒....

這兩個執行時間的差距!
如果你是跟我一樣的偷懶開發者!
在LOG的部分 不要忘了這招! 而且在非 debug的播放器下自動失效!

下面是我測的是文件

public function testLocalClassCall()
{
unitTestTool.addFunction('test02', this);
unitTestTool.addFunction('test03', this);
unitTestTool.addFunction('test04', this);
unitTestTool.startFunTest(1000);
unitTestTool.start();
}

public function test02():void
{
var s:String = getFunctionName(arguments.callee, this);
}

public function test03():void
{
var s:String = getName();
}

public function test04():void
{
var s:String = 'test04';
}

下面是他的輸出!(每次輸出都有差!)

[SWF] C:\FlexWorks\testLocalClassCall\bin-debug\testLocalClassCall.swf - 6,432 bytes after decompression
test02函數執行1000次 消耗的時間為1843毫秒
test03函數執行1000次 消耗的時間為43毫秒
test04函數執行1000次 消耗的時間為1毫秒
[Unload SWF] C:\FlexWorks\testLocalClassCall\bin-debug\testLocalClassCall.swf

2012年3月8日 星期四

[AS3] 調教效能問題:濾鏡 並不會比較耗資源!

一樣也是在公司遇到的一個小狀況
讓我 非常非常的訝異~

多層濾鏡所構成的元件在 the miner 監測下所耗用記憶體
和 一張 PNG 所構成的元件 是一樣的!

本來我推論 可能會在 CPU 的耗用上有差異
但是更嚇的人是~
沒有~兩個我自己在測的時候都是 10% 左右~
圖中所見的差異...
那應該抓圖時間的錯置的問題...

大家可以自己回去測看看~




這個是我自己弄得一個小測試~~
個人懷疑多層濾鏡的元件
自動的轉成類似 bitmapdata的方式(我沒勾點陣快取 也沒設定)
而不是和以前一樣試即時運算的結果~
所以比較不吃資源和記憶體!


所以期待靠把濾鏡去掉 去增進效能的部分
最好還想想就好~
就我目前
做的一些部分來分享一下心得



1. 
把滑鼠事件關閉 能省的資源不多 
特別是物件不多的情況下  
層次不多 或是 根本沒監聽的情況下
關閉 是省不了太多資源的!

甚至如果你是一層一層一個一個元件關 那消耗的資源還會比較多 !
以我自己的例子 一個mc 物件下面有 200~300個 sprite原件~
你沒關 所消耗的資源量 在沒監聽的情況下
基本上 和只關 最上面 mc 元件是一樣的
如果你跟我一樣傻傻的從最裡面的 SP 元件開始關起!
那恭喜 你還會消耗更多的資源

但是我用很多 我自己覺得蠻 BUG的寫法~
利用事件流的部分~所以關閉對我自己的案子來說
是有作用的

2.
把濾鏡 換成 圖片(就這篇文章專為這點寫的)
說真的用處真的不大~
不過換成圖 還是會有一點點的縮減的
特別是你用換的圖會比較小 而且重複利用的時候
個人懷疑 他是把每個元件都快取成 點陣圖
但是每個點陣圖 是獨立存在記憶體中的!
所以換成同一個元件! 會有一點點的幫助!

3.
減少使用 movieClip 真的會節省很多資源!
特別是內有複雜原件的 mc 拆成多個 簡單的 sprite 在某種程度上
是非常有用處的
個人在這個部分 節省了相當 相當多的記憶體
第一點提到的 mc 原來內部都是用 mc 去包!
但是我只是將 底層類別改成 sprite
整體來說 減少了 20~30 mb的記憶體的資源
比我換了 400~500張左右的圖
所節省的 20mb 左右還來的多.

4.
大圖換小圖 有用!
多張靜態合成一張 有用!

5.
剩下的就是一些
縮減無用的程式碼
物件變數清空
固定不用的變數改成常數
減少使用一些過度的變數

6.
還有 到MC 的最後一格
如果你用程式讓他回到第一格!
在某些情況下 不會構成 物件 消失在建造的情況
如果你沒下 那這個物件會在更新一次
雖然不知道這部分 會影響多少~
但介意的人 就多一個CODE巴

7.
其實 timer 或是 setTimeout 等的東西
吃記憶體也是蠻凶的~個人懷疑 某開場爆增的 20mb
就是因為這個部分
不過這部分我自己是還夾了 事件發送..
等等等的東西在~
所以也不太確定!

有再考慮把這部分換成 enterFrame 去監聽 !
看看會不會比較省一點~
雖然我覺得不會~不過至少就某種程度來說
好控制~
比寫在元件最後一個影格送出EVENT 或是 seTimeout 的部分都好控制多了

雖然這幾點 感覺用處不大!
但是還是有一點點的用處~
有類似問題的可以考慮試看看

以我手上的案子~
最一開始沒調整過
開場約是 144~150 mb左右的記憶體
經過我自己一堆調整後
開場約 118 ~124
不過 穩定後 大約都是  106~118 左右的記憶體!

如果以關閉全部動畫和元件中的事件流...
穩定的時候 大約可以壓到 89mb左右....(最佳情況)

不過遊戲中 有一個算是特殊遊戲的東西~
這部分很誇張~
載入就約 220左右~
效能最高可以吃到 699mb

經過我一些調整後 大約最高 650mb
不過開場始終壓不下來~慘的是還會飆的比沒調高....
讓我自己覺得非常的失敗~
而且還是將大圖換小圖後的結果!

不過穩定約 186 mb 都是差不多的! 調前調後都一樣
不過我已經將大量 可以換成 靜態圖 取代的 濾鏡效果都替換了
連 大量的 大圖我都 換成小圖了....

這邊我想除了我從 程式的部分去調外~
原件的部分 我真的不知道怎樣調了...

[AS3] 調用本地的CLASS

調用 外部SWF 的CLASS 已經是稀鬆平常的事了~
調用本地類別 的CLASS 通常都是直接打 比較快 還有提示~
萬一本地的類別太多 須要靠拼字來調用
會讓程式碼減短一點
可以利用這招
this.loaderInfo.applicationDomain.getDefinition('className')
來調用~
這招我用很久了~
不過到最近工作才發現~
原來他有一個限制

就是一定要新增到場景上后 才能調用該類別 !

下面是測試的程式碼

package
{
import flash.display.Sprite;

public class testLocalClassCall extends Sprite
{
public function testLocalClassCall()
{
trace("test !!!!");
var cla:Class;
if(this.loaderInfo.applicationDomain.hasDefinition('mc1'))
cla  = this.loaderInfo.applicationDomain.getDefinition('mc1') as Class;
trace('mc1 ' + cla)
}
}
}


理論上 會有這樣的輸出

test !!!!
mc1 : null
原來以前某些案子的 null 是這樣來的
所以以後調用 本地端的函數
還是先寫好 switch 然後~
靠拼字去取得 class 比較妥當


2012年2月2日 星期四

[AS3]IF和 SWITCH 的比較

在公司我看到一些用IF的判斷~
我就一直想改成SWTICH版的~
不過想想不知到那一種比較好~
所以我就來試看看~

個人的想法是 如果項數多
應該是SWTICH會比較快~
因為IF是多次判斷
所以來測試了一下~

如果是兩個選項的

testIf函數執行100000次 消耗的時間為71毫秒 消耗 0 記憶體 平均每次時間為 0.00071毫秒
testSwitch函數執行100000次 消耗的時間為72毫秒 消耗 0 記憶體 平均每次時間為 0.00072毫秒


四個選項的

testIf函數執行100000次 消耗的時間為70毫秒 消耗 0 記憶體 平均每次時間為 0.0007毫秒
testSwitch函數執行100000次 消耗的時間為72毫秒 消耗 0 記憶體 平均每次時間為 0.00072毫秒

10個選項的


testIf函數執行100000次 消耗的時間為74毫秒 消耗 0 記憶體 平均每次時間為 0.00074毫秒
testSwitch函數執行100000次 消耗的時間為75毫秒 消耗 0 記憶體 平均每次時間為 0.00075毫秒

不過以上是在數據平均的情況下~

如果數字不平均~會讓IF多次判斷的話
十個選項的

testIf函數執行100000次 消耗的時間為69毫秒 消耗 0 記憶體 平均每次時間為 0.00069毫秒
testSwitch函數執行100000次 消耗的時間為67毫秒 消耗 0 記憶體 平均每次時間為 0.00067毫秒

平均的話
我是改 teatInit 把數字給的和選項一樣多
那 IF 會比 SWTICH 稍快一點
如果 10個選項 但是產生的數字只從 0~5
會差多一點
如果只有 0~3那會差快一被
不過看起來 還是使用 if會比較好

下面是我的程式碼~
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
  xmlns:s="library://ns.adobe.com/flex/spark" 
  xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
 applicationComplete="init();"
  >
<fx:Script>
<![CDATA[
import com.tenchiwang.unitTest.unitTestFunObj;
import com.tenchiwang.unitTest.unitTestTool;

private var arr:Array;
private function init():void
{
//switch
teatInit();
unitTestTool.addFunction('testIf', this, new Array(arr), 'testIf');
unitTestTool.addFunction('testSwitch', this, new Array(arr), 'testSwitch');
unitTestTool.startFunTest(100000);
trace(unitTestTool.DETAIL);
}

public function testIf(arr:Array):void
{
for(var i:int = arr.length-1;i<0;i--)
{
if(arr[i]==1)
{
test01();
}
else if(arr[i]==2)
{
test01();
}else if(arr[i]==3)
{
test01();
}else if(arr[i]==4)
{
test01();
}else if(arr[i]==5)
{
test01();
}else if(arr[i]==6)
{
test01();
}else if(arr[i]==7)
{
test01();
}else if(arr[i]==8)
{
test01();
}else if(arr[i]==9)
{
test01();
}else if(arr[i]==0)
{
test01();
}
else
{
test01();
}
}
}

public function testSwitch(arr:Array):void
{
for(var i:int = arr.length-1;i<0;i--)
{
switch(arr[i])
{
case 1:
test01();
break;
case 2:
test01();
break;
case 3:
test01();
break;
case 4:
test01();
break;
case 5:
test01();
break;
case 6:
test01();
break;
case 7:
test01();
break;
case 8:
test01();
break;
case 9:
test01();
break;
case 0:
test01();
break;
default:
test01();
}
}
}

private function teatInit():void
{
arr = new Array();
for(var i:int= 0;i<10000;i++)
{
arr.push(int(Math.random()*5));
}
}

private function test01():void
{
var tot:Number = 0;
for(var i:int= 0;i<10000;i++)
{
tot+= Math.random();
}
}
]]>
</fx:Script>
</s:Application>

2012年1月31日 星期二

[AS3]一個AIR使用的自動更新類別

恩~很早之前就決定做了~
讓AIR的程式可以自動更新的類別

不過因為眾多理由~
直到這兩天才比較有時間可以做~
來分享一下我遇到的一些問題和解決的部分

我花了一些時間再看她的DOC
不過光看DOC比實作來的複雜~

我還有看一篇 FLEX 的教學
http://www.adobe.com/devnet/air/flex/quickstart/articles/update_framework.html
基本上它的範例是可以用的
但是編譯後會遇到許多的問題

一開始遇到的問題應該是
There was an error downloading the update. Error# 16831
如果你沒改  update-descriptor.xml 的話
我查了一下~這個是說你XML寫的和編譯的xxx-app.xml
<application xmlns="http://ns.adobe.com/air/application/3.1"> 不同
如果你跟我一樣直接改成
 3.1
那你就會跟我一樣遇到


There was an error downloading the update. Error# 16815  這個問題
這是說沒有找到對應版本的 AIR
按照參考資料2
把 update-descriptor.xml
<update xmlns="http://ns.adobe.com/air/framework/update/description/2.5">
改成 2.5 那就 OK 了
至少在 FLEX 4.5 SDK 4.6.1下可以正常運行

正常狀況下~

是不會遇到下面的問題
There was an error downloading the update. Error# 16824
如果遇上了~是代表你的 發佈時的 xxx-app.xml 和  update-descriptor.xml
內的 versionNumber  不同~
就算是 2.0.0 和 2.0 這樣的差別 也會發生

最後~如果你遇到了
An unexpected error occurred. Error# 16828
這個問題~恭喜你~
你可能是因為你在 DEBUG下執行~
發佈成AIR 跑
就不會遇上了~

下面是我的從 參考資料1 的範例改成 SDK 4.6.1
可以用的版本
http://dl.dropbox.com/u/11428389/AIRupDateDemo/UpdateSampleFlex.rar 這個是整個 Flex project
http://dl.dropbox.com/u/11428389/AIRupDateDemo/UpdateSampleFlexSer.rar 這個是 我的www內放的東西~基本上根範例一內的資料夾一樣~

剩下的就是一些重複的資料了~

資料參考:
參考資料 1 :http://www.adobe.com/devnet/air/flex/quickstart/articles/update_framework.html
參考資料 2 http://help.adobe.com/zh_TW/air/build/WS9CD40F06-4DD7-4230-B56A-88AA27541A1E.html
參考資料 3 http://forums.adobe.com/message/3401427

2011年12月4日 星期日

[PHP] PHP 的多人聊天 Socket 伺服器


恩~為了幫我的 prueMVC 的作測試!
尋找多種不同 伺服器端是很重要的!
這次的目標是 Socket 伺服器

恩~不過這個有很多的問題~

第一個
遇上的就是 PHP 不支援的部分~
首先看 php 的 info
如果
Sockets Support enabled
這樣就 OK了~如果沒有
那請到 php.ini
去修改 extension=php_sockets.dll 把這個的# 用掉
這樣就可以成功的寫出 PHP的程式了

第二個
就是執行的問題
根據 因為是伺服器的關係~
不太建議大家使用 網頁去開~
特別是沒改限制時間的
比較建議使用 命令列的方式去開

像我在這會遇上一個問題就是
php_exif.dll 會說有問題 (或是 沒找到)
基本上~你只要修改一下順序就可以了
把 extension=php_exif.dll 移到
extension=php_mbstring.dll 的後面
重開一次 伺服器~
就可以正常執行了

3. 程式的部分!
因為我PHP只會一點點~
所以這邊 99% 都是照抄的
這個網站教PHP Socket 的部分我覺得蠻詳細的
一開始我都是照這個去建構~
基本上 只要照作範例是跑得起來的
不過會遇上防火牆的問題

4.
如果遇上防火牆的問題
這邊就是需要你把防火牆打開

怎樣判斷是否式防火牆的問題!
如果你 網址 PORT都設定正確~
伺服器也跑起來了
但是 你使用 CLIENT 沒有出現任何的回應
在你伺服器端的畫面上
那應該是防火牆的問題~

記得按照你寫的PROT 和 TCP UCP去開~
而且要開兩個~一個傳出 一個傳入~

5.
一個多人架構的 PHP 伺服器
PHP+Flex实现多人聊天(berrywu寫的)
他的這個 伺服器只能在 DEBUG的情況下使用
當然是以WEB的FLASH來說~
用AIR也是可以正常執行~不過要雙開有點麻煩~
然後這個在ADOBE中有一個範例 是解決安全性問題的SOCKET的策略
不過不記得網址了

我修改 (berrywu的) 伺服器 只要在他的
function readFromSocket( $clientId ){
中加入一段就可以解決
基本加完的結果如下


function readFromSocket( $clientId ){
   // start with empty string
   $data   = "";
   // 新增安全規則的部分!
   $buf2 = socket_read( $this->clientFD[$clientId], $this->readBufferSize );
   if(strpos($buf2,'policy-file-request')){
    $msg ="<cross-domain-policy><allow-access-from domain='*' to-ports='*' /></cross-domain-policy>";
socket_write($this->clientFD[$clientId], $msg."\0", strlen($msg."\0"));
}
   // read data from socket
   while( $buf = socket_read( $this->clientFD[$clientId], $this->readBufferSize ) ){
    $data .= $buf;

    $endString = substr( $buf, - strlen( $this->readEndCharacter ) );
    if( $endString == $this->readEndCharacter )
     break;
    if( $buf == NULL )
     break;
   }
   if( $buf === false ) $this->sendDebugMessage( "Could not read from client2 ".$clientId." ( ".$this->getLastSocketError( $this->clientFD[$clientId] )." )." );
   return $data;
}


好了到此算是完全結束~
當然你也可以使用 (berrywu的) 範例做一下試驗!
不過我等等來看看 zend 有沒有這方面的東東~
忘了一開始使就去查 orz

2011年12月3日 星期六

[AS3] zendAmf + PureMVC + flex 4.5的聊天室

先來來 看看效果巴
聊天室的原碼


這個放在空間上的是 單機板的!
所以不是即時的可以多人聊天版
我的改法是錯誤示範把 Proxy 中的 Delegate 的通通停掉
然後直接傳出事件
其實應該寫另外一個 Delegate 來作單機的
而不是像現在的方式~
直接寫在 Proxy 中!

然後我來講一下這個裡面我遇上的一些問題!

1. 中文問題
很久以前FLEX MX版的textInput有問題~
後來修正了~現在 S版的 textInput
也是一樣有中文的問題~
所以我打算找 MX的INPUT和S版的對照改
看看能不能解決~
但是我覺得這兩個 相差太多 我照改改出一些問題~
所以最後又改回 MX版的 不過這樣做有不少的問題~
MX和S版的 參數有差~本身對 RICHTEXT有差~~
基本上~我遇過 input的中文輸入問題 大概就下面這幾個
 a . 因為 HTML上的鑲入語法沒設成 windows 或是  transparent
 b. input有沒有 focus~沒有焦點不能換成中文輸入
 c. 沒有設 IME.enabled = true;
 d. 組件使用 s版的
這邊我是使用 MX版的組件~
配合HTML設成 windows  來解決這個問題

2.文字框置底問題
以前都是使用MX版的組件~
設置置底很簡單~都使用verticalScrollPosition
現在使用 S版的沒有這個屬性變得很麻煩
而且 S版的 textArea的組件 要設 verticalScrollPosition 和 verticalCenter 屬性~
使用 appendText 區增加文字~
會自動置底~
我是過直接將 文字給 組件的方式
但是這個方式不會置底喔

後來置換 SKIN的時候! 又遇上了置底的問題~
建議是換了後 過一小段時間
在執行appendText 就會置底了

3. 文字格式的問題
這個範例中 可以簡單的設 5種不同的屬性
大小 顏色 粗細 斜體 底線
恩~因為MX沒有 textFlow這個屬性..
最後看 官方文件 才知道怎樣做
我選擇的是 Creating a TextFlow object in ActionScript 的方法~
如果沒看到這個 我想我的做法應該還是回去老方式
使用 htmlText的方法去做~

4.換SKIN的方法~
本來我是想使用CSS的方式~或是換MC元件的方式
後來想到之前 Ticore 大大教的方法 (之前我要換官方的Alert的SKIN 不會換~)
所以就使用 MXML SKIN的方式去做~
基本上我設計不太行 所以我就基本的改了幾個屬性看看效果
像是 button 的部分我只有改框線的顏色
textArea 的部分 我就加了背景
如果仔細研究一下應該是可以加更多的地方
還有支援這樣換的 只有S版的 不過可能是因為介面的關係~
說不定仔細的GOOGLE一下 說不定可以找到兼容MX版的方式
我覺得兩個應該不會相差太大!

5. 表情符號的部分~雖然我有看到範例!
但是我沒辦法傳回 主機端處理在使用!
最重要原因是 一次傳輸裡面可以有多個表情符號!
傳到伺服器是沒問題!
但是伺服器的記錄和在使用的部分就麻煩了
最主要是我不想在建一個表然後JOIN
但是這邊我還沒想到好的方法~
基本上應該是存成文字檔 存進資料庫
然後 讀出來在解析成 ARRAY然後傳回去的方式
傳回的文字串和圖片位置的問題
而且這一塊 我是想要獨立出來 自己成一個 VIEW的方式去處理!

6. PHP 處理數據的問題~
本來想使用remote的方式可以減低PHP的連線數的
不過看起來好像是沒啥幫助!
不過也可能是SQL寫的太爛的關係
我在本機端測 1秒鐘 更新一次資料
兩個人同時連的情況~我的電腦 CPU 就會吃到100%...
就是因為這個原因~
讓我不敢放在主機上這種自動更新的即時機置