MovieClip.onRollOverが動作しなくなる [Edit]

問題ムービーのレシピ
この不思議な現象を再現するには、いくつかの条件を満たす必要があります。問題のムービーのつくり方は、つぎの3つのステップです。

[1]ムービーにレイヤーを3つ作成します。2つのレイヤーにはそれぞれMovieClipをひとつずつ置き、3番目のレイヤーはスクリプト用に使います。

[2]ひとつ目のレイヤーには、MovieClipを第1フレームから最終フレームまで配置します。2つ目のレイヤーは、第2フレームから最終フレームまでMovieClipを設定します。インスタンス名は、それぞれmy1_mc、my2_mcとします。2つのMovieClipは、同じシンボルで構いません。

[3]メインのタイムラインの第1フレームと第2フレーム、そして最終フレームに、それぞれフレームアクションを設定します。
// 第1フレームアクション
my1_mc.onRollOver = function() {
trace(this);
this.swapDepths(1);
};

// 第2フレームアクション
my2_mc.onRollOver = function() {
trace(this);
this.swapDepths(1);
};

// 最終フレームアクション
this.gotoAndPlay(this._currentframe-1);

[ムービーの構造]
ムービーの構造

これで、ムービーはできあがりです。「ムービープレビュー」で、不思議な現象を確認してみましょう。

MovieClip.onRollOverが動作しなくなる現象
現象は、実際にサンプルSWFムービーでお試しいただくのが、わかりやすいでしょう。また、ソースのFLAファイル(Zip圧縮約4KB)もダウンロード可能です。SWFの再生あるいはソースファイルを開くためには、それぞれFlash Player 6およびFlash MXが必要です。

2つのMovieClipには、onRollOverイベントハンドラメソッドを設定しましたので、ボタンとして動作します。まず、一方のMovieClipにロールオーバー、つまりマウスボタンを重ねます。カーソルは指先に変わり、「出力」ウィンドウにはインスタンス名が表示されます。見た目ではわかりませんが、onRollOverに定義したfunctionで、MovieClip.swapDepthsメソッドを使って、MovieClipの深度を1に切替えています(上記第1フレームアクションおよび第2フレームアクション参照)。

つぎに、もう一方のMovieClipにロールオーバーします。カーソルはやはり指先に変わり、インスタンス名が出力されます。このMovieClipにも、深度を変更する同じ内容のfunctiononRollOverメソッドに設定されています。見た目でわかりませんが、このインスタンスの深度は1に設定され、すでにその深度にあった最初のMovieClipと入替わるはずです。

では、最初のMovieClipにポインタを戻して、ロールオーバーさせてみましょう。今度は指先カーソルに変わらず、「出力」ウィンドウにも何も表示されません。このインスタンスのonRollOverメソッドが消滅してしまったのです。

この現象を再現するには、上述の3つのステップが必須です。つまり、まず[1]最終フレームでは、再生ヘッドを止めず(stopアクション/メソッドを使わず)、ループさせなければなりません。つぎに、[2]MovieClipの配置は、フレームの頭の位置をずらしておくことが条件です。そして、[3]onRollOverメソッドは、2つのMovieClipを配置したタイムラインのフレームアクションで設定する必要があります。ムービークリップシンボルの中にイベントハンドラメソッドを定義したのでは、現象が再現しません。

つまりこの不具合は、特定の条件下で生じるめずらしい現象だといえそうです。この条件さえわかってしまえば、対処の方法は難しくありません。一番簡単なのは、[1]のフレームループを避け、stopアクション/メソッドで再生ヘッドを止めることでしょう。イベントハンドラアクションのMovieClip.onEnterFrameなどを使えば、フレームループが必要な局面はかぎられると思われます。また、[3]のMovieClip.onRollOverメソッドを、配置されたタイムラインでなく、そのムービークリップの中に定義する方法も考えられます。

MovieClip.swapDepthsの不思議
とはいえ、何が発生しているのか、やはり気になります。もう少し見てみましょう。

実はswapDepthsメソッドをオーサリング時に配置したMovieClipに適用すると、元のインスタンスが残像のように複製されてしまう現象が、これまでもさまざまな状況で確認されています。今回の問題でも、この現象が原因となっているようです。

結果が見やすいように、MovieClip.onRollOverメソッドに設定したfunctionに、ステートメントを1行追加します。

// 第1フレームアクション
my1_mc.onRollOver = function() {
trace(this);
this.swapDepths(1);
this._rotation += 30; // 角度を30度回転
};

第2フレームアクションのfunctionにも、同じ変更を加えます。そのうえで、「ムービープレビュー」を確認してみます。

MovieClip(青)にロールオーバー

MovieClip(青)にロールオーバーすると、深度が1に変わると同時にインスタンスが30度回転します。ところが、深度を変更して回転する前の状態のインスタンスが、残像のように複製されています。

つぎに、もう一方のMovieClip(赤)にロールオーバーします。そうすると、こちらもインスタンスの深度が1に変更されて、30度回転します。ただし、今回はすでに深度1にMovieClip(青)が存在しますので、そのインスタンスとMovieClip.swapDepthsメソッドで深度が入替わり、30度回転した以外見た目の変化は(MovieClip同士が重なっていないかぎり)ないはずです。

MovieClip(赤)にロールオーバー

ところが、先に深度1に存在したMovieClip(青)は、消滅しています。その代わりに、ロールオーバーしたMovieClip(赤)の残像が、またしても複製されます。これ以降、先にswapDepthsメソッドで深度変更したMovieClip(青)にロールオーバーしても、ボタンとしての反応は一切しなくなります。つまり、カーソルは指先に変わらず、深度変更・回転ともに行われません。

ここで、[制御]メニューから[変数のリストアップ]を実行してみます。「出力」ウィンドウで、以下のような表示が確認できます。

ムービークリップ: ターゲット="_level0.my1_mc"
ムービークリップ: ターゲット="_level0.my2_mc"
ムービークリップ: ターゲット="_level0.my2_mc"
変数 _level0.my2_mc.onRollOver = [関数 'onRollOver']

30度回転したMovieClipと残像の両方表示されているのが、インスタンスmy2_mcです。実際「出力」ウィンドウにも、同じパス"_level0.my2_mc"が2回表示されています。しかし、ここで注目していただきたいのは、「変数 _level0.my2_mc.onRollOver = [関数 'onRollOver']」という出力が1行しかないということです。

これは、2つのmy2_mcというインスタンスのうち、一方しかonRollOverメソッドが設定されていないということを示しています。筆者が確認したところでは、メソッドが消滅しているは残像の方のインスタンスのようです。そして、my1_mcの方は、回転していない残像だけが表示されています。ですから、「出力」ウィンドウの表示でも、my1_mcにはonRollOverメソッドが存在していません。つまり、ボタンとして反応しなくなったのは、onRollOverメソッドが存在しない残像が表示されているからだということです。

_____

作成者: 野中文雄
協力者: icutommy ツツイ
作成日: 2003年2月6日

その他の記事