yoppa.org


Web動画表現 2010

AS3 マウスイベントを扱う

先週に引き続き、マウスを利用したインタラクションについて取り上げます。

今回は、マウスの位置だけでなく、より詳細なマウスの状態を取得する方法について紹介します。

マウスイベント

マウスからの入力は、先週とりあつかったマウスポインタの位置だけでなく、マウスのボタンの状態や対象との関係によって様々な状態を表現することが可能です。ActionScript 3では、マウスの状態をイベントとして受けとることができます。マウスのイベントを処理するイベントリスナーを生成することで、きめ細かなマウスの入力の処理が可能となります。

ActionScript 3で取り扱うことのできるイベントは下記の通りです。

  • MouseEvent.CLICK
  • MouseEvent.DOUBLE_CLICK
  • MouseEvent.MOUSE_DOWN
  • MouseEvent.MOUSE_MOVE
  • MouseEvent.MOUSE_OUT
  • MouseEvent.MOUSE_OVER
  • MouseEvent.MOUSE_UP
  • MouseEvent.MOUSE_WHEEL
  • MouseEvent.ROLL_OUT
  • MouseEvent.ROLL_OVER

これらのイベントがどのような時に発生するのか、また、これらのイベントを活用することでどのようなことが出来るのかを探っていきましょう。

スクリプトのテンプレート

今日の授業で使用するスクリプトのテンプレートです。まず、AS3形式のFlashファイルを用意し、ドキュメントクラスを「Main」に指定します。その上で下記のコードを新規に作成したActionScriptファイルにペーストして、ファイル名を「Main.as」にしてFlaファイルと同じ場所に保存してください。

package {
  import flash.display.*;
  import flash.events.*;

  public class Main extends Sprite {
  //ここにグローバルな変数を記入

    public function Main() {
    //初期設定の項目を記入
           
      //フレーム更新のイベントリスナーの登録
      this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }

    //イベントハンドラ
    function enterFrameHandler(event:Event):void {

    }
  }
}

マウスイベントを取得する

まず初めに、マウスイベントを取得して、trace() 関数を使用して状態を出力するサンプルを作成してみましょう。またいつものように、AS3形式でFLAファイルを作成し、ドキュメントクラスを「Main」にします。その上で同じ場所に「Main.as」というファイル名でActionScript形式のファイルを作成し、下記のスクリプトを記入します。

package {
    import flash.display.*;
    import flash.events.*;

    public class Main extends Sprite {
        //ここにグローバルな変数を記入

        public function Main() {
            //初期設定の項目を記入

            //マウスイベントリスナー
            stage.addEventListener(MouseEvent.CLICK, clickHandler);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
        }

        //クリック
        private function clickHandler(event:MouseEvent):void {
            trace("clickHandler");
        }
        //マウスボタンを押した瞬間
        private function mouseDownHandler(event:MouseEvent):void {
            trace("mouseDownHandler");
        }
        //マウスボタンを離した瞬間
        private function mouseUpHandler(event:MouseEvent):void {
            trace("mouseUpHandler");
        }
        //マウスボタンを動かした瞬間
        private function mouseMoveHandler(event:MouseEvent):void {
            trace("mouseMoveHandler");
        }
    }
}

ムービーを実行すると、マウスの動作に対応して、「出力」画面にメッセージが表示されると思います。マウスボタンを何も押さずにマウスポインタを動かしたときには、MouseEvent.MOUSE_MOVEのメッセージ。マウスボタンを押した瞬間に、MouseEvent.MOUSE_DOWN。そして、押していたマウスボタンを離した瞬間にMouseEvent.MOUSE_UPと、MouseEvent.CLICKが出力されるのがわかります。

ムービークリップとマウスとの関係を取得する

先程の例は、ステージ上でのマウスの動作を取得していました。AS3のマウスイベントでは、ステージ上に配置したムービークリップとの関係性を表現するために、MOUSE_DOWNやMOUSE_UPなどの他に、様々なイベントが用意されています。

