2013年9月17日 星期二

PullToRefresh

PullToRefresh 是作者製作的類別, 目的在Adobe AIR mobile 提供用戶下拉刷新動作, 建基於Feathers 的兩個元件(GroupedListList). 當用戶在目錄向下拉和放手, 會產生更新事件, 然後把目錄內容更新.

用戶把目錄向下拉 [範例]
   
用戶放手後, 目錄等待更新

以下是編寫的簡單步驟:

  1. 引入(Import) 相關的類別
    import feathers.controls.PullToRefreshList;
    import feathers.controls.List;
    
    
  2. 建立目錄內容
    var data:Array =
      [
        { text: "Aardvark" },
        { text: "Alligator" },
        { text: "Alpaca" },
        { text: "Anteater" },
      ];
    
    
  3. 建立目錄和添加事件監聽 (PULL_TO_REFRESH_EVENT)
    var list:List = new PullToRefreshList();
    list.dataProvider = new ListCollection(data);
    list.addEventListener(PullToRefreshList.PULL_TO_REFRESH_EVENT, listPullToRefreshHandler);
    this.addChild(list);
    
    
  4. 當用戶產生下拉刷新事件, 我們可以呼叫伺服器來更新目錄內容
    private function listPullToRefreshHandler(event:Event):void{
      ...
      // call server to return some data
      ...
    }
大家可以 [下載] 範例試試看.

2013年4月22日 星期一

PhysInjector 2D 物理引擎

PhysInjector 是一個基於Box2D 的物理引擎. 可以整合Starling 圖像引擎, 並透過Adobe AIR 發佈在iOS 和Android 系統運行.

請按 [觀看] 軌道重力Orbital Gravity 範例

若開發一個Angry Birds Space 遊戲, 我們可以使用這個軌道重力物理引擎喔.
作者在iPad2 進行測試, 並能順暢運行數個物件.

原生手機對話框 (Native Dialogs)

NativeDialogs 是一個提供原生手機對話框的外掛. 它在iOS 和Android 系統提供接口給Adobe AIR 呼叫. 當中包括NativeAlert, NativeProgress, NativeListDialog, NativeDatePickerDialog, Text input Dialog 和Toast 等對話框.

NativeDatePickerDialog 的介面

日期對話框NativeDatePickerDialog 的呼叫語句:
var d:NativeDatePickerDialog = new NativeDatePickerDialog();
d.displayMode = NativeDatePickerDialog.DISPLAY_MODE_DATE;
d.title = "DatePicker";
d.message = "Select date:";
d.date = new Date();
d.show();

大家可以 [下載] 範例試試看, 作者在Flash Builder 設定NativeDialogs_AS.swcNativeDialogs.ane 外掛的路徑和關掉一些問題.

2013年4月17日 星期三

在iOS 背景運行Adobe AIR

作者發現在iOS 運行NetConnection 網路連結, 關閉螢幕後再啟動, 會產生錯誤導致程序崩潰. 這個錯誤不能以Try、Catch、Finally 捕捉錯誤事件. 我們必需在發佈的xml 檔案中, 加入以下設定來解決:

<iPhone>
    <InfoAdditions>
        <![CDATA[
            <key>UIApplicationExitsOnSuspend</key>
            <true/>
        ]]>
    </InfoAdditions>
</iPhone>

除了網路連結外, 在背景運行音樂和位置更新相關設定, 可以參考這個連結.

2013年1月28日 星期一

找不到iOS 裝置

作者在Windows 環境下, 使用Flash Builder 4.7 或Flash Professional CS6, 透過USB 連接iOS 裝置進行除錯發佈測試, 結果找不到任何iOS 裝置連接:

Flash Builder could not find a connected device.

以下是者作的電腦配置:
  • Windows 7 64 bit
  • iPad2 iOS 6.0
  • Flash Builder 4.7 或Flash Professional CS6 (Version 12.0.2.529) 更新請參考
  • Adobe AIR SDK 3.6
  • iTunes 11.0.1.12

在Goolge 找尋下, 發現一個方法可以暫時解決這個問題:
  1. C:\Program Files (x86)\Common Files\Apple\Apple Application Support\ 路徑, 找到SQLite3.dll
  2. SQLite3.dll 檔製至C:\Program Files\Adobe\Adobe Flash Builder 4.7 (64 Bit)\eclipse\plugins\com.adobe.flash.compiler_4.7.0.XXXXXX\AIRSDK\lib\aot\bin\iOSBin\

其實這個問題, 不是每個電腦會發生, 者作朋友的電腦在相同配置條件下, 亦不會遇上. 相信與電腦內曾安裝SQLite 軟件有關係.


後記:
對Flash Professional CS6 的用戶, 解決方法與Flash Builder 相似, 設定Adobe AIR SDK 請參考.

