2013年3月29日金曜日

Feathers PopUpManager サンプル

PopUpManagerクラスのAPIDocumentは(リンク先へ)

実用例の動画です。

PopUpManagerはFlexにもありましたが、使用方法もほぼ一緒です。

PopUpManagerクラスを利用してみます。

PopupWindowコンポーネント

使用クラス
  protected var theme:MetalWorksMobileTheme;
  private var popUpWindow:PopUpWindow;

  private function doPopUpWindow():void
  {
   this.theme = new MetalWorksMobileTheme(this.stage);

   popUpWindow = new PopUpWindow();
   popUpWindow.addEventListener(PopUpWindow.WINDOW_CLOSE,popUpWindowCloseHandler);
   popUpWindow.width = 320;
   popUpWindow.height = 240;

   PopUpManager.addPopUp(popUpWindow);
  }

  private function popUpWindowCloseHandler(event:Event):void
  {
   PopUpManager.removePopUp(popUpWindow);
   popUpWindow.dispose();
  }

PopUpWindow.as
package controls
{
 import feathers.controls.Button;
 import feathers.core.FeathersControl;
 import feathers.display.Scale9Image;
 import feathers.textures.Scale9Textures;

 import flash.geom.Rectangle;

 import starling.animation.Transitions;
 import starling.core.Starling;
 import starling.events.Event;
 import starling.textures.Texture;

 public class PopUpWindow extends FeathersControl
 {
  [Embed(source="./assets/scale9.png")]
  private static const SCALE_9_TEXTURE:Class;

  public static const WINDOW_CLOSE:String = "windowClose";

  public function PopUpWindow()
  {
   super();
  }

  private var okButton:Button;
  private var bg:Scale9Image;

  override protected function initialize():void
  {
   var texture:Texture = Texture.fromBitmap(new SCALE_9_TEXTURE(), false);
   var textures:Scale9Textures = new Scale9Textures(texture,new Rectangle(20, 20, 20, 20));

   bg = new Scale9Image(textures, 1);
   bg.width = width;
   bg.height = height;
   bg.x = bg.pivotX = width >> 1;
   bg.y = bg.pivotY = height >> 1;
   addChild(bg);

   okButton = new Button();
   okButton.label = "Ok";
   okButton.width = 100;
   okButton.height = 48
   addChild(okButton);
   okButton.x = (bg.width >> 1) - (okButton.width >> 1);
   okButton.y = (bg.height >> 1) - (okButton.height >> 1);
   okButton.addEventListener(Event.TRIGGERED, button_triggeredHandler);

   Starling.juggler.tween(bg, 1,
    {
     transition: Transitions.EASE_OUT_BOUNCE,
     onStart:tweenStartHandler,
     onComplete:tweenCompleteHandler,
     scaleX: 1,
     scaleY: 1
    });
  }

  private function button_triggeredHandler(event:Event):void
  {
   dispatchEventWith(WINDOW_CLOSE);            
  }

  private function tweenStartHandler():void
  {
   okButton.visible = false;
   bg.scaleX = 0;
   bg.scaleY = 0;
  }

  private function tweenCompleteHandler():void
  {
   okButton.visible = true;
  }

  override public function dispose():void
  {
   bg.dispose();
   okButton.dispose();
   removeChildren();

   super.dispose();
  }

 }
}
Windowで使用する9Scale用の素材

Starling ATFファイルの使用

SpriteSheetをATF形式で試してみました。
詳しくはATF SDKの公開(リンク先へ)をご覧下さい。

