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

第31回マウスのロールオーバー

前回の第30回「マウスイベントとインスタンスの兄弟・親子の関係」に引続き、今回もマウスイベントの扱いをお題にする。とくに、マウスのロールオーバーをネタに、複数のインスタンスを含んだマウスイベントの捉え方について解説したい。

InteractiveObject.mouseOverとInteractiveObject.rollOverイベント

マウスのロールオーバーを捉えるイベントには、InteractiveObject.mouseOver(定数MouseEvent.MOUSE_OVER)とInteractiveObject.rollOver(定数MouseEvent.ROLL_OVER)がある(※1)。このふたつのイベントの違いについて調べるムービーをつくってみよう。MovieClipシンボル(シンボル名Parent)の中に、ふたつの MovieClipインスタンスを入れ子にする。ふたつのインスタンス名は、それぞれpen0_mcとpen1_mcだ(図1)。

図1 MovieClipシンボル内にふたつのMovieClipインスタンスを入れ子にする
図1 MovieClipシンボル内にふたつのMovieClipインスタンスを入れ子にする

このMovieClipシンボルのインスタンスをひとつメインタイムラインに配置し、インスタンス名はparent_mcとする。イベントInteractiveObject.mouseOverInteractiveObject.rollOverとは、そのターゲットのインスタンスをどう捉えるかが違っている。親のMovieClipインスタンスparent_mcの第1フレームアクションに以下のスクリプト1を書き、ふたつのイベントにリスナー関数xTraceを登録する(図2)。

スクリプト1 イベントInteractiveObject.mouseOverとInteractiveObject.rollOverにリスナー関数を登録
// MovieClip: マウスイベントを処理するparent_mc
// MovieClipインスタンスpen0_mcとpen1_mcを配置
// 第1フレームアクション
addEventListener(MouseEvent.MOUSE_OVER, xTrace);
addEventListener(MouseEvent.ROLL_OVER, xTrace);
function xTrace(eventObject:MouseEvent):void {
  trace(eventObject.type,
   eventObject.target.name,
   eventObject.currentTarget.name);
}
図2 親のMovieClipインスタンスparent_mc内に第1フレームアクションを記述
図2 親のMovieClipインスタンスparent_mc内に第1フレームアクションを記述

リスナー関数xTrace()は、受取ったイベントオブジェクトから、3つのプロパティを取出す。Event.typeEvent.targetおよびEvent.currentTargetプロパティだ。ただし、後のふたつはインスタンスが区別できるようDisplayObject.nameプロパティを調べたうえで、trace()関数により3つの情報を[出力]する。なお、シンボル内に入れ子にしたふたつのインスタンスには、名前をつけたほかはとくに設定はしていない。

[ムービープレビュー]して、入れ子の一方のMovieClipインスタンス(pen0_mc)にマウスポインタを重ねると、イベントInteractiveObject.mouseOverInteractiveObject.rollOverがともに発生する。ただし、つぎのようにEvent.targetプロパティのインスタンスの[出力]が異なる。

rollOver parent_mc parent_mc
mouseOver pen0_mc parent_mc

InteractiveObject.mouseOverイベントではマウスポインタを重ねた子のインスタンスが捉えられているのに対し、InteractiveObject.rollOverイベントはリスナーを登録した親に発生したものと扱われるのだ。

さらに、マウスポインタを他方のインスタンス(pen1_mc)の上に移すと、InteractiveObject.mouseOverイベントはインスタンスpen1_mcに対して改めて発生する。しかし、InteractiveObject.rollOverイベントは起こらない(図3)。つまり、InteractiveObject.mouseOverイベントは子インスタンスごとに、InteractiveObject.rollOverイベントはリスナーが登録されたインスタンスをひとつとみなして発生するのである。

図3 InteractiveObject.mouseOverイベントは子インスタンスごとに発生する
図3 InteractiveObject.mouseOverイベントは子インスタンスごとに発生する

子のインスタンスに対するマウスイベントの発生を止める

マウスのロールオーバーについては、子インスタンスごとにイベントを受取りたいときはInteractiveObject.mouseOverリスナーを登録した親インスタンスでまとめて捉えたいときにはInteractiveObject.rollOverと、ふたつを使い分ければよいと一応はいえる。しかし、InteractiveObject.mouseOverイベントを使いつつ、子インスタンスごとではなく、親インスタンスでまとめて扱いたい場合があるかもしれない。

それだけでなく、マウスクリックを捉えるInteractiveObject.clickイベントも、実は子インスタンスごとに発生する。つまり、前述のムービーのようにふたつの子インスタンスが入れ子になっている場合(前掲図3参照)、一方の子インスタンス上でマウスボタンを押したまま、ポインタを他方のインスタンス上に移してボタンを放したとき、InteractiveObject.clickイベントは発生しない。しかも、ロールオーバーと違って、クリックを親インスタンスでまとめて受取るイベントというものは別に用意されてない。

そうなると、子インスタンスごとにイベントを発生させない手段が知りたい。ひとつは、前回紹介したInteractiveObject.mouseEnabledプロパティfalseにすることだ。すると、子インスタンスへのマウスイベントは親インスタンスが直接受取れる。ただし、その設定をしていない子インスタンスは、相変わらず自分に対するマウスイベントと捉えてしまう。したがって、マウスイベントを親インスタンスがまとめて受取るためには、すべての子インスタンスのInteractiveObject.mouseEnabledプロパティをfalseにしなければならない(図4)。

pen0_mc.mouseEnabled = false;
pen1_mc.mouseEnabled = false;
図4 すべての子インスタンスのInteractiveObject.mouseEnabledプロパティをfalseに設定
図4 すべての子インスタンスのInteractiveObject.mouseEnabledプロパティをfalseに設定

