サイトトップ

Director Flash 書籍 業務内容 プロフィール

Adobe Flash非公式テクニカルノート

Starlingフレームワークでインスタンスをクリックする

ID: FN1204003 Product: Flash CS5 and above Platform: All Version: 11 and above/ActionScript 3.0

Starlingフレームワークでは、マウスイベントはDisplayObject.touchイベント(定数TouchEvent.TOUCH)で扱います。本稿は、インスタンスのクリックをDisplayObject.touchイベントでどのように受取るかについてご説明します。


01 Quadインスタンスをステージに置く
まずは、クリックするインスタンスをステージに置かなければなりません。矩形のQuadインスタンスをひとつつくることにします。Starlingフレームワークのルートクラス(MySprite)はつぎのように定めます。ステートメントの頭に添えた番号は、後に掲げるクリックの扱いまで含めたクラス定義のスクリプト001の行を示します。

    // ActionScript 3.0クラス定義ファイル: MySprite.as
  1. package {
  1.   import starling.display.Sprite;
  2.   import starling.display.Quad;
  3.   import starling.events.Event;
  1.   public class MySprite extends Sprite {
  2.     private var square:Quad;
  3.     private var nUnit:Number = 50;
  4.     public function MySprite() {
  5.       addEventListener(Event.ADDED_TO_STAGE, initialize);
  6.     }
  7.     private function initialize(eventObject:Event):void {
  8.       square = new Quad(nUnit, nUnit, 0x0000FF);
  9.       addChild(square);
  10.       square.x = nUnit;
  11.       square.y = nUnit;
  12.       square.pivotX = nUnit / 2;
  13.       square.pivotY = nUnit / 2;
  1.     }
  1.   }
  2. }

そして、クラス定義のASファイルと同じ場所に保存したFlashムービー(FLA)ファイルには、メインタイムラインにつぎのフレームアクションが書かれているものとします。[パブリッシュプレビュー]で確かめると、ステージに50ピクセル四方の青い矩形のQuadインスタンスが表れます(図001)。

// フレームアクション: メインタイムライン
import starling.core.Starling;
var myStarling:Starling = new Starling(MySprite, stage);
myStarling.start();

図001■ステージに矩形のQuadインスタンスを置く
図001

これらのスクリプトの内容およびパブリッシュ設定などのStarlingフレームワークを使うために必要な準備については、基本的に「Starlingフレームワークを使う」でご説明しています。詳しくは、このノートをお読みください。


02 クリックを扱うために用いるイベントおよびプロパティとメソッド
マウスのインタラクティブな操作は、DisplayObject.touchイベントで扱われます。そして、どのような操作をマウスでしたのかは、DisplayObject.touchイベントのリスナーが引数に受取るTouchEventオブジェクトからTouchEvent.getTouch()メソッドによりTouchオブジェクトを得て、そのTouch.phaseプロパティで調べます[*1]

Touch.phaseプロパティがとる文字列の値は、TouchPhaseクラスに定数として定められています。Touchクラスという名前からもおわかりのように、マウスだけでなくタッチスクリーンのインタラクションも同じように扱えます。TouchPhaseクラスの定数とタッチスクリーンおよびマウスの操作は、次表001のとおりです。

表001■TouchPhaseクラスの定数とタッチスクリーンおよびマウスの操作
TouchPhaseクラスの定数 操作
タッチスクリーン マウス
BEGAN 画面に触れる マウスボタンを押す
ENDED 画面から指を離す マウスボタンを放す
HOVER マウスポインタを重ねる
MOVED 画面に触れた指を動かす ボタンは押したままマウスを動かす
STATIONARY 画面に触れたまま動かさない ボタンを押したままマウスは動かさない

マウスのクリックに当たるTouch.phaseプロパティの値は、TouchPhase.ENDEDです。Flashに定義済みのInteractiveObject.mouseUpイベント(定数MouseEvent.MOUSE_UP)と違って、予めインスタンスの上でマウスボタンが押されていなければなりません。けれど、後に述べるとおり、InteractiveObject.clickイベント(定数MouseEvent.CLICK)とも、細かく見ると動きが異なります。

さて、Touch.phaseプロパティを調べるには、Touchオブジェクトを得なければなりません。DisplayObject.touchイベントのリスナーが受取ったTouchEventオブジェクトからTouchオブジェクトを取出すのはTouchEvent.getTouch()メソッドです。引数はふたつあります。

TouchEventオブジェクト.getTouch(DisplayObjectオフジェクト, TouchPhaseクラス定数)

第1引数は、DisplayObject.touchイベントの受取りを調べる表示リストの頂点となるDisplayObjectインスタンスです。TouchEvent.getTouch()メソッドは、この引数に定めたインスタンスとその表示リスト下層の子インスタンスからTouchオブジェクトを探します。さらに第2引数のTouchPhaseクラス定数で、DisplayObject.touchイベントの操作を絞り込めます。デフォルト値はnullで、すべてのDisplayObject.touchイベントになります。ふたつの引数で定まるTouchオブジェクトが見つかればそのオブジェクト、なければnullが返ります。