ムービークリップとの関連を調べるために、ステージ上に「MyButton」というクラス名でリンケージを設定してボタンの図形を描きます。これをステージ中央に配置してマウスでのインタラクションを試してみましょう。

screen(2010-12-07 20.52.00).png

package {
    import flash.display.*;
    import flash.events.*;

    public class Main extends Sprite {
        //ここにグローバルな変数を記入
        var myButton:MyButton = new MyButton();

        public function Main() {
            //初期設定の項目を記入
            //画面中心にボタンを配置
            myButton.x=stage.stageWidth/2;
            myButton.y=stage.stageHeight/2;
            this.addChild(myButton);

            //ボタン(myButton)に対するマウスイベントリスナー
            myButton.addEventListener(MouseEvent.CLICK, clickHandler);
            myButton.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            myButton.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            myButton.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            myButton.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
        }

        //クリック
        private function clickHandler(event:MouseEvent):void {
            trace("clickHandler");
        }
        //マウスボタンを押した瞬間
        private function mouseDownHandler(event:MouseEvent):void {
            trace("mouseDownHandler");
            myButton.scaleX = myButton.scaleY = 0.9;
        }
        //マウスボタンを離した瞬間
        private function mouseUpHandler(event:MouseEvent):void {
            trace("mouseUpHandler");
            myButton.scaleX = myButton.scaleY = 1.0;
        }
        //ロールオーバー
        private function rollOverHandler(event:MouseEvent):void {
            trace("rollOverHandler");
            myButton.alpha=0.5;
        }
        //ロールアウト
        private function rollOutHandler(event:MouseEvent):void {
            trace("rollOutHandler");
            myButton.alpha=1.0;
        }
    }
}

この例ではステージ状に配置した、MyButton(インスタンス名はmyButton)というムービークリップシンボルと、マウスの状態を表示しています。注意深く観察すると、MouseEvent.CLICK、MouseEvent.MOUSE_UP、MouseEvent.MOUSE_DOWN、MouseEvent.ROLL_OVER、MouseEvent.ROLL_OUT という合計5つのイベントが、それぞれ独自のタイミングで発生していることがわかると思います。

  • MouseEvent.ROLL_OVER:マウスポイタが、対象のムービクリップ(myButton)と重なった瞬間
  • MouseEvent.ROLL_OUT:マウスポイタが、対象のムービクリップ(myButton)から離れた瞬間
  • MouseEvent.MOUSE_DOWN:マウスポイタが、対象のムービクリップ(myButton)の上でボタンを押した瞬間
  • MouseEvent.MOUSE_UP:マウスポイタが、対象のムービクリップ(myButton)の上でボタンを離した瞬間
  • MouseEvent.CLICK:マウスポイタが、対象のムービクリップ(myButton)の上でボタンを離した瞬間。ただし、対象のムービクリップの外でマウスボタンを押して、ボタンを押したままボタンの上まで移動して離しても、CLICKイベントは発生しない。

この中で、MOUSE_UPとCLICKの違いがわかりずらいかもしれません。両者は共にマウスボタンを離した瞬間に発生するのですが、1つだけ違いがあります。対象とするムービークリップの外でマウスボタンを押し(= MouseEvent.MOUSE_DOWN)、そのままボタンを押した状態でムービークリップまで移動してきて、マウスボタンを離します。その際には、CLICKイベントは発生するのですが、MOUSE_UPイベントは発生しません。

ムービークリップをマウスで掴んで移動する

では、もう少し高度な例として、ムービークリップをマウスポインタで掴んで移動できるようなインタラクションを作成してみましょう。

マウスで対象のムービークリップを掴んで移動するには、MOUSE_DOWNイベントとMOUSE_UPイベントをうまく使い分ける必要があります。MOUSE_DOWNイベントが発生した際に、物体を掴んだと判断し、MOUSE_UPイベントが発生した瞬間に掴んでいた物体を離したと解釈すると自然なインタラクションとなります。

