株式会社antsのホームページへようこそ。

FlexとActionScript 3でガジェットを作る!<第5回>

0
Posted in Lab. By tanaka

先日、GIZMOコンポーネントのAS3版をリリースしました。AS3に対応したことで、Flash CS3に加えてFlex BuilderでもGIZMOのAPIへ一通りアクセス可能になったわけです。ということで、しばらく放置されていた連載エントリを締めてみたいと思います。
ただ、第4回まで執筆していたBetaNewsが不在のため、彼に変わって私タナカがお送りします。ここではFlex Builder 3 beta3を使って、GIZMOに昔っから同梱されている目ん玉グルグルをAS3に移植してみましょう。オリジナルはなんとAS1。時代の流れを感じます。


■GIZMOコンポーネントのダウンロード
さて、AS3版GIZMOコンポーネントは下記よりダウンロードできます。
[ 開発ツールダウンロード ]
コンポーネントのリファレンスはこちらです。
[ Gizmoコンポーネントリファレンス 2.1.1 (ActionScript 3.0) ]
コンポーネント(gizmo-as3.swc)をダウンロードしたら、Flex Builder 3のライブラリに追加しておきましょう。アプリケーションフォルダ内の sdks/3.0.0/frameworks/libs/ に入れておけばオッケーです。

■ガジェットの素材を用意
ガジェットで使うパーツはFlashで組み上げてしまうのが手っ取り早いです。Flex Builderではそれを外部SWFとしてロードします。スクリプトの処理はすべてFlex側で組み込むことにしたので、Flash素材には一切スクリプトを記述していません。今回は下図のようなeyes.swfを作りました。
※すべての作業はMacで行っていますが、残念ながら完成したガジェットは今のところWindowsでしか動作しません。
eyeball_workspace.jpg

■パーツの読み込み
Flex Builder 3を起動して、Eyeballという名前の新規Flexプロジェクトを作成します。プロジェクトを作成すると、ユーザのドキュメントディレクトリ以下にあるFlex Builder 3フォルダ内にEyeballというプロジェクトフォルダが作成されます。その中にあるsrcフォルダへ、さきほどFlashで作ったeyes.swfを入れておきましょう。SWFLoaderコンポーネントを使ってコレをロードします。
また、ステージサイズが無意味に大きいとそれだけ描画負荷も上がるので、読み込む素材に合わせます。ついでに背景を透過させるためのスタイル設定も行えば、見た目の処理は完了です。

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="120" height="62">
  <mx:Style>
    Application
    {
      background-alpha:"0";
    }
  </mx:Style>
  <mx:SWFLoader x="0" y="0" id="_loader" source="eyes.swf" complete="loadCompleteHandler()"/>
</mx:Application>

■グルグル回す
上のコードでは、SWFLoaderの読み込み完了時にloadCompleteHandler()を実行するよう設定してあります。そのタイミングで諸々の初期化を行っていきます。まずは、目玉が回るために必要な処理の設定です。
GIZMO APIでは、Desktop.mouseXとDesktop.mouseYでスクリーン上のマウス座標を取得できます。現在のガジェットの座標はGadget.xおよびGadget.yです。これらを利用してマウスと目玉(左右それぞれの黒目)の角度を計算し、回転させればよいわけです。で、回転させるタイミングですが、ユーザーがデスクトップ上でマウスを動かしたときでよいでしょう。これはDesktopEvent.MOUSE_MOVEイベントの通知を受け取ることで実現できます。

<mx:Script>
  <![CDATA[
    import jp.anthill.gizmo.*;
    private var eyes_mc:MovieClip;

    private function loadCompleteHandler():void {
      eyes_mc = _loader.content as MovieClip;
      init();
    }

    private function init():void {
      eyes_mc.left_mc.rotate =
      eyes_mc.right_mc.rotate = function():void {
        var dx:int = Desktop.mouseX - Gadget.x - this.x;
        var dy:int = Desktop.mouseY - Gadget.y - this.y;
        var radian:Number = Math.atan2(dy, dx);
        this.rotation = radian / (Math.PI / 180);
      };
      Desktop.addEventListener(DesktopEvent.MOUSE_MOVE, mouseMoveHandler);
    }

    private function mouseMoveHandler(event:DesktopEvent):void {
      eyes_mc.left_mc.rotate();
      eyes_mc.right_mc.rotate();
    }
  ]]>