もっとも、DisplayObject.touchイベントを扱うリスナーは、EventDispatcher.addEventListener()メソッドで決まります。それに、TouchEvent.getTouch()メソッドの第2引数を組合わせれば、第1引数を絞り込まなければならないことは多くありません。その場合、第1引数は表示リスト最上位のStageオブジェクトを渡します。

[*1] 併せて、akihiro kamijo「Starling のタッチイベントと Touch クラス」が参考になります。


03 インスタンスのクリックを扱うスクリプト
ステージに置いたQuadインスタンスをクリックしたとき、下に動かすようにしてみます。Starlingルートクラス(MySprite)の定義は以下のスクリプト001のとおりです。まず、必要なクラスのimport宣言(第7〜9行目)をしたうえで、QuadインスタンスのDisplayObject.touchイベントにリスナーメソッド(dispatchMouseEvent())を加えます(第23行目)。

つぎに、リスナーメソッド(dispatchMouseEvent())はさまざまなマウス操作を同じDisplayObject.touchイベントとして受取るため、操作に応じたメソッドは別に定めることにして交通整理に徹しました。TouchEvent.getTouch()メソッドにより、インスタンス上でクリックしたマウスボタンを放したときとき(定数TouchPhase.MOVED)のTouchオブジェクトが取出され(第30行目)、オブジェクトがあればクリックで行う処理のメソッドを呼出します(第31〜33行目)。

そして、クリック用のメソッド(onClick())は、マウス操作が加えられたインスタンスをEvent.currentTargetプロパティで取出し(第26行目)、そのインスタンスの位置を5ピクセル下げます(第27行目)。

スクリプト001■Quadインスタンスをクリックするたびに下に動かす
    // ActionScript 3.0クラス定義ファイル: MySprite.as
  1. package {
  2.   import flash.geom.Point;
  3.   import starling.display.DisplayObject;
  4.   import starling.display.Sprite;
  5.   import starling.display.Quad;
  6.   import starling.events.Event;
  7.   import starling.events.TouchEvent;
  8.   import starling.events.Touch;
  9.   import starling.events.TouchPhase;
  10.   public class MySprite extends Sprite {
  11.     private var square:Quad;
  12.     private var nUnit:Number = 50;
  13.     public function MySprite() {
  14.       addEventListener(Event.ADDED_TO_STAGE, initialize);
  15.     }
  16.     private function initialize(eventObject:Event):void {
  17.       square = new Quad(nUnit, nUnit, 0x0000FF);
  18.       addChild(square);
  19.       square.x = nUnit;
  20.       square.y = nUnit;
  21.       square.pivotX = nUnit / 2;
  22.       square.pivotY = nUnit / 2;
  23.       square.addEventListener(TouchEvent.TOUCH, dispatchMouseEvent);
  24.     }
  25.     private function onClick(eventObject:TouchEvent):void {
  26.       var instance:DisplayObject = eventObject.currentTarget as DisplayObject;
  27.       instance.y += 5;
  28.     }
  29.     private function dispatchMouseEvent(eventObject:TouchEvent):void {
  30.       var myTouch:Touch = eventObject.getTouch(stage, TouchPhase.ENDED);
  31.       if (myTouch) {
  32.         onClick(eventObject);
  33.       }
  34.     }
  35.   }
  36. }

これで、ステージのQuadインスタンスをクリックするたびに、位置が5ピクセルずつ下がります。ただ、細かい動きでひとつ気になります。インスタンスの上でマウスボタンを押せば、プレスしたままマウスボタンをインスタンスの外で放しても、クリック用のメソッドが呼ばれてしまいます(図002)。つまり、TouchPhase.ENDEDが捉えるのは、インスタンス上でマウスボタンを押し続けた後、ボタンをどこかで放したというマウス操作なのです。

図002■インスタンス上でマウスボタンをプレスしたままインスタンス外で放しても下に動く
図002左
インスタンス上でマウスボタンを押す
図002右
マウスボタンをプレスしたままインスタンス外で放す

04 マウスボタンを放したのがインスタンス上か外か切り分ける
前掲スクリプト001では、インスタンス上でマウスボタンを押してしまったら、もはや押さなかったことにはできません。ボタンなどのインターフェイスの動きとしては不十分です。しかし、TouchPhaseクラスの定数で調べられるマウス操作から、ボタンを放したのがインスタンス上なのかどうかは切り分けられません。

そこで、マウスボタンを放したとき、ポインタの座標を調べて、それがインスタンスの上にあるかどうか確かめます。DisplayObject.touchイベントが起こったときのマウスポインタの座標は、Touch.getLocation()メソッドでPointオブジェクトとして得られます。引数のDisplayObjectインスタンスは、基準とする座標空間を定めます。

