ActionScript 3.0で始めるオブジェクト指向スクリプティング

第5回イベントリスナーを使う

前回の第4回関数を使ってパーツ化するでは、まとまった処理を関数として定義し、いつでも何度でも呼出せるようにした。今回は、⁠イベントリスナー」について学習する。関数をイベントリスナーとして登録することにより、指定したイベントが発生したときに、その関数が呼出されるようにしてみたい。

イベントとは

FlashのActionScriptは、イベントをベースにして処理が構成される。イベントというのは、ユーザーのマウスクリックやキーボード入力のようなインタラクションから、外部データの読込みや、ディスプレイの描画更新のようなシステムの処理まで、さまざまな事象・状態の変化にともなって発せられるFlash Playerからの信号である。

その信号を検知することにより、ユーザーがクリックしたとか入力したとか、あるいは外部データの読込みが終わった、画面がリフレッシュされたといった事象の瞬間を捉え、必要な処理を実行することができる。

イベントを受取ってスクリプトで処理をするには、Flash Playerがイベントを伝える相手つまりターゲットと、イベントの種類を知らなければならない。ただ、この段階では、ターゲットとしてはまずムービークリップを扱い、イベントもその都度ひとつひとつ覚えていけばよい。学習が進むにつれ、イベントの体系やその調べ方も徐々に身についていくだろう。

表1 ムービークリップが受取るイベントの例
イベント発生時期
clickユーザーがインスタンスをマウスでクリックしたとき
keyDownユーザーがキーボードのキーを押したとき
enterFrame画面の描画が更新されるとき

今回は、前回つくった時計のアニメーションの続きを、イベントを使って作成する図1※1⁠。アニメーションは、画面の描画が更新されるたびに、ステージ上のイメージを変化させる処理だ。したがって、利用するイベントはenterFrameになる表1⁠。描画更新の頻度は、フレームレートに依存する。デフォルトの12fpsなら、スクリーンは1/12秒ごとにリフレッシュされることになる。したがって、このイベントも同じ1/12秒間隔で発生する。

図1 前回作成した時計のアニメーション
図1 前回作成した時計のアニメーション

イベントとイベントリスナー

ActionScript 3.0では、イベントリスナーという仕組みによってイベントを扱う。まず第1に、イベント発生時に行いたい処理を、関数として定義する。そして第2に、イベントを受取るターゲットとなるインスタンスに、その関数を登録する。すると、イベントが発生したときに、その関数が呼出されることになる。

イベントリスナーを使った処理の書き方
  1. リスナー関数の定義
  2. ターゲットインスタンスにイベントリスナーとして登録

ターゲットのインスタンスに登録された関数は、イベントの発生を検知(listen)して呼出される。そのため、⁠イベントリスナー」とか「リスナー関数」と呼ばれる。前回作成した時計のムービーでは、すでにアニメーションの処理が関数として定義してある図2⁠。これは、ほぼそのままリスナー関数として用いることができる。

図2 時計のシンボル内の第1フレームアクション
図2 時計のシンボル内の第1フレームアクション

他方、メインタイムラインのフレームアクションに記述した、関数の呼出しは要らなくなる。イベントリスナーとして登録すれば、リスナー関数は自動的に呼出されるからである。また、関数の呼出しが不要になれば、それを繰返し実行するためのフレームループも必要ないので、メインタイムラインは1フレームで足りる図3⁠。

図3 メインタイムラインのフレームアクションは削除して1フレームに
図3 メインタイムラインのフレームアクションは削除して1フレームに ↓ 図3 メインタイムラインのフレームアクションは削除して1フレームに

addEventListener()メソッド

ターゲットのインスタンスにイベントリスナーを登録するには、addEventListener()メソッドを使う。このメソッドは、つぎのような文法で使用する[2]⁠。

ターゲット.addEventListener(イベント, リスナー関数)

ターゲットは、今回は時計のムービークリップインスタンスだ。なお、このaddEventListener()メソッドのステートメントは、時計のムービークリップシンボルの第1フレームアクションに追加する予定である。スクリプトを記述しているインスタンスがターゲットのときは、ターゲットの記述は省略してもよい。

括弧()の中に指定するのは、⁠引数」⁠ひきすう)と呼ばれるパラメータである。第1引数は、イベント名で、今回は"enterFrame"を指定する。第2引数として渡すのは、リスナー関数の識別子だ。すでに関数は定義済み図2なので、その識別子であるxSetTimeを指定すればよい。

それでは、時計のシンボルの第1フレームアクションの最後に、つぎの1行のステートメントを加えてみよう。なお、前述のとおり、ターゲットはスクリプトを記述したムービークリップインスタンスなので省略した。

addEventListener("enterFrame", xSetTime);

[ムービープレビュー]を試してみると、⁠出力]パネルにつぎのような内容のエラーが表示される[3]⁠。

xSetTime()の引数の数が一致していません。

実は、リスナー関数が呼出されるとき、引数がひとつ渡されることになっている。ところが、関数xSetTime()の定義には、引数が宣言されていない。ActionScript 3.0では、関数呼出し時に引数が渡される場合には、その関数の定義に引数を受取る宣言がされていないとエラーになるのだ。