利点

  • テクスチャの保持に必要なメモリ料が少ない
  • テクスチャのアップロードが短時間で済む
  • 描画が早くなる
  • という事ですが、Starling1.3で試した結果以下のようになりました。

    Sprite Animation Sample

    150個のスプライトをアニメーションさせながら、移動をさせています。
    pngスプライトデータ 約43fps
    atfフォーマット 約35fps

    Starlingコンテンツの描画領域とassetsの管理 まとめ

    1.Starlingコンテンツの描画領域とassetsの管理(リンク先へ)

    2.Starlingコンテンツの描画領域とassetsの管理 実装編(リンク先へ)

    3.Starlingコンテンツの描画領域とassetsの管理 解説(リンク先へ)

    Starlingコンテンツの描画領域とassetsの管理 解説編

    描画領域の処理
    ScreenMultiResolution.as
    var showType:int = 0;
    
    if(showType == 0)
    {
    showAll();
    } else if(showType == 1) {
    showCenter();
    } else {
    return;
    }
    
    変数showTypeの0で画面全体を表示し、1で画面の中央に表示に切り替えます。
    ScreenMultiResolution.as
      private function showCenter():void
      {
       viewport = RectangleUtil.fit(
        new Rectangle(0, 0, stage.stageWidth,stage.stageHeight), 
        new Rectangle((stage.stageWidth >> 1) - (STAGE_WIDTH >> 1),
        (stage.stageHeight >> 1) - (STAGE_HEIGHT >> 1),
        STAGE_WIDTH,
        STAGE_HEIGHT),
        starling.utils.ScaleMode.SHOW_ALL);
      }
    
      private function showAll():void
      {
       viewport = RectangleUtil.fit(
        new Rectangle(0,0,stage.stageWidth,stage.stageHeight), 
        new Rectangle(0,0,stage.fullScreenWidth,stage.fullScreenHeight),
        starling.utils.ScaleMode.SHOW_ALL);
      }
    
    RectangleUtil.fit()メソッドは、第1引数の矩形領域を第2引数の矩形領域に、縦横比は変えずに納めるためのRectangleオブジェクトを返します。
    第3引数には、ScaleModeクラスの定数で伸縮モードが渡せます。 

    詳しくは
    Starlingフレームワーク1.3の新しい機能(リンク先へ)
    Multi-Resolution Development(リンク先へ)
    をご覧下さい。

    assetsの管理
    Main.as
      private function addAssets(data:Object):void
      {
       var sheetPngName:String = "sheetPng";
       var sheetXmlName:String = "sheetXml";
       var scaleFactorName:String = "scaleFactor";
       var contentScaleFactor:int;
       var sScale:String;
    
       if(Starling.contentScaleFactor >= 1 && Starling.contentScaleFactor < 3)
       {
        contentScaleFactor = int(Starling.contentScaleFactor);
        sScale = "x"+contentScaleFactor.toString();
    
        assetManager = new AssetManager(contentScaleFactor);
        assetManager.verbose = true;
        assetManager.enqueue(data[sScale][sheetPngName]);
        assetManager.enqueue(data[sScale][sheetXmlName]);
        assetManager.loadQueue(loadAssetsHandler);
       }
      }
    
      private function loadAssetsHandler(ratio:Number):void
      {
       if(ratio < 1.0) return;
    
       addTextures();
      }
    

    addAssetsメソッドでは、Starling.contentScaleFactorからテクスチャのスケール係数を取得します。 スケール係数に適したSpriteSheetを用意し、jsonファイルで管理するという仕組みになります。
    SpriteSheetファイルが決定した所で、次にAssetManagerクラスを利用し指定した読み込み処理を行なっています。 読み込みが完了(1.0)になるまで、loadAssetsHandlerを繰り返しコールされます。

    Starlingコンテンツの描画領域とassetsの管理 実装編


    spriteSheetは各自で用意をして下さい。
    このサンプルでは、TexturePackerを利用して作成しました。

    ScreenMultiResolution.as
    package
    {
     import flash.display.Sprite;
     import flash.display.StageAlign;
     import flash.display.StageScaleMode;
     import flash.events.Event;
     import flash.geom.Rectangle;
    
     import starling.core.Starling;
     import starling.utils.RectangleUtil;
     import starling.utils.ScaleMode;
    
     [SWF(width="320",height="480",frameRate="60",backgroundColor="#0")]
     public class ScreenMultiResolution extends Sprite
     {
      public static const STAGE_WIDTH:uint = 320;
      public static const STAGE_HEIGHT:uint = 480;
    
      private var viewport:Rectangle;
    
      public function ScreenMultiResolution()
      {
       super();
    
       stage.align = StageAlign.TOP_LEFT;
       stage.scaleMode = StageScaleMode.NO_SCALE;
    
       addEventListener(Event.ADDED_TO_STAGE,addedToStageHandler);
      }
    
      protected function addedToStageHandler(event:flash.events.Event):void
      {
       removeEventListener(Event.ADDED_TO_STAGE,addedToStageHandler);
    
       var showType:int = 0;
    
       if(showType == 0)
       {
        showAll();
       } else if(showType == 1) {
        showCenter();
       } else {
        return;
       }
    
       Starling.handleLostContext = true;
       Starling.multitouchEnabled = true;
    
       var st:Starling = new Starling(Main, stage, viewport);
       st.stage.stageWidth  = STAGE_WIDTH;
       st.stage.stageHeight = STAGE_HEIGHT;
       st.start();
      }
    
      private function showCenter():void
      {
       viewport = RectangleUtil.fit(
        new Rectangle(0, 0, stage.stageWidth,stage.stageHeight), 
        new Rectangle((stage.stageWidth >> 1) - (STAGE_WIDTH >> 1),
        (stage.stageHeight >> 1) - (STAGE_HEIGHT >> 1),
        STAGE_WIDTH,
        STAGE_HEIGHT),
        starling.utils.ScaleMode.SHOW_ALL);
      }
    
      private function showAll():void
      {
       viewport = RectangleUtil.fit(
        new Rectangle(0,0,stage.stageWidth,stage.stageHeight), 
        new Rectangle(0,0,stage.fullScreenWidth,stage.fullScreenHeight),
        starling.utils.ScaleMode.SHOW_ALL);
      }
    
     }
    }
    
    Main.as
    package
    {
     import flash.events.Event;
     import flash.net.URLLoader;
     import flash.net.URLRequest;
    
     import starling.core.Starling;
     import starling.display.Image;
     import starling.display.Quad;
     import starling.display.Sprite;
     import starling.events.Event;
     import starling.text.TextField;
     import starling.textures.Texture;
     import starling.utils.AssetManager;
    
     public class Main extends Sprite
     {
      private var assetManager:AssetManager;
    
      public function Main()
      {
       super();
    
       addEventListener(starling.events.Event.ADDED_TO_STAGE,addedToStageHandler);
      }
    
      private function addedToStageHandler(event:starling.events.Event):void
      {
       var urlLoader:URLLoader = new URLLoader();
    
       urlLoader.addEventListener(flash.events.Event.COMPLETE,urlLoaderCompleteHandler);
       urlLoader.load(new URLRequest("./assets/setting.json"));
      }
    
      protected function urlLoaderCompleteHandler(event:flash.events.Event):void
      {
       var urlLoader:URLLoader = event.target as URLLoader;
    
       urlLoader.removeEventListener(flash.events.Event.COMPLETE,urlLoaderCompleteHandler);
       addAssets(JSON.parse(urlLoader.data as String));
      }
    
      private function addAssets(data:Object):void
      {
       var sheetPngName:String = "sheetPng";
       var sheetXmlName:String = "sheetXml";
       var scaleFactorName:String = "scaleFactor";
       var contentScaleFactor:int;
       var sScale:String;
    
       if(Starling.contentScaleFactor >= 1 && Starling.contentScaleFactor < 3)
       {
        contentScaleFactor = int(Starling.contentScaleFactor);
        sScale = "x"+contentScaleFactor.toString();
    
        assetManager = new AssetManager(contentScaleFactor);
        assetManager.verbose = true;
        assetManager.enqueue(data[sScale][sheetPngName]);
        assetManager.enqueue(data[sScale][sheetXmlName]);
        assetManager.loadQueue(loadAssetsHandler);
       }
      }
    
      private function loadAssetsHandler(ratio:Number):void
      {
       if(ratio < 1.0) return;
    
       addTextures();
      }
    
      private function addTextures():void
      {
       var scaleFactor:Number = Starling.current.contentScaleFactor;
       var quadW:Number = 100;
       var quadH:Number = 100;
    
       var bg:Quad = makeQuad(0,0,stage.stageWidth,stage.stageHeight,0x0000ff);
       bg.alpha = 0.5;
       addChild(bg);
    
       var luQuad:Quad = makeQuad(0,0,100,100,Math.random() * 0xffffff);
       addChild(luQuad);
    
       var ldQuad:Quad = makeQuad(0,stage.stageHeight - quadH,100,100,Math.random() * 0xffffff);
       addChild(ldQuad);
    
       var ruQuad:Quad = makeQuad(stage.stageWidth - quadW,0,100,100,Math.random() * 0xffffff);
       addChild(ruQuad);
    
       var rdQuad:Quad = makeQuad(stage.stageWidth - quadW,stage.stageHeight - quadH,
        100,100,Math.random() * 0xffffff);
       addChild(rdQuad);
    
       var texture:Texture = assetManager.getTexture("bird");
    
       var image:Image = new Image( texture );
       addChild(image);
       image.x = 0;
       image.y = 0;
    
       var image2:Image = new Image( texture );
       addChild(image2);
       image2.x = stage.stageWidth - image.width;
       image2.y = (stage.stageHeight) - (image.height);
    
       var image3:Image = new Image( texture );
       addChild(image3);
       image3.x = (stage.stageWidth >> 1) - (image.width >> 1);
       image3.y = (stage.stageHeight >> 1) - (image.height >> 1);
      }
    
      private function makeQuad(_x:Number,_y:Number,_w:Number,_h:Number,_color:Number):Quad
      {
       var quad:Quad = new Quad(_w,_h,_color);
       quad.x = _x;
       quad.y = _y;
    
       return quad;
      }
    
     }
    }
    
    setting.json
    {"x1":{"sheetPng":"./assets/spriteSheet.png","sheetXml":"./assets/spriteSheet.xml"},"x2":{"sheetPng":"./assets/spriteSheet2x.png","sheetXml":"./assets/spriteSheet2x.xml"}}
    


    Starlingコンテンツの描画領域とassetsの管理

    iPodTouchとNexus7の2機種を利用して、コンテンツの描画領域の処理を行います。

    画面解像度に差のある2機種で、縦480x横320を基準にして表示をしました。
    Nexus7右側の画像では縦480x横320の大きさにした状態で
    画面の中央に配置しました。
    この処理は、RectangleUtil.fitというメソッドを利用する事で実現が可能です。

    今回はこの描画領域の処理とAssetManagerクラスを利用したアセットの管理方法を
    紹介します。
    この方法は、Starling Framework 1.3からの機能になります。

    実行結果


    Nexus7で表示した結果


    iPodTouchで表示した結果

    開発環境
    FlashBuilder 4.6
    Starling Framework 1.3
    Nexus7実機
    iPodTouch実機

    2013年3月28日木曜日

    ANEでnative twitterを利用する ビルド編

    FlashBuilderでnarive twitterサンプルアプリをビルドします

    NativeTwitterSample
    ActionScriptモバイルプロジェクトを作成します。NativeTwitterSample.asの内容は
    NativeTwitter-aneSample/src/Main.asです

    プロジェクトの追加から、NativeTwitterライブラリを追加します

    ActionScipt ビルドパスから作成したaneファイルを選択します

    ActionScipt ビルドのパッケージ化のApple iOSを選択します
    ネイティブエクステンションを選択し、パッケージにチェックを入れます

    Apple iOS SDKを設定します。
    XCodeをインストールした時のパスによって、ディレクトリパスの違いがあります
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk

    この際に、電子署名ファイルプロビジョニングファイルパスの設定も行います。
    ビルドを行った後、ipaファイルを作成します。

    ANEでnative twitterを利用する ANEtty編

    ANEtty 1.0.1 Previewを利用します。設定は以下のように行います

    ExtInfo(General)
    ProjectTitle
    NativeTwitter

    ExtensionID
    com.palDeveloppers.ane.NativeTwitter

    VersionNumber
    1.0.1

    ANE-Interface-SWC
    /(NativeTwitterプロジェクトライブラリパス)/bin/NativeTwitter.swc

    ANE Export Path
    /(NativeTwitterプロジェクトライブラリパス)/bin/NativeTwitter.ane

    ANE Version
    3.6

    エラーダイアログについて
    ディレクトリパスを設定する際に、稀にこのようなエラーが表示されます
    この場合は...ボタンの隣にあるresetボタンを1度押すとエラーは出なくなります

    Platforms 
    General

    NativeLibraryPath
    /(NativeTwitterプロジェクトライブラリパス)/bin/libNativeTwitter.a

    Initializer
    NativeTwitterExtInitializer

    Finalizer
    NativeTwitterExtFinalizer

    PlatformOption
    Use PlatformOption for iOSにチェックを入れる
    iOSフレームワークライブラリを追加する必要があります
    詳細はネイティブライブラリの構築(リンク先へ)をご覧下さい


    SDK Version
    6.0

    LinkerOptions

    -framework Twitter
    -framework Accounts
    -liconv


    PlatformOption Setting - Optional
    Description(Optional)
    NativeTwitter
    Copyright(Optional)
    2012 PalDeveloppers

    最後に、Compileボタンを押してaneファイルを作成します

    ANEでnative twitterを利用する SWC編

    FlashBuilderでSWCの作成を行います
    3つのファイルを追加します
    ・NativeTwitter.as
    ・TweetCompositionResult.as
    ・TWRequestMethod.as

    ビルドを行い、binディレクトリにNativeTwitter.swcが作成されます

    XCodeで作成したlibNativeTwitter.aファイルをbinフォルダへコピーします。
    これは後程aneファイルを作成する時に必要になります。

    この時点ではまだNativeTwitter.aneは作成されていませんが、
    ANE作成時にこのディレクトリへ出力するようにしています。

    ANEでnative twitterを利用する XCode編

    XCodeを起動し、Cocoa Touch Static Libraryプロジェクトを選択します

    nativetwitter-ane内にある2つのソースコードを追加します
    ・NativeTwitter.h
    ・NativeTwitter.m

    FlashRuntimeExtensions.hを追加します
    FlashRuntimeExtensions.hの場所は(リンク先へ)を参考にして下さい

    Accounts.frameworkTwitter.framework
    TARGETSBuild Phases内にあるLink Binary With Librariesで追加します

    ビルドを行い、libNativeTwitter.aを作成します

    ANEでnative twitterを利用する

    native twitterをANEを通して利用してみます。

    native twitterサンプルアプリ画面
    開発環境
    MacOS 10.7.5
    XCode 4.6
    FlashBuilder 4.6
    ANEtty 1.0.1 Preview(リンク先へ)
    nativetwitter-ane(リンク先へ)




    ANEttyでnative twitterを試してみる


    ANEtty 1.0.1 Previewを利用して、native twitterのサンプルを動作させてみました。
     
    1.ANEでnative twitterを利用する(リンク先へ)

    2.ANEでnative twitterを利用する XCode編(リンク先へ)

    3.ANEでnative twitterを利用する SWC編(リンク先へ)

    4.ANEでnative twitterを利用する ANEtty編(リンク先へ)

    5.ANEでnative twitterを利用する ビルド編(リンク先へ)

    6.ANEでnative twitterを試してみる(リンク先へ)

    実機でnative twitterを試してみる

    NativeTwitterSample.ipaを実機にインストールして試してみました。
    端末の設定のTwitterにユーザーアカウントを作成しておく必要があります。
    Compose tweetをタップすると、Twitterダイアログが表示されます。

    実際にTweetできるか試してみました。



    2013年3月14日木曜日

    adt+Rakeでビルドやインストールをする

    Rakeを使用してiOS端末へ以下の作業を行います。
    ・リリースビルドとインストール
    アンインストール

    AIRで使用するadtコマンドは(リンク先へ)から調べることが出来ます。


    作成したプロジェクトのbin-debug内にRakefileとSettings.rbを配置します。
    ※画像キャプチャ内にdevicesファイルというのがありますが使用しません。

    Settings.rb
    task :set do
        $provisionFilePath = "~/certs/provision.mobileprovision";
        $p12FilePath = "~/certs/provision.p12"; 
        $storepw = "password"; 
        $ipaFileName = "./MobileSample.ipa";
        $appXmlFileName = "./MobileSample-app.xml";
        $swfFileName = "./MobileSample.swf";
        $extdirPath = "./";
        $platformsdkPath = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk";
        $defaultPngPath = "./Default.png";
        $deviceHandle = "1";
    end
    
    Settings.rbはRakefile内で使用します。 リリースビルドに必要な各種項目を定義します。

    Rakefile
    load "./Settings.rb"
    
    $bl = " ";
    
    task :default => [:set,:build,:ipaInstall];
    
    task :build do
        adt = "adt";
        adt += $bl+"-package";
        adt += $bl+"-target"+$bl+"ipa-app-store";
        adt += $bl+"-provisioning-profile"+$bl+"#{$provisionFilePath}";
        adt += $bl+"-storetype"+$bl+"pkcs12";
        adt += $bl+"-keystore"+$bl+"#{$p12FilePath}";
        adt += $bl+"-storepass"+$bl+"#{$storepw}";
        adt += $bl+"#{$ipaFileName}";
        adt += $bl+"#{$appXmlFileName}";
        adt += $bl+"#{$swfFileName}";
        adt += $bl+"#{$defaultPngPath}";
        adt += $bl+"-extdir"+$bl+"#{$extdirPath}";
        adt += $bl+"-platformsdk"+$bl+"#{$platformsdkPath}";
        sh "#{adt}";
    end
    
    task :ipaInstall do
        adt = "adt";
        adt += $bl+"-installApp";
        adt += $bl+"-platform"+$bl+"ios";
        adt += $bl+"-platformsdk"+$bl+"#{$platformsdkPath}";
        adt += $bl+"-device"+$bl+"#{$deviceHandle}";
        adt += $bl+"-package"+$bl+"#{$ipaFileName}";
        sh "#{adt}";
    end
    
    task :ipaUninstall,'appid'
    task :ipaUninstall do |t, args|
        Rake::Task["set"].invoke;
        adt = "adt";
        adt += $bl+"-uninstallApp";
        adt += $bl+"-platform"+$bl+"ios";
        adt += $bl+"-platformsdk"+$bl+"#{$platformsdkPath}";
        adt += $bl+"-device"+$bl+"#{$deviceHandle}";
        adt += $bl+"-appid"+$bl+"#{args['appid']}";
        sh "#{adt}";
    end
    

    作成したRakefileを実行すると、リリースビルド後に端末へインストールします。
    $>rake
    
    bin-debugにディレクトリを移動し、rakeコマンドを呼び出します。

    次にアプリのアンインストールを行います。
    $>rake 'ipaUninstall[com.app.MobileSample]'
    
    ipaUninstallタスクを指定し、applicationIDを引数に渡します。