Think About it



Home > Blog

20071012

onMouseMove(1)


フラッシュ全体がボタンになっているものがあるとします。

その上に違うボタンを配置します。
そのボタンは普段は非表示ですが、そのフラッシュ上にマウスをもっていくと現れます。
そして離してからしばらくすると消えます。
(ムービーのタイムラインを制御してるバー(シークバー)を考えるとわかりやすい。
ずっと出てると邪魔だ、とか)

まず、始めに思ったのが、全体のボタンにロールオーバーした時ボタンを表示、
ロールアウトすると非表示、というものです。

しかし、これには問題がありました。

ボタンの上にボタンをおいてしまうと、片一方のボタンしか動作しないのです。
(当たり前ですが。)

実験:

Btn1にロールオーバーでball_mcが動き、Btn2にロールオーバーでball2_mcが動く。
どちらもロールアウトで止まる。
(ボールの動きは、各mc内でタイムラインで制御)

では、このボタンを重ねてみます。(Btn2が上)

結果はごらんのとおり。
Btn1の上にあるBtn2にロールオーバーすると、ball2_mcしか動きませんん。
その下にあるBtn1には反応しません。
さらに、ball_mcは止まっています。
要するに、Btn1からはロールアウトした、と判定されてしまうのです。

これでは問題です。

冒頭の動きをこの方法で再現しようとすると、中にあるボタンを押そうと、ロールオーバーした瞬間に、全体のボタンからロールアウトした、と判定してしまい、ボタンが消えてしまいます。
(そのままでも押すことは出来ますが。)

で。

次に考えた方法が、hitTestを使用した方法です。

これについては前回のエントリーで書きましたが、サンプルのみ載せてみます。

まず、先ほどのサンプルを改良し、
Btn1の上にマウスが乗ると、ball_mcが動くようにします。


これでは「画面全体」に反応はしてくれませんので、このBtn1を画面全体に配置します。


すると、「上に乗った時」反応はしてくれますが、「外に出たとき」は反応してくれません。
(ball_mc内のタイムラインで外れるまでループする設定にしていますので、止まりません。)
※ずっと動いているのがうっとおしいと思ったら一度ページをリロードして下さい。)

これは、フラッシュの領域(swfの範囲)からマウスが外れても、
フラッシュ内ではマウスの位置は画面内に停止したままになる為です。


ではどうすれば実装できるでしょうか?


それで、考えたのが、onMouseMoveです。
マウスが動いている時は表示、止まっている時(フラッシュ領域外に出たときも止まっている判定)は非表示、にすればいいのではないのでしょうか。

ここで一つ問題があります。
フラッシュには、onMouseMove、という、「マウスが動いたら」という関数はありますが、
「マウスが止まったら(動いてなかったら)」という関数はありません。

そこで、色々調べてみると、以下に参考になる(というか正に、な感じ)サイト(フォーラムですが)がありました。

FLASH-JP.COM - マウスポインタが一定時間動かなかったらWebに飛ぶというものをつくりたいのですが、

そこでは、onMouseMove、onEnterFrame、あと、setIntervalを使用し、
「マウスが止まったら」の判定を実現しています。

そこでさっそく、その内容を冒頭の動きに近くなるように改良。

結果がこれです。


始めは中心にある円は表示されていますが、一度でもフラッシュエリア内にマウスが入れば、判定が始まります。

以下、長いですが、コードです。

var speed:Number = 0.5;
var A:Number = 100;

//enterFrame用の空のムービークリップ
_root.createEmptyMovieClip("IDa",1);
_root.createEmptyMovieClip("IDb",2);

//中心の円が徐々に消える
function transMc(){
test_mc._alpha += ( A - test_mc._alpha)*speed;
if ( test_mc._alpha < 1){
test_mc._alpha = 0;
IDa.onEnterFrame = null;
IDb.onEnterFrame = null;
}
if ( test_mc._alpha > 98){
test_mc._alpha = 100;
IDa.onEnterFrame = null;
IDb.onEnterFrame = null;
}
}

//ここがsetIntervalによって呼び出され、上記transMcが繰り返される
function setTrans(){
A = 0;
IDa.onEnterFrame = transMc;
}

//マウスが動く度に読み出される
this.onMouseMove = function(){
clearInterval(setID);
delete setID;
A = 100;
IDa.onEnterFrame = transMc;
IDb.onEnterFrame = setEnterframe;
}

//マウスが動いているか止まっているかの判定の核
function setEnterframe(){
if( !setID){
setID = setInterval(setTrans,4000);
}
}


EnterFrame処理を何もしていない時も実行しているのが嫌だったため、
それを使用しないように、一段階ややこしくなってます。
(FLASH-JPの方が簡単なサンプルが載ってます)

簡単に解説すると、
マウスが動いている間は、setIDが消され続けます。
さらに、setEnterframeが、呼び出されます。
この、setEnterframeの中では、setIDがもしなかったら、setIDを作れ、
と、命令しています。
ですが、マウスを動かしている間はsetIDは消され続けるのでここでイタチごっこが行われます。
さらに、setIDにはsetIntervalを割り当て、ここでは4秒に一回、setTransを実行するよう命令しています。

要するに、setIDが作られてから、4秒経つと、setTransが実行されるのです。

しかし、マウスを動かしている間は、
setIDを消去→setIDを作成→setIDを消去→4秒経つ前に再びsetIDを作成(タイマーがリセットされる)
を繰り返しているので、いつまでたってもsetTransが実行されません。

しかし、マウスを動かすのをやめると、setIDが作成された後、消去されません。
(次にマウスを動かすまでsetIDが作られることはない。)
なので、無事、setTransが(4秒後に)実行される事となるのです。

あとは、setTransから円が消えるように指示を出してやればいいのです。
(もう一段階踏んでますが、今趣旨とは無関係なので割愛)

Labels: ,

----------------------------------------------------------------------------------------------------