</mx:Script>

■ガジェットの移動と終了
GIZMOはガジェットのドラッグ移動を自動的に処理してくれるので、基本的には開発者がその点を意識する必要はありません。しかし、今回のガジェットはドラッグしようとしても動いてくれません。なぜかと言うと、FlexのApplicationコンポーネントがマウスイベントを受け取るようになっているためです。GIZMOはマウスイベントを受け取るオブジェクト(主な想定はボタンやテキストフィールド)をドラッグ移動の対象から外すのです。もちろんこの設定を変えて、どこを掴んでもドラッグできるようにすることも可能ですが、ここでは次のようにGadget.startMove()メソッドで明示的に移動させます。マウスボタンを放せば自動的にドラッグが終わります。

this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
private function mouseDownHandler(event:MouseEvent):void {
  Gadget.startMove();
}

ガジェットの終了は右クリックメニューからも行えますが、スクリプトで終了する場合は、Gadget.close()メソッドを使います。クローズボタンで終了できるようにしましょう。

eyes_mc.close_btn.addEventListener(MouseEvent.CLICK, closeClickHandler);
private function closeClickHandler(event:MouseEvent):void {
  Gadget.close();
}

■完成
これまでの処理をまとめたコードは次のようになります。クローズボタンはガジェットの上にマウスカーソルが乗った時だけ現れるよう、味付けも施しました。Gadget.getBounds()でガジェットの矩形領域が取得できるので、マウス座標と重なっているか判定しています。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="120" height="62">

  <mx:Style>
    Application
    {
      background-alpha:"0";
    }
  </mx:Style>

  <mx:SWFLoader x="0" y="0" id="_loader" source="eyes.swf" complete="loadCompleteHandler()"/>

  <mx:Script>
    <![CDATA[
      import jp.anthill.gizmo.*;
      private var eyes_mc:MovieClip;

      private function loadCompleteHandler():void {
        eyes_mc = _loader.content as MovieClip;
        init();
      }

      private function init():void {
        this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
        eyes_mc.left_mc.rotate =
        eyes_mc.right_mc.rotate = function():void {
          var dx:int = Desktop.mouseX - Gadget.x - this.x;
          var dy:int = Desktop.mouseY - Gadget.y - this.y;
          var radian:Number = Math.atan2(dy, dx);
          this.rotation = radian / (Math.PI / 180);
        };
        eyes_mc.close_btn.visible = false;
        eyes_mc.close_btn.addEventListener(MouseEvent.CLICK, closeClickHandler);
        Desktop.addEventListener(DesktopEvent.MOUSE_MOVE, mouseMoveHandler);
      }

      private function mouseDownHandler(event:MouseEvent):void {
        Gadget.startMove();
      }

      private function mouseMoveHandler(event:DesktopEvent):void {
        eyes_mc.left_mc.rotate();
        eyes_mc.right_mc.rotate();
        var bounds:Rectangle = Gadget.getBounds();
        eyes_mc.close_btn.visible = bounds.containsPoint(event.position);
      }

      private function closeClickHandler(event:MouseEvent):void {
        Gadget.close();
      }
    ]]>
  </mx:Script>

</mx:Application>

これでリリースビルドを書き出せば、ガジェットのSWFは完成です。後は、次のようなガジェット定義ファイルを用意して、ガジェットフォルダにまとめます。ガジェットフォルダ名は任意ですが、ここではEyeball_Flexにします。

<?xml version="1.0" encoding="utf-8" ?>
<gadget xmlns="http://gizmo.anthill.jp/gadget/2.0" version="1.0">
  <content src="Eyeball.swf" />
  <title>Eyeball Flex</title>
  <author>タナカヤスヒロ</author>
  <description>Flexで作った目玉です。</description>
  <menu>
    <close label="閉じる" />
  </menu>
</gadget>

ガジェットフォルダが用意できたら、WindowsのDocuments and Settings\ユーザ名\Application Data\GIZMO2\deck\community\gadget\以下に置くとGIZMOで動かすことができます。