2013年1月17日 星期四

P2P 指令同步播放影片

作者製作一個處理Peer-to-peer(P2P) 的物件(P2PCore), 它透過Action Script 原生的NetConnectionNetGroup, 簡單地傳送文字, 圖像或物件, 達成點對點資料傳送.


以下為大家介紹, 如何利用P2P 技術, 在iPad 與PC 之間同步播放影片: 
  1. 建立P2PCore 物件, 為它加入監聽事件:
    var _core:P2PCore = new P2PCore();
    _core.addEventListener(P2PEvent.LOAD,loadHandler);
    _core.addEventListener(P2PEvent.MESSAGE, messageHandler);
    

  2. 當P2PCore 連接成功, 為用戶介面加入監聽事件:
    function loadHandler(event:P2PEvent):void{
      scaleX1Btn.addEventListener(MouseEvent.CLICK, scaleX1ClickHandler);
      scaleX2Btn.addEventListener(MouseEvent.CLICK, scaleX2ClickHandler);
      video.addEventListener("stateChange", playheadUpdateHandler);
    }
    

  3. 當按下Scale x1 或Scale x2 按鈕, 透過P2PCore 廣播給所有裝置改變影片大小:
    function scaleX1ClickHandler(event:MouseEvent):void{
      video.setScale(1, 1);
      _core.sendObject({type:"setScale", value:1});
    }
    function scaleX2ClickHandler(event:MouseEvent):void{
      video.setScale(2, 2);
      _core.sendObject({type:"setScale", value:2});
    }
    

  4. 當改變影片播放位置, 透過P2PCore 廣播給所有裝置最新播放位置:
    function playheadUpdateHandler(event:Event):void{
      _core.sendObject({type:"playheadTime", value:video.playheadTime.toString()});
      video.play();
    }
    

  5. 若裝置接收廣播訊息, 改變影片大小或播放位置:
    function messageHandler(event:P2PEvent):void{
      var msg:P2PMessage = event.value as P2PMessage;
      switch(msg.data.type){
        case "setScale":
          video.setScale(msg.data.value, msg.data.value);
        break;
        case "playheadTime":
          // <----- only allow one controller
          video.removeEventListener("stateChange", playheadUpdateHandler);
          
          video.playheadTime = parseFloat(msg.data.value);
          video.play();
        break;
      }
    }
這個實例主要運用發出和接收指令, 達到影片同步播放功能, WiFi 穩定性會直接影響iPad 與PC 之間的同步效果. 若希望製作串流影片, 請參考這個連結.

大家可以 [下載] 範例試試看.