マウスでムービークリップを移動したように見せる方法は、マウスの座標を取得して常にその座標とムービークリップの座標が一致するようにすることで実現可能ですが、もう少し簡易な方法が存在します。例えば、ムービークリップシンボルが「hoo」だとすると以下のメソッドでマウスのドラッグによる移動の開始/終了を設定可能です。

  • hoo.startDrag():ターゲットのムービクリップのマウスドラッグでの移動を開始
  • hoo.stopDrag():ターゲットのムービクリップのマウスドラッグでの移動を終了

この機能を活用して、以下のようにプログラムしてみましょう。

package {
    import flash.display.*;
    import flash.events.*;

    public class Main extends Sprite {
        //ここにグローバルな変数を記入
        var myObject:MyObject = new MyObject();

        public function Main() {
            //初期設定の項目を記入
            //画面中心にボタンを配置
            myObject.x=stage.stageWidth/2;
            myObject.y=stage.stageHeight/2;
            this.addChild(myObject);

            //フレーム更新のイベントリスナーの登録
            this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);

            //マウスイベントリスナー
            myObject.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            myObject.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            myObject.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            myObject.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
        }

        //イベントハンドラ
        function enterFrameHandler(event:Event):void {
        }

        //マウスボタンを押した瞬間
        private function mouseDownHandler(event:MouseEvent):void {
            event.target.startDrag();
        }
        //マウスボタンを離した瞬間
        private function mouseUpHandler(event:MouseEvent):void {
            event.target.stopDrag();
        }
        //ロールオーバー
        private function rollOverHandler(event:MouseEvent):void {
            event.target.alpha=0.5;
        }
        //ロールアウト
        private function rollOutHandler(event:MouseEvent):void {
            event.target.alpha=1.0;
        }
    }
}

応用:ふくわらい

最後に複数の物体をそれぞれマウスで掴んで移動できるような例を紹介します。

目や鼻、口などを画像で作成して、それをマウスで移動可能にすることで「ふくわらい」を作成してみましょう。

package {
    import flash.display.*;
    import flash.events.*;

    public class Main extends Sprite {
        //ここにグローバルな変数を記入
        var eyeR:EyeR = new EyeR();
        var eyeL:EyeL = new EyeL();
        var nose:Nose = new Nose();
        var mouth:Mouth = new Mouth();

        public function Main() {
            //初期設定の項目を記入
            //ランダムに顔のパーツを配置
            eyeR.x=Math.random()*stage.stageWidth;
            eyeR.y=Math.random()*stage.stageHeight;
            this.addChild(eyeR);

            eyeL.x=Math.random()*stage.stageWidth;
            eyeL.y=Math.random()*stage.stageHeight;
            this.addChild(eyeL);

            nose.x=Math.random()*stage.stageWidth;
            nose.y=Math.random()*stage.stageHeight;
            this.addChild(nose);
            
            mouth.x=Math.random()*stage.stageWidth;
            mouth.y=Math.random()*stage.stageHeight;
            this.addChild(mouth);

            //マウスイベントリスナー
            eyeR.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            eyeR.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            eyeR.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            eyeR.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
            
            eyeL.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            eyeL.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            eyeL.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            eyeL.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
            
            nose.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            nose.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            nose.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            nose.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
            
            mouth.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            mouth.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            mouth.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            mouth.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
        }

        //マウスボタンを押した瞬間
        private function mouseDownHandler(event:MouseEvent):void {
            event.target.startDrag();
        }
        //マウスボタンを離した瞬間
        private function mouseUpHandler(event:MouseEvent):void {
            event.target.stopDrag();
        }
        //ロールオーバー
        private function rollOverHandler(event:MouseEvent):void {
            event.target.alpha=0.5;
        }
        //ロールアウト
        private function rollOutHandler(event:MouseEvent):void {
            event.target.alpha=1.0;
        }
    }
}