もうひとつ、子インスタンスごとにマウスイベントが発生しないように、親インスタンスのプロパティを使って設定できる。DisplayObjectContainer.mouseChildrenプロパティfalseにすると、その子インスタンスはマウスイベントを自分に対して受取らなくなり、親インスタンスへのイベントとして扱われる(図5)。すると、InteractiveObject.mouseOverイベントも、InteractiveObject.rollOverと同じ動きになる。

mouseChildren = false;
図5 DisplayObjectContainer.mouseChildrenプロパティをfalseにすると親がマウスイベントを受取る
図5 DisplayObjectContainer.mouseChildrenプロパティをfalseにすると親がマウスイベントを受取る
画像

サムネイルへのロールオーバーで表示画像を切替える

ロールオーバーを使う練習として、サンプルムービーをひとつつくってみよう。ステージの端にサムネイル画像を並べて、それらにロールオーバーしたとき、対応する大きい画像の表示を切替える(図6)。サムネイルと表示画像とをどう結びつけるかが、ひとつのポイントだ。

サムネイルは3つMovieClipインスタンスで並べ、インスタンス名はbutton0_mcからbutton2_mcとした。大きい表示画像も予めタイムラインに重ねて置いておき、DisplayObject.visibleプロパティにより表示を切替えることにする。MovieClipインスタンス名は、サムネイルと番号を対応させて、my0_mcからmy2_mcとしておこう。

図6 サムネイルと表示画像をステージに配置する
図6 サムネイルと表示画像をステージに配置する

以下のフレームアクションは、サムネイルのインスタンスにロールオーバーすると、対応する大きい画像の表示を切替える(スクリプト2)。サムネイルのインスタンス(button0_mc~button2_mc)には、それぞれのInteractiveObject.rollOverイベント(定数MouseEvent.ROLL_OVER)に同じリスナー関数xShow()を登録した。

サムネイルと表示画像を結びつけるために、すべてのサムネイルのインスタンス(button0_mc~button2_mc)に同じ名前の変数(show_mc)を設定し、そこに対応する表示画像のインスタンスを納めた。リスナー関数xShow()は、引数に受取ったイベントオブジェクトのEvent.currentTargetプロパティからロールオーバーしたサムネイルのインスタンスを取出し、その変数に納められた対応する画像のインスタンスを表示するという仕組みだ。

スクリプト2 サムネイルにロールオーバーすると対応する画像の表示を切替える
// タイムライン: メイン
// MovieClipインスタンス
// サムネイル: thum0_mc~thum2_mc
// 表示画像: my0_mc~my2_mc
// フレームアクション
var glow:GlowFilter = new GlowFilter(0x000033);
var dropShadow:DropShadowFilter = new DropShadowFilter();
var filters_array:Array = [glow, dropShadow];
button0_mc.addEventListener(MouseEvent.ROLL_OVER, xShow);
button1_mc.addEventListener(MouseEvent.ROLL_OVER, xShow);
button2_mc.addEventListener(MouseEvent.ROLL_OVER, xShow);
// 対応する画像のインスタンスを変数に設定する
button0_mc.show_mc = my0_mc;
button1_mc.show_mc = my1_mc;
button2_mc.show_mc = my2_mc;
xClearAll();
function xShow(eventObject):void {
  var my_mc:MovieClip = eventObject.currentTarget as MovieClip;
  var show_mc:MovieClip = my_mc.show_mc;   // 対応する画像のインスタンスを取得
  xClearAll();   // 一旦すべての画像を非表示
  // 改めて表示画像を設定
  show_mc.visible = true;
  show_mc.filters = filters_array;
}
function xClearAll():void {
  my0_mc.visible = false;
  my1_mc.visible = false;
  my2_mc.visible = false;
  my0_mc.filters = [];
  my1_mc.filters = [];
  my2_mc.filters = [];
}

もうひとつちょっとしたテクニックは、トグルボタンのようにひとつをオンにしたら他はすべてオフにするという処理だ。このサンプルでひとつの画像を表示したら、他はすべて非表示にしなければならない。そういうとき、一旦すべてをオフつまり非表示にしてから、改めて対象のものだけオンつまり表示すればよい。こうすると、今どれがオンになっているのかということも気にしなくて済む。

関数xClearAll()は、すべての画像を非表示にする。リスナー関数xShow()はこの関数を呼出したうえで、変数から取得した対応画像の表示を行っている。なお、画像のアウトラインがわかりにくいものもあるので、グローとドロップシャドウのフィルタもかけた。このサンプルであれば、フィルタはオーサリング時に予め設定しておいても構わない。ダイナミックなフィルタの適用と破棄は、いわば練習として加えてみた。

[ムービープレビュー]を確かめると、ロールオーバーしたサムネイルに応じて、左側の大きい表示画像が切替わる(図7)。

図7 サムネイルにロールオーバーすると画像が対応して切替わる
図7 サムネイルにロールオーバーすると画像が対応して切替わる
画像

ActionScript 1.0や2.0では、異なるインスタンスを結びつけるためにインスタンス名がよく使われた(※2)。ActionScript 3.0でも、その手法は一応使える。しかし、DisplayObject.nameプロパティは、trace()関数で[出力]してインスタンス名を確かめる以外には、あまり使い勝手はよくない。

ActionScript 3.0では、できるだけインスタンスの参照を使う仕組みにする方がよいだろう。このサンプルでは、MovieClipインスタンスの変数に参照を加えた。マウスイベントのお題は今回で終える。しかし、次回も同じサンプルをネタに、インスタンスの参照の扱いについて考えてみたい。つぎのお題は、 Dictionaryクラスだ。

今回解説した次のサンプルファイルがダウンロードできます。

おすすめ記事

記事・ニュース一覧