引数を受取る関数の定義は、一般につぎのようになる。引数には、任意の変数を、必要な数だけカンマ(,)区切りで宣言する。


function 関数名(引数1:データ型, 引数2:データ型, ... , 引数n:データ型):戻り値のデータ型 {
   ステートメント;
}

リスナー関数の場合には、引数はひとつで、データ型はイベントによる。enterFrameイベントの場合には、Eventで型指定する。引数の名前は、任意の識別子だ。ただ、リスナー関数に渡される引数はイベントオブジェクトと呼ばれるため、eventObjectのような名前がよく用いられる。

関数xSetTimeに正しく引数を宣言した、時計のムービークリップの第1フレームアクションは、以下のとおりだスクリプト1⁠。

スクリプト1 enterFrameイベントにリスナー関数を登録した時計のムービークリップのフレームアクション
function xSetTime(eventObject:Event):void {
  var nSeconds:Number = getTimer()/1000;
  var nMinutes:Number = nSeconds/60;
  second_mc.rotation = nSeconds*6;
  minute_mc.rotation = nMinutes*6;
}
addEventListener("enterFrame", xSetTime);

addEventListener()メソッドの引数について、もう少し補足しよう。第1引数は、イベントの名前を文字列で指定する。文字列は、ダブルクォーテーション(")で括って記述する必要がある。

第2引数のリスナー関数を指定するときには、呼出しの括弧()はつけてはならない。リスナー関数を呼出すのは、イベントが発生したときである。addEventListener()メソッドには、イベント発生時に関数が呼出せるよう、その識別子を渡すだけだ。ターゲットのインスタンスは、その識別子を使って、タイムラインにメモリされている関数の定義を取出すのである。識別子は文字列ではないので、ダブルクォーテーション(")はつけない。

これで、すべての時計のアニメーションのスクリプトが、ムービークリップシンボルのフレームアクションにまとまった図4⁠。⁠ムービープレビュー]で、動作を確認しよう。

図4 ムービークリップのフレームアクションにまとめられた時計のアニメーションの処理
図4 ムービークリップのフレームアクションにまとめられた時計のアニメーションの処理

イベントをクラスの定数で指定する

addEventListener()メソッドの第1引数であるイベントには、別の指定の仕方がある。それは、イベントのクラスの定数を使う方法だ。具体的に、前記スクリプト1のenterFrameイベントの場合には、addEventListener()メソッドのステートメントをつぎのように書替えることになる。

addEventListener(Event.ENTER_FRAME, xSetTime);

Eventというのはリスナー関数xSetTime()の引数eventObjectに指定したデータ型で、実はenterFrameイベントのイベントオブジェクトをつくっているクラスである。そのEventクラスに、ENTER_FRAMEという一種のプロパティがある。プロパティと違うのは、値が一定で変わらないことだ。そのため、正確にはクラスの「定数」と呼ばれる。

では、定数Event.ENTER_FRAMEの値は何かというと、文字列"enterFrame"である。つまり、addEventListener()イベントの第1引数に文字列で"enterFrame"と記述した場合と、スクリプトの動作上はまったく違いがない。しかし、スクリプティングの実践上、ふたつ意味がある。

第1は、シンタックスがチェックされ、コードヒントも表示されることだ図5⁠。定数を正しく記述すれば、まずシンタックスカラーが適用される。また、クラス名Eventの後にドット(.)を打つとコードヒントが表れるので、タイプミスの心配もない。それでも間違えたときには、⁠コンパイルエラー]が発生する。

図5 シンタックスカラーとコードヒントが適用される
図5 シンタックスカラーとコードヒントが適用される

それに対して、文字列で指定した場合、シンタックスカラーは文字列であることを示すだけだ。誤って、たとえば頭を大文字にした"EnterFrame"と入力しても、何のエラーも起こらず、単に動作しなくなる。

第2は、イベントオブジェクトの型が決まることだ。イベントの定数をもっているクラスが、リスナー関数の受取る引数のイベントオブジェクトを生成する。したがって、引数の型には、そのクラスを指定すればよい。定数Event.ENTER_FRAMEを指定して登録したリスナー関数は、引数をEvent型で指定することになる。

イベントは、ActionScript 3.0を理解するうえで、もっとも重要な概念のひとつである。初めは面倒でも、イベントの定数をリファレンスで調べることによって、イベントの種類やそのクラスの構成などについての理解も深まるはずだ。スクリプト1のaddEventListener()メソッドの呼出しで、イベントの指定を定数に替えたのが次のスクリプト2である。

スクリプト2
function xSetTime(eventObject:Event):void {
  var nSeconds:Number = getTimer()/1000;
  var nMinutes:Number = nSeconds/60;
  second_mc.rotation = nSeconds*6;
  minute_mc.rotation = nMinutes*6;
}
addEventListener(Event.ENTER_FRAME, xSetTime);

すべてのスクリプトがムービークリップシンボル内の第1フレームアクションにまとまったので、⁠ライブラリ]からこのインスタンスをステージにドロップするだけで、ただちに時計のアニメーションが開始できる。スクリプトによるアニメーションをパーツ化する練習は、これでひと区切りだ。次回からは、実際の時を刻む時計の作成に入る。

おすすめ記事

記事・ニュース一覧