注意事項:
 - 在Flash Professional CS6 透過USB 連接iOS 安裝發佈請參考這個連結.
 - Flash Media Server 我們可以申請Adobe 公開伺服器 (rtmfp://stratus.adobe.com/) 作試驗或自行架設.

2013年1月10日 星期四

Flash Professional CS6 透過USB 連接iOS 安裝發佈

在Flash Professional CS6 版本12.0.2.529 中, 我們可以透過USB 連接iOS 裝置, 進行實機測試. 在Windows 或MAC OS X 平台兩者皆可, 過程無需透過iTunes 或越獄(Jailbreak) 後的iOS 裝置, 純粹USB 連接, 十分方便.

以下是更新Flash Professional CS6 和連接iOS 發佈方法:
  1. 在官方下載最新Flash Professional CS6 更新:

  2. 安裝完成後, 在Help -> Aboout Adobe Flash Professional 看到新版本編號 (12.0.2.529).

  3. 下載Adobe AIR SDK, 然後設定路徑. (設定方法請參考)

  4. 開啟一個AIR for iOS  新專案.

  5. 設定發佈對象為AIR 3.4 for iOS 或以上版本.

  6. AIR for iOS Settings -> Deployment 中, 選擇以USB 連接iOS 裝置進行實機測試.
    (Install application on the connected iOS device)


注意事項:
若曾經修改host 檔案, 在更新過程會發生錯誤訊息, 請把host 檔案暫時回復, 待更新完成後才可修改.
(host 檔案路徑: C:\Windows\System32\drivers\etc\host)

2012年10月17日 星期三

Adobe AIR 與Push Notifications

為大家介紹Adobe AIR 原生支援的Push Notifications 功能, 配合apns-php 伺服器發出訊息給iOS 裝置.

簡單測試需要的準備:
  • Adobe AIR 3.4 或以上SDK (安裝SDK 於Flash Builder 請參考)
  • 一個iOS 裝置 (不能以XCode Simulator 來取代)
  • 需要.p12, .mobileprovision 與.pem 檔 (製作包含Push Notifications 功能請參考)
  • 一個執行Push Notification Provider 的伺服器, 我們可以使用apns-php


Push Notifications 的運作原理:

  • 使用Adobe AIR 提供的介面(RemoteNotifier) 並執行訂閱(subscribe), 取得一個Device Token (這是每個iOS 裝置獨一無異的記號)
  • 把Device Token 提交給伺服器記下
  • 利用Push Notification Provider 發放訊息給這些Device Token
  • 這個iOS 裝置會收到Push Notification
Push Notifications 基本工作流程


Adobe AIR 提供以下三種Push Notification 提示:
  • NotificationStyle.ALERT - 在收到通知時顯示警告方塊的通知
  • NotificationStyle.BADGE - 收到通知時會以數字/影像更新應用程式圖示的通知
  • NotificationStyle.SOUND - 在收到通知時播放聲音的通知
Adobe AIR 在iOS 接收Push Notifications

在Adobe AIR 程式編寫, 提供一個按鈕給用戶按下(clickHandler), 取得iOS 裝置的Device Token:
private function clickHandler(event:MouseEvent):void{
  trace("clickHandler: " + RemoteNotifier.supportedNotificationStyles.length);
  myTxt.appendText("clickHandler: " + RemoteNotifier.supportedNotificationStyles.length+"\n");
  
  if ( RemoteNotifier.supportedNotificationStyles.length > 0)
  {
    var preferredNotificationStyles:Vector.<string> = new Vector.<string>;
    
    preferredNotificationStyles.push(NotificationStyle.ALERT);
    preferredNotificationStyles.push(NotificationStyle.SOUND);
    preferredNotificationStyles.push(NotificationStyle.BADGE);
    
    var subscribeOptions:RemoteNotifierSubscribeOptions = new RemoteNotifierSubscribeOptions();
    subscribeOptions.notificationStyles = preferredNotificationStyles;
    
    rn = new RemoteNotifier();
    
    rn.addEventListener(RemoteNotificationEvent.TOKEN, sendDeviceTokenToServer);
    rn.addEventListener(StatusEvent.STATUS, subscriptionFailureCallback);
    
    rn.subscribe(subscribeOptions);
  }
}
protected function subscriptionFailureCallback(event:StatusEvent):void
{
  trace("Received Status event for registrationFailure with code:" + event.code + " and level:" + event.level + "\n");
  myTxt.appendText("Received Status event for registrationFailure with code:" + event.code + " and level:" + event.level + "\n");
}
protected function sendDeviceTokenToServer(event:RemoteNotificationEvent):void
{
  trace("Received " + event.type + " with tokenString:" + event.tokenId + "\n");
  myTxt.appendText("Received " + event.type + " with tokenString:" + event.tokenId + "\n");
}

在Adobe AIR 程式發佈設定:
  • Certificate 和Provisioning file 需要使用包含Push Notifications 功能的.p12 和 .mobileprovision 檔
  • 在XML 設定檔加入Entitlements 設定:
    <iPhone>
      <Entitlements><![CDATA[
        <key>get-task-allow</key>
        <true/>
        <key>aps-environment</key>
        <string>development</string>
        <key>keychain-access-groups</key>
        <array>
          <string>KEYCHAIN_ACCESS_GROUP</string>
        </array>
      ]]></Entitlements>
    </iPhone>
  • 在Flex Compiler > Additional compilder arguments: 更改成:
    -locale en_US -swf-version=17

架設apns-php 伺服器後, 我們更改sample_push.php 的內容作為發訊測試:
  • 更改.pem 檔名稱, 並把.pem 檔案複製至與sample_push.php 同一資料夾內
  • 加入iOS 裝置的Device Token
更改sample_push.php 內容

當執行sample_push.php 後, 測試對像的iOS 裝置會接收到Push Notification. 大家可以 [下載] 範例試試看.

參考資料: http://blogs.adobe.com/airodynamics/2012/05/29/push-notifications-support-in-ios/

2012年10月16日 星期二

製作p12, mobileprovision 與pem

製作p12 :  認證檔 iOS Certificate (包含Push Notifications 功能)
  1. 進入iOS Provisioning Portal, 在App IDsNew App ID

  2. 輸入新增程式的名稱 (NameApp ID)

  3. 找尋新增的程式, 按下Configure

  4. 啟動Enable for Apple Push Notification service, 並在Development Push SSL Certificate 按下Configure

  5. 然後按指示, 在MAC OS X 的Utilities 開啟Keychain Access, 選擇:
    Keychain > Certificate > Assistant > Request a Certificate from a Certificate Authority

  6. 產生一個csr 檔, 並儲存於桌面上

  7. 把桌面上的csr 檔上載給iOS Provisioning Portal 處理

  8. 處理完成後, 會產生一個cer 檔, 把它下載至桌面

  9. 在桌面執行cer 檔後, 在Keychain Access 會新增一個Certificate

  10. 在新增的Certificate 右按Export 產生p12 檔


製作mobileprovision :  描述檔 Provisioning Profile
  1. ProvisioningDistribution 選擇New Profile

  2. 輸入Profile Name 等資料

  3. 手動更新iOS Provisioning Portal 網頁(數秒時間便可), 直至新增的項目提供mobileprovision 檔下載按鈕


製作pem :  數位憑證 Push Certificate
  1. 開啟MAC OS X 的Terminal, 移至儲存p12 檔的桌面位置: (請更改為正確路徑)
    cd /Users/YOUR_USER_NAME/Desktop/
  2. 然後輸入以下指令產生pem 檔:
    openssl pkcs12 -in Certificates.p12 -out server_certificates_bundle_sandbox.pem -nodes -clcerts

若大家沒有開發者帳號, 可考慮暫時使用假認證檔(p12) 和描述檔(mobileprovision) 作測試. 待日後正式發佈時, 才購買開發者帳號.

2012年10月10日 星期三

as3dpad 操控桿介紹

as3dpad 是作者製作的一個類別庫, 目的在Adobe AIR mobile 提供一個虛擬操控桿, 於iOS 和Android 等流動裝置運作, 為遊戲提供一個輸入方法.

配合Starling 的 [範例] (請以鍵盤WASDm, 操控)

as3dpad 渲染部分參考SpriteSheetClip 的手法, 所以在stage3d 之上有效運作, 與Starling 等框架相容.
另外, 類別庫提供以鍵盤代替螢幕輸入(WASDm,), 給開發人員在電腦直接測試遊戲.

弧度(radians) 表示操控桿位置

以下是編寫的簡單步驟:
  1. 建立DPad 物件
    var dPad:DPad = new DPad();
    this.addChild(dPad);
    
  2. 接收X 軸與Y 軸回傳的數據
    dPad.leftPad.addEventListener(DPadEvent.TOUCH_PRESS, touchPressHandler);
    dPad.leftPad.addEventListener(DPadEvent.TOUCH_RELEASE, touchReleaseHandler);
    
    private function touchPressHandler(event:DPadEvent):void{
      var axisPad:AxisPad = event.target as AxisPad;
      trace("radians: " + axisPad.radians);
      trace("distance: " + axisPad.distance + "/" + axisPad.maxDistance);
      trace("press left:  " + (axisPad.value & AxisPad.LEFT));
      trace("press right: " + (axisPad.value & AxisPad.RIGHT));
      trace("press up:    " + (axisPad.value & AxisPad.UP));
      trace("press down:  " + (axisPad.value & AxisPad.DOWN));
    }
    private function touchReleaseHandler(event:DPadEvent):void{
      ...
    }
    
  3. 接收A 和B 按鈕回傳的數據
    dPad.rightPad.addEventListener(DPadEvent.TOUCH_PRESS_A, touchPressAHandler);
    dPad.rightPad.addEventListener(DPadEvent.TOUCH_PRESS_B, touchPressBHandler);
    dPad.rightPad.addEventListener(DPadEvent.TOUCH_RELEASE_A, touchReleaseAHandler);
    dPad.rightPad.addEventListener(DPadEvent.TOUCH_RELEASE_B, touchReleaseBHandler);
    
    private function touchPressAHandler(event:DPadEvent):void{
      var groupPad:GroupPad = event.target as GroupPad;
      trace("press A: " + (groupPad.value & GroupPad.A_BUTTON));
      trace("press B: " + (groupPad.value & GroupPad.B_BUTTON));
    }
    private function touchPressBHandler(event:DPadEvent):void{
        ...
    }
    private function touchReleaseAHandler(event:DPadEvent):void{
        ...
    }
    private function touchReleaseBHandler(event:DPadEvent):void{
        ...
    }

類別庫提供以下範例參考:
  • example01_basic - 基本用法 [demo]
  • example02_custom_UI - 自定介面 [demo]
  • example03_double_AxisPad - 雙操控桿 [demo]
  • example04_touch9Grid - 螢幕九格觸控 [demo]
  • example05_starling - 配合Starling [demo]

Launch Examples Launch Examples Launch Examples Launch Examples Launch Examples

大家可以 [下載] 範例試試看.

2012年9月26日 星期三

[教學] Panorama 全景圖實作

日本的Spark project 為Action Script 開發人員提供大量程式庫. 其中AlternativaTemplate 編寫的Camera 操作控制, 能簡單實作全景圖, 並透過Alternativa3D 運行Stage3D 硬體加速顯示.

請按 [觀看] 範例

以下是編寫的步驟:

  1. 建立一個新類別並繼承AlternativaTemplate 類別
  2. 設定CameraCameraType.PANORAMA 模式
  3. 設定紋理材料(TextureMaterial) 為內嵌的全景圖像(assets/test1.jpg)
  4. 建立一個幾何球體(GeoSphere) 並貼上紋理材料
package
{
  import alternativa.engine3d.materials.TextureMaterial;
  import alternativa.engine3d.primitives.GeoSphere;
  import alternativa.engine3d.resources.BitmapTextureResource;
  
  import org.libspark.alternativa3d.camera.CameraType;
  import org.libspark.alternativa3d.view.AlternativaTemplate;
  
  [SWF(backgroundColor="#000000", frameRate="60", quality="LOW", width="800", height="480")]
  public class Alternativa_Panorama extends AlternativaTemplate
  {
    [Embed(source = "assets/test1.jpg")]
    private static var ImageCls:Class;
    
    public function Alternativa_Panorama():void{
      super({
        cameraType:CameraType.PANORAMA,
        useDiagram : true
      });
    }
    override protected function atInit():void{
      var material:TextureMaterial = new TextureMaterial(new BitmapTextureResource(new ImageCls().bitmapData));
      var shpere:GeoSphere = new GeoSphere(100, 32, true, material);
      scene.addChild(shpere);
    }
  }
} 
在Android 和iOS 運作正常, 大家可以 [下載] 範例試試看.

參考資料: http://clockmaker.jp/blog-en/2011/11/alternativa3d-panorama/

2012年9月24日 星期一

SpriteSheetClip 的高效能渲染

關於2D 渲染部分, 我們大多選擇以Stage3D 為基礎的Starling 圖像引擎, 其效能必然是最好. 若大家希望簡單製作, 又要求達到一個理想的渲染效果, SpriteSheetClip 相信是個好選擇, 它比傳統MovieClip 效能高很多.


SpriteSheetClip 運作原理十分簡單, 它是繼承Bitmap 類別, 建立時記錄Sprite Sheet 的內容. 當播放時更換相對的BitmapData 內容, 達到連續播放效果.

請按 [觀看] 範例
以下是使用方法:
  1. 準備一份Sprite Sheet 格式檔案的PNG 與JSON:
    [Embed("assets/Animation.png")]
    public var AnimationImage:Class;
     
    [Embed("assets/Animation.json", mimeType="application/octet-stream")]
    public var AnimationData:Class;
    

  2. 透過SpriteSheetClip 產生實體:
    var mc:SpriteSheetClip = new SpriteSheetClip(AnimationImage, AnimationData);
    mc.gotoAndPlay("someLabel");
    this.addChild(mc);
    

  3. 設定實體位置(x, y), 縮放(scaleX, scaleY), 旋轉(rotation) 或透明度(alpha):
    mc.x = 10;
    mc.y = 10;
    mc.scaleX = 0.5;
    mc.scaleY = 0.5;
    mc.rotation = 90;
    mc.alpha = 0.8;
    

  4. Event.ENTER_FRAME 呼叫step() 功能, 手動觸發播放:
    this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    ...
    function onEnterFrame(event:Event):void {
          mc.step();
    }

在沒有Stage3D 硬體加速幫助下, 純粹更換BitmapData 能給出高效能渲染, 這個既簡單又實用的手法, 確實令人驚訝喔.

參考資料: http://blog.domlib.com/articles/291

後記:
由於SpriteSheetClip 依賴Zoe 產生相關的PNG 與JSON. 若Zoe 產生內容有所更改, SpriteSheetClip 需要作出相應的改動, 它們之間沒有統一的標準.

2012年9月21日 星期五

[教學] AIRKinect 的魔法帽子

Kinect 與Flash 的連接, 我們透過AIRKinect (安裝參考)簡單地完成. 以下為大家介紹魔法帽子範例, 當一個人走進Kinect 範圍, 在螢幕為她蓋上一個魔法帽子.


  1. 在程序啟動時, 對AIRKinect 物件加入三個事件監聽器:
      CameraImageEvent.RGB_IMAGE_UPDATE - 影像每次更新產生的事件
      UserEvent.USERS_WITH_SKELETON_ADDED - 發現一個新骨架時事件
      UserEvent.USERS_WITH_SKELETON_ADDED - 骨架離開Kinect 事件
    if (Kinect.isSupported()) {
      // <----- get Kinect instance
      _device = Kinect.getDevice();
      
      // <----- add listener for Kinect
      _device.addEventListener(CameraImageEvent.RGB_IMAGE_UPDATE, rgbImageUpdateHandler, false, 0, true);
      _device.addEventListener(UserEvent.USERS_WITH_SKELETON_ADDED, skeletonsAddedHandler, false, 0, true);
      _device.addEventListener(UserEvent.USERS_WITH_SKELETON_REMOVED, skeletonsRemovedHandler, false, 0, true);
      
      ...
      
      // <----- start the Kinect
      _device.start(settings);
    }
    

  2. 當發現一個新骨架, 我們建立一個帽子MovieClip, 產生魔法效果:

    帽子(_Hat1) 魔法效果是由Flash IDE 的時間軸製作
    ...
    [Embed(source="assets/hat1.swf")]
    private var _Hat1:Class;
    ...
    private function skeletonsAddedHandler(event:UserEvent):void{
      for each(var addedUser:User in event.users){
        var sprite:Sprite = new Sprite();
        var head:SkeletonJoint = addedUser.getJointByName("head");
        var headRGB:Point = head.position.rgb;
        sprite.name = addedUser.trackingID.toString();
        sprite.x = headRGB.x;
        sprite.y = headRGB.y;
        
        // <----- add the MovieClip to stage
        sprite.addChild(new _Hat1() as MovieClip);
        _sprites.push(sprite);
        this.addChild(sprite);
      }
    }
    

  3. 若骨架離開Kinect, 把相對於這個骨架的帽子刪除:
    private function skeletonsRemovedHandler(event:UserEvent):void{
      for each(var removedUser:User in event.users){
        for(var i:int=0; i<_sprites.length; i++){
          var id:String = removedUser.trackingID.toString();
          if(_sprites[i].name==id){
            this.removeChild(_sprites[i]);
            _sprites.splice(i, 1);
          }
        }
      }
    }
    

  4. 影像每次更新時, 追蹤每個骨架頭部(head) 和頸部(neck) 關節位置, 計算兩者距離來決定帽子大小, 並利用TweenLite 把帽子移至頭部:

    Kinect 關節名稱
    private function rgbImageUpdateHandler(event:CameraImageEvent):void{
      // <----- get Kinect RGB Camera image to display
      _bitmapData.draw(event.imageData);
      
      for each(var user:User in _device.users) {
        if (user.hasSkeleton) {
          var head:SkeletonJoint = user.getJointByName("head");
          var neck:SkeletonJoint = user.getJointByName("neck");
          var headRGB:Point = head.position.rgb;
          var neckRGB:Point = neck.position.rgb;
          var diff:Number = Math.abs(neckRGB.y - headRGB.y);
          var diffBase:Number = 50;
          var scale:Number = diff/diffBase;
          var id:String = user.trackingID.toString();
          
          // <----- find the MovieClip
          for(var i:int=0; i<_sprites.length; i++){
            if(_sprites[i].name==id){
              // <----- change the MovieClip position
              TweenLite.to(_sprites[i], 0.1, {x:headRGB.x, y:headRGB.y, scaleX:scale, scaleY:scale});
              break;
            }
          }
        }
      }
    }
    
大家可以 [下載] 範例試試看.

後記:
微軟推出的Kinect 硬體在不同的版本, 是有不同的支援上限:
Kinect for Xbox 360 是由2009 年6 月份推出, 支援追蹤兩組骨架, 解像度640x480 @30Hz.
Kinect for Windows 是由2012 年2 月份推出, 支援追蹤四組骨架, 解像度1280x960 @30Hz.

2012年9月12日 星期三

[教學] 原生OpenCV 編譯C++ 成SWC 庫

研究Augmented Reality 的朋友, 相信對OpenCV (Open Source Computer Vision Library) 有一定認識. 她是由英特爾(Intel) 公司發起並參與開發, 以BSD 許可證授權發行, 可以在商業和研究領域中免費使用. 我們可用於開發實時的圖像處理, 計算機視覺以及模式識別程序.

wouter 編譯的OpenCV SWC 庫, 能透過讀取Cascade XML檔案辨認不同物件

現在為大家介紹如何在MAC OS X 中, 透過Adobe Alchemy (安裝參考) 編譯原生OpenCV:
  1. 我們到bonext 下載已整理的OpenCV 包. (OpenCV2.2.0 版本)
  2. 把bonext 解壓並存於/Library/bonext/ 路徑上.
  3. 在Terminal 中, 分別進入以下五個路徑:
    cd /Library/bonext/src/opencv/calib3d/
    cd /Library/bonext/src/opencv/contrib/
    cd /Library/bonext/src/opencv/core/
    cd /Library/bonext/src/opencv/imgproc/
    cd /Library/bonext/src/opencv/objdetect/

    並在每個路徑請輸入以下指命進行編譯:
    repo_root=/Library/bonext/;
    alc-on; rm -rdf log ; rm -f *.o; mkdir log ; for src in *.cpp ; do g++ -I$repo_root/include -DOSX -c -Wall -O3 -o ${PWD##*/}_`basename $src .cpp`.o $src 2> `basename $src .cpp`.log ; done ; mv -v *.log ./log ; alc-off; for f in ./log/*.log ; do grep 'error' $f ; done | cat | sort -u > ./log/errors.log ; less ./log/errors.log
  4. 若編譯正確, 會在每一個路徑找到多個.o 檔案. 把它們移至/Library/bonext/flash/ 路徑上.
  5. 根據bonext 者作提示, 我們需要刪除core_system.o 檔案.
  6. 最後, 在/Library/bonext/flash/ 路徑, 輸入以下指命編譯成.swc 檔案:
    rm *achacks* *.swc ; alc-on; g++ -swc -Wall -O3 -DOSX -I../include -o camlib.swc *.o camlib.cpp ; alc-off;
我們透過Adobe Alchermy 成功產生swc 元件, 在Flash Builder 設定swc 路徑後, 便可以使用:
package
{
  import flash.display.Sprite;
  import cmodule.camlib.CLibInit;
  
  public class Bonext_WebCam extends Sprite
  {
    private var lib:Object;
    ...
    public function setupCLib():void
    {
      ...
      // <----- create a library instance from swc
      var loader:CLibInit = new CLibInit;
      lib = loader.init();
      ...
    }
    ...
    public function enterFrameHandler(event:Event):void
    {
      ...
      // <----- call a method from swc
      var outPixels:ByteArray = lib.setFramePtr(pixels,pixels.length);
      ...
    }
    ...
  }
}

在bonext 的作者純粹示範呼叫OpenCV 使影像變成灰色. 當然我們可以修改camlib.cpp 檔案, 加入相對的函數給Action Script 調用, 發揮OpenCV 的強大功能. 大家可以 [下載] 範例試試看.

2012年9月7日 星期五

AIRKinect 怪獸

AIRKinect 配合Away3D 可以製作很多有趣事, 我們把Away3D 當中的怪獸, 配合AIRKinect 的骨架移動3D 模型, 怪獸起動來喔~~~



只要修改AIRKinect 內建範例, 把關節名稱對應為Away3D 怪獸範例的模型:
var jointMapping:Vector.<Number> = Vector.<Number>([
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("head"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("neck"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("waist"),
  
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("luparm"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("lloarm"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("lhand"),
  
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("ruparm"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("rloarm"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("rhand"),
  
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("lupleg"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("lloleg"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("lfoot"),
  
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("rupleg"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("rloleg"),
  (mesh.animationState.animation as SkeletonAnimation).skeleton.jointIndexFromName("rfoot")
]);

大家可以 [下載] 範例試試看.

2012年9月4日 星期二

Beyond Reality Face 臉部偵測引擊

Beyond Reality Face 是一個臉部偵測引擊, 能夠實時偵測臉部輪廓. 她們提供SDK 免費下載和測試, 若開發人員於商業用途, 需要購買許可證. 雖然不是完全免費, 但作為Augmented Reality 引擊, 她是一個不錯的參考.

請按 [觀看] 範例 (需要Web Camera)

識別臉部的位置

者作把Beyond Reality Face 範例整理, 發現十分有趣, 大家可以 [下載] 範例試試看.

2012年9月2日 星期日

foxhole 元件

foxhole 是一個以Starling Framework 為基礎的元件庫, 與MadComponents 性質十分相似, 它們都是以Stage3D 技術, 在iOS 或Android 中流暢操作的UI 框架.

請按 [觀看] Layout Explorer 範例

請按 [觀看] Gallery 範例

請按 [觀看] Tile List 範例

foxhole 主要透過程式編寫來決定元件的位置與關係. 與MadComponents 的XML 設定有所不同.

API 參考: http://flashtoolbox.com/foxhole-starling/documentation/

2012年8月30日 星期四

[教學] 安裝Adobe Alchemy 在MAC OS X

Adobe 在2009 年的研究項目中, 曾經被喻為劃時代的Adobe Alchemy, 開發者以C/C++ 編寫核心, 給ActionScript 調用, 達至加速效果. 回到今天運作平台分裂嚴重, 對我們現在Windows, MAC, Android 及iOS 同樣可以分享, 當年這個技術實在意義重大.

Adobe Alchemy 基於LLVM 技術運行

現在為大家說明如何在MAC OS X 環境中, 運用Adobe Alchemy 編譯C/C++ 語言, 包裝給ActionScript 調用.

必須有以下的準備:

安裝步聚:
  1. 把Flash Builder 內的SDK bin 目錄設定為MAC OS X 的PATH 環境變數(PATH Environment Variables)
     - 打開.bash_profile 檔案, 在Terminal 輸入:
          touch ~/.bash_profile; open ~/.bash_profile
     - 在TextEdit 中, 把空白的.bash_profile 檔案更改成:
         (請把Adobe Flash Builder 4.6/4.6.0_AIR3.4 更改成正確路徑)
          PATH="$PATH:/Applications/Adobe Flash Builder 4.6/sdks/4.6.0_AIR3.4/bin"
          export PATH

     - 在TextEdit 中把.bash_profile 檔案儲存(Command+S)
     - 然後在Terminal 輸入:
          source ~/.bash_profile
    - 關閉Terminal (Command+Q)
  2. 測試是否設定正確, 重新開啟Terminal, 然後輸入:
      adt -version
    若步聚正確, 會顯示SDK 版本代號"3.4.0.3010"
  3. 把下載的Alchemy Toolkit Package 解壓存放於/Library/alchemy/
  4. 把游漂移至alchemy 目錄內, 在Terminal 輸入:
      cd /Library/alchemy
  5. 執行alchemy 目錄內的config, 在Terminal 輸入:
      ./config
  6. 在PATH 環境變數加入alchemy 相關資料:
     - 再次打開.bash_profile 檔案, 在Terminal 輸入:
          touch ~/.bash_profile; open ~/.bash_profile
     - 在TextEdit 中, 把.bash_profile 檔案更改成:
         source "/Library/alchemy/alchemy-setup"
         PATH="$PATH:/Applications/Adobe Flash Builder 4.6/sdks/4.6.0_AIR3.4/bin"
         PATH="$PATH:/Library/alchemy/achacks"
         export PATH

     - 在TextEdit 中把.bash_profile 檔案儲存(Command+S)
     - 然後在Terminal 輸入:
          source ~/.bash_profile
     - 關閉Terminal (Command+Q)
  7. 重新開啟Terminal, 分別輸入:
      alc-on

      gcc
    以上兩個指令, 不會出現"command not found" 錯誤訊息, 代表設定完成

範例編譯:

  1. 把游漂移至alchemy/samples/stringecho/ 目錄內, 在Terminal 輸入:
      cd /Library/alchemy/samples/stringecho/
  2. 在Terminal 輸入:
      alc-on; which gcc
    以上指令會顯示出gcc 路徑"/Library/alchemy/achacks/gcc"
  3. 把c 語言編譯成swc 元件, 在Terminal 輸入:
      gcc stringecho.c -O3 -Wall -swc -o stringecho.swc
  4. 若元件正確產生, 在Terminal 會顯示以下訊息: (若發生錯誤, 請看編譯錯誤修正)
    1911.achacks.swf, 259831 bytes written
    frame rate: 60
    frame count: 1
    69 : 4
    72 : 259761
    76 : 33
    1 : 0
    0 : 0
    frame rate: 24
    frame count: 1
    69 : 4
    77 : 506
    64 : 31
    63 : 16
    65 : 4
    9 : 3
    41 : 26
    82 : 471
    1 : 0
    0 : 0
      adding: catalog.xml (deflated 75%)
      adding: library.swf (deflated 70%)

編譯錯誤修正:

修正一
  • 若在編譯時, 出現以下錯誤:
    Array @ARGV missing the @ in argument 1 of shift() at /Library/alchemy/achacks/gcc line 218.
    我們需以在/Library/alchemy/achacks 的gcc 檔案的218 行, 加入"@"字元, 請更改成:
    { $path = shift(@ARGV) }

修正二
  • 若在編譯時, 出現以下錯誤:
    dyld: Library not loaded: /usr/lib/libltdl.3.dylib
      Referenced from: /Library/alchemy/bin/llvm-gcc
      Reason: image not found

    我們需要把游漂移至/usr/lib/ 目錄內, 在Terminal 輸入:
      cd /usr/lib/
    然後再在Terminal 輸入:
      sudo ln -s libltdl.7.dylib libltdl.3.dylib

使用swc 元件:

我們透過Adobe Alchermy 成功產生swc 元件, 在Flash Builder 設定swc 路徑後, 便可以使用:
package
{
  import flash.display.Sprite;
  import cmodule.stringecho.CLibInit;
  
  public class stringecho_mobile extends Sprite
  {
    public function stringecho_mobile()
    {
      var loader:CLibInit = new CLibInit;
      var lib:Object = loader.init();
      trace(lib.echo("foo"));
    }
  }
}

大家若在Windows 環境下安裝Alchemy, 請參考這個連結, 安裝原理與MAC 很相近.

Alchermy 安裝參考:
http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Getting_Started
更改PATH 環境變數參考:
http://hathaway.cc/2008/06/how-to-edit-your-path-environment-variables-on-mac-os-x/
編譯錯誤修正參考:
http://forums.adobe.com/message/3892045