Think About it



Home > Blog

20071016

cacheAsBitmap(2)


マスクは便利な機能ですが、通常の使い方ではフィルタが
かかっていたり透明のマスクなどは効果が切れてしまいます。

■マスクをかける前


■マスクをかけた後(通常どおり)


■フィルタ「ぼかし」をかけたMCをマスクに


しかしそれも、cacheAsBitmapを使えば実現できます。

※要FlashPlayer8以上

マスクのかけてやり方はフレームにマスクレイヤーを作るのではなくて、
スクリプト、setMask()でかけてやります。
(でないと出来ません)

test_mc.setMask(mask_mc);

test_mc.cacheAsBitmap = true;
mask_mc.cacheAsBitmap = true;


この様に、双方をビットマップに変換してやると、ぼかし等のフィルタがかかっていたりしてもマスクをかける事ができます。



そのマスクを動かしてやっても問題ありません。



この事はヘルプにも書いてあるそうです。
(ちょっと感嘆の声を上げました)

アルファチャンネルマスクについて
アルファチャンネルマスクは、マスクとマスクされたムービークリップの両方でビットマップキャッシュが使用されている場合にサポートされます。



ちなみに、

フィルタ、キャッシュおよび MovieClip クラスの操作
ムービークリップに少なくとも 1 つのフィルタが適用されていれば、cacheAsBitmap プロパティが true となり、実行時にムービークリップがビットマップとしてキャッシュされます。



だ、そうです。

なら、フィルタをかけている方にはcacheAsBitmapをかけてやらなくても大丈夫という事でしょうか。

結果、こうなりました。


大丈夫、という事ですね。

参考:グラデーション・マスク - にゃあプロジェクト ウェブログ

Labels: ,

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

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: ,

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

20071011

cacheAsBitmap(1)


setMaskを使うとスクリプトでマスクをかけることが出来ます。

test_mc.setMask(mask_mc);




test_mcをmask_mcでマスクして表示。
mask_mcの円の形にtest_mcがくりぬかれます。

この、mask_mcは今、描画オブジェクトで書かれていて、線はなし、塗りのみ、となってます。

では、逆に線だけ、でマスクをかけることは出来るのでしょうか?
とりあえす、mask_mcを線だけにしてみます。



結果はごらんの通り。何も表示されません。

要するに、描画オブジェクト(ベクターオブジェクト)の場合は塗りのみマスクが適用されるようです。

では、描画オブジェクトではなく、ビットマップに変えてしまえばいいのでないか、となります。

それが、cacheAsBitmapプロパティです。

acheAsBitmap (MovieClip.cacheAsBitmap プロパティ) - Flashドキュメンテーション

これを使用するとベクターオブジェクトをビットマップオブジェクトに変換できます。

引用
ビットマップがキャッシュされているムービークリップのベクターデータはすべて、メインステージでなくビットマップに描画されます。


このようにします。

test_mc.setMask(mask_mc);
test_mc.cacheAsBitmap = true;
mask_mc.cacheAsBitmap = true;




結果、みごとに線にマスクをかけることが出来ました。

参考 - 線でマスク:にゃあプロジェクト

Labels: ,

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

20071010

hitTest(1)

hitTest関数によって、マウスポインタがムービークリップと重なっているかどうか
(そのエリアにマウスがいるかどうか)
が、検出できます。
以下のようにすれば、hit Areaにマウスがある時とない時で、別々のイベントが発生させれる。
(マウスオーバーのような効果)

function test1(){
test_mc._alpha --;
}
function test2(){
test_mc._alpha ++;
}

_root.onMouseMove = function(){
var Flag = hit_mc.hitTest(_root._xmouse,_root._ymouse,true);
if ( Flag){
onEnterFrame = test1;
} else{
onEnterFrame = test2;
}
}




では、この範囲をFlashのサイズギリギリいっぱいまで広げてみるとどうなるのでしょうか?



ご覧のとおり、外に出たときは反応しません。
あくまでもFlash内でのみ判定可能、ということでした。

Labels: ,

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

背景色


Flashでの背景色の指定は、Flaファイル上で、
背景の色を単純に変えてやり、パブリッシュすれば変更できる。
(htmlを書き出さないと出来ない)

だが、いちいちFlashを立ち上げるのはめんどくさい、もしくは、
Flashのソフト(または.flaファイル)を持ってないときもある。