Touchオブジェクト.getLocation(DisplayObjectオフジェクト)

ある座標がインスタンスの上にあるかどうかは、DisplayObject.hitTest()メソッドでわかります。第1引数には、参照するDisplayObjectオブジェクトから見た座標を、Pointオブジェクトで定めます。第2引数にtrueを渡すと、マウス(またはタッチ)操作できる表示されたインスタンスだけを対象として、座標の重なりが調べられます(デフォルト値はfalse)。

DisplayObjectオブジェクト.hitTest(Pointオブジェクト, マウスまたはタッチ操作の対象のみ)

Flash定義済みのDisplayObject.hitTestPoint()メソッドと異なり、戻り値はブール(論理)値ではなく、座標と重なるDisplayObjectインスタンスです[*2]。また、重なりはインスタンスの矩形領域(Rectangleオブジェクト)の内側かどうかで決まります。座標が重ならないときの戻り値はnullです。

それでは前掲スクリプト001でDisplayObject.touchイベントに加えたリスナーメソッド(dispatchMouseEvent())を書替えます。以下のスクリプト002は、リスナーメソッドのifステートメントに、ボタンを放したポインタ座標がインスタンス上かどうかの判定を加えました(第32〜34行目)。

スクリプト002■Quadインスタンスのクリックをマウスボタンがインスタンス上で放された場合にかぎる
    // ActionScript 3.0クラス定義ファイル: MySprite.as
  1. package {
  2.   import flash.geom.Point;
  3.   import starling.display.DisplayObject;
  4.   import starling.display.Sprite;
  5.   import starling.display.Quad;
  6.   import starling.events.Event;
  7.   import starling.events.TouchEvent;
  8.   import starling.events.Touch;
  9.   import starling.events.TouchPhase;
  10.   public class MySprite extends Sprite {
  11.     private var square:Quad;
  12.     private var nUnit:Number = 50;
  13.     public function MySprite() {
  14.       addEventListener(Event.ADDED_TO_STAGE, initialize);
  15.     }
  16.     private function initialize(eventObject:Event):void {
  17.       square = new Quad(nUnit, nUnit, 0x0000FF);
  18.       addChild(square);
  19.       square.x = nUnit;
  20.       square.y = nUnit;
  21.       square.pivotX = nUnit / 2;
  22.       square.pivotY = nUnit / 2;
  23.       square.addEventListener(TouchEvent.TOUCH, dispatchMouseEvent);
  24.     }
  25.     private function onClick(eventObject:TouchEvent):void {
  26.       var instance:DisplayObject = eventObject.currentTarget as DisplayObject;
  27.       instance.y += 5;
  28.     }
  29.     private function dispatchMouseEvent(eventObject:TouchEvent):void {
  30.       var myTouch:Touch = eventObject.getTouch(stage, TouchPhase.ENDED);
  31.       if (myTouch) {
  32.         var instance:DisplayObject = eventObject.currentTarget as DisplayObject;
  33.         var myPoint:Point = myTouch.getLocation(instance);
  34.         if (instance.hitTest(myPoint, true)) {
  35.           onClick(eventObject);
  36.         }
  37.       }
  38.     }
  39.   }
  40. }

まず、TouchEventオブジェクトのEvent.currentTargetプロパティから、マウス操作が加えられたインスタンスの参照(instance)を得ます(スクリプト002第32行目)。つぎに、Touch.getLocation()メソッドで、インスタンスから見たポインタ座標(myPoint)を調べます(第33行目)。そのうえで、DisplayObject.hitTest()メソッドによりマウス座標の重なったオブジェクトを取出して、インスタンスが得られたときにクリック用のメソッド(onClick())を呼出しています(第34〜35行目)[*3]

これで、クリック用のメソッド(onClick())は、インスタンス上にポインタがあるときにマウスボタンを押し、かつその上で放したときのみ呼出されるようになります。

[*2] たとえば、Quadインスタンスに対してDisplayObject.hitTest()メソッドを呼出せば、座標が重なっていたときの戻り値はそのQuadインスタンス自身です。ただし、DisplayObjectContainerクラスはこのメソッドを再定義(オーバーライド)して、DisplayObjectContainer.hitTest()として定めています。SpriteなどDisplayObjectContainerインスタンスは自らは表示する要素をもたないので、すべての子インスタンスを調べ、座標と重なる最前面のインスタンスを返します。

[*3] インスタンス外でマウスボタンを放したときの処理が必要なときは、ifステートメント(スクリプト002第34〜36行目)の後にelseステートメントで加えることができます。


作成者: 野中文雄
更新日: 2012年5月22日 StarlingフレームワークのDisplayObject.hitTest()メソッドをDisplayObject.hitTestPoint()としていた誤記を修正。
作成日: 2012年4月4日


Copyright © 2001-2012 Fumio Nonaka.  All rights reserved.