そんな時、あとから背景色を変えるにはどうしたらいいんでしょう?

答えは簡単。HTMLファイルをいじって、色を変更するだけ。

直接貼り付けの場合、
<param name="bgcolor" value="#ffffff" />
<embed ~ bgcolor="#ffffff" ~ />
と、なっているところの、色を変更してやるだけ。

ちなみに、この箇所を、
<param name="wmode" value="transparent">
<embed ~ wmode=”transparent” ~ />
に、変更してやると、背景が透明なフラッシュが出来上がります。

Labels:

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

20071009

onEnterFrame(1)



onEnterFrameについて。

スクリプトでムービークリップ内に、
onClipEvent(enterframe)と、書くのではなくて、
タイムライン内に、
onEnterFrame = function(){ 内容 }
と、書く方法があります。

これのさらに発展形(?)で、
function XXX (){ 内容 }と、functionで関数を設定し、
それを、OnEnterFrameにする、という方法があります。

例:
function Test(){
test_mc._x ++;
}
this.onEnterFrame = Test;


と、書くと、Test関数がEnterFrameとして繰り返され、test_mcがx方向に1づつ進むこととなります。
こうする利点として、EntterFrame処理がいらなくなったときに、消すことが出来ます。
(たぶん、しなくても消せると思いますが、、)

例:
function Test(){
test_mc._x ++;
}
test_btn.onPress = function(){
this.onEnterFrame = Test;
};
test_btn.onRelease = function(){
this.onEnterFrame = null;
}




こうすると、test_btnを、押したとき(Press)test_mcが動き、
離したとき(Release)EnterFrameにnullが与えられ(要するに、処理を消す)test_mcは止まります。

色々参考サイトを見てみて、この方法があることを知ったのですが、
見た限りでは、
this.onEnterFrame = ~;
と、書いてあります。

では、複数のEnterFrame処理を同時に発生させ、一方だけを消す、という時はどうするのでしょうか?
試してみます。

例:
function Test1(){
test_mc._x ++;
}
function Test2(){
test_mc._y ++;
}
test_btn.onPress = function(){
this.onEnterFrame = Test1;
this.onEnterFrame = Test2;
};
test_btn.onRelease = function(){
this.onEnterFrame = null;
}




結果を見ればお分かりの通り、test_mcはy方向(下)にしか動きません。
そして、ボタンを離すと止まります。
やはり、this.~と同じにしてるのがいけないようです。

なので、次を書いてみます。
例:
function Test1(){
test_mc._x ++;
}
function Test2(){
test_mc._y ++;
}
test_btn.onPress = function(){
onEnterFrame = Test1;
this.onEnterFrame = Test2;
};
test_btn.onRelease = function(){
this.onEnterFrame = null;
}




一つ目から、this.を取り除いてみました。
結果、ボタンを押すと、斜めに(EnterFrameが同時に働いている)、離すと、x方向(横)に動き続けます。

これはどうやら、どれにEnterFrame関数を当てるか、で変わってくるようです。
Test2は、thisに当てていますので、this.onEnterFrame = null;で、処理を取り消すことが出来ます。
しかし、Test1はとくに当てられていませんので、取り消しにはなりません。
違いが出てきました。
(では、何も書かない場合はどこに当てられてるんでしょう、、?)

なので、それぞれの処理をそれぞれ別のムービークリップなりなんなりに割り当ててやれば管理しやすそうです。
そこで、それぞれのためにわざわざ新規にムービークリップを作るのも手間なので、createEmptyMovieClipで、それ用のムービークリップを作ってやる事にします。

例:
_root.createEmptyMovieClip("one",1);
_root.createEmptyMovieClip("two",2);
function Test1(){
test_mc._x ++;
}
function Test2(){
test_mc._y ++;
}
test_btn.onPress = function(){
one.onEnterFrame = Test1;
two.onEnterFrame = Test2;
};
test1_btn.onRelease = function(){
one.onEnterFrame = null;
}
test2_btn.onRelease = function(){
two.onEnterFrame = null;
}




これで、メインのボタンをクリックすると、斜めに動き(同時に働く)、
ボタン1をクリックで、横方向の動きが止まり、
ボタン2をクリックで、縦方向の動きが止まるようになりました。

Labels: ,

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