- ベストアンサー
雪が降るスクリプトについて
- flashplayer7対応の雪が降るスクリプトを作成する方法は?
- 雪がふるスクリプトをflashplayer6から7対応に変更する方法を教えてください。
- ムービークリップとフレームを使用してflashplayer7で動作する雪が降るスクリプトを作成する方法を教えてください。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
Flash Player 7 では Flash Player 6 向けに書かれたスクリプトも動きますので、大きな変更は必要ありません。 ただし、1箇所だけ、変更するところがあります。 雪のムービークリップ” snow ”に設定されている onClipEvent(load) アクションの中に、 rad = 0; というスクリプトを追加してください。 これがないと、Flash Player 7 向けに書き出した時はX座標の計算が正常に行われず、雨のように単純に縦に落ちる雪になります。 ------------------------------------------------ この理由ですが。 参照しようとした変数が未定義だった場合は、undefined (未定義)という値が返されます。 Flash Player 6 までは、undefined は 0 として解釈されます。 ですから、初期値を 0 にする変数は最初から明示的に 0 を入れておかなくても、未定義の変数の初期値が 0 である点を利用することができました。 ご質問文のスクリプトは Flash Player 6 向けとのことで、この特徴を利用しています。 onClipEvent(enterFrame) の中に、X方向の移動量を決めるための下準備として rad += (k/180)*Math.PI; という演算があります。 enterFrame イベントを利用しているので繰り返し行われる演算ですが、最初の1回は、変数 rad は未定義= undefined = 0 と解釈されますから、 0 += ( k / 180 ) * Math.PI; となり、これは問題がありません。 ところが、Flash Player 7 からは undefined の解釈が変更され、今までのように 0 とは見なされなくなりました。 undefined はあくまでも”未定義”であり、存在しないもの、と解釈されます。 undefined の変数を使って演算等を行おうとしても、存在しないものと演算はできませんから、未定義の変数を演算に利用した場合、結果は NaN(数値ではないもの)になります。 先述の箇所ですと、変数 rad は onClipEvent(enterFrame) 内で利用されるまでは存在していません。 この計算は undefined += ( k / 180 ) * Math.PI; と解釈され、結果は NaN になります。 X方向の移動には、この変数 rad を利用して三角関数 cos を求めています。 しかし、変数 rad が数値ではないものになっているために cos の取得に失敗し、従ってX方向の移動の処理は無効になってしまいます。 Flash Player 7 では縦にまっすぐに落ちるボタ雪のようになってしまうのは、このためです。
その他の回答 (1)
- DPE
- ベストアンサー率85% (666/776)
#1です。 重そうな処理といえば、 ・アルファの処理 ・乗算・除算を含む演算( cos の計算や、ラジアンへの変換処理など) あたりでしょうか。 ご質問文のサンプルでは、アルファを 75 ~ 100 の間でランダムに設定することで雪の色に変化を付けています。 アルファの計算は一般的に重いので、まずはアルファを計算しないようにしてはいかがでしょうか。 例えば、背景が黒で雪が単純に白いムービークリップなら、半透明になる雪の色はグレーになります。 つまり、ムービークリップの色を最初から白かグレーで塗りつぶしておくと、アルファの処理をしなくても済みます。 ムービークリップは、Color クラスの setRGB メソッドで塗つぶすことができます。 色は予め配列変数で何色か用意しておき、この中からランダムで選ぶと簡単です。 ちなみに、データを登録しておいて表を見るように使う配列変数は、”テーブル”と呼ばれます。 ----------------------------------------------------- もう1つ重い部分があるとすれば、#1で問題になった変数 rad の演算と cos を求める部分です。 Flash に限らずプログラミングの世界では、乗算や除算、小数点の計算は概して処理が重くなります。 現実の世界でも、掛け算や割り算・小数点が付く計算は嫌われがちですよね。 コンピュータはもともと計算はお手のもので、昨今のコンピュータならややこしい計算もホイホイとこなすところではありますが、人間と同じく、こんな面倒な計算はなるべく少ない方が楽なのです。 コンピュータの内部では全て2進数で処理されているので、256 ( 0 ~ 255 、2の8乗で8ビット)や 65536 ( 0 ~ 65535 、2の 16 乗で 16 ビット)といった、2の累乗で求められる数字の扱いを得意とします。 2の累乗の数であれば、乗算や除算の代わりに、ビット演算という、より高速な演算を利用しやすくなるからです。 ビット演算については詳しくは省略しますが、今回は AND というビット演算を使って高速化を図ります。 例えば、ある正の整数Aがあるとします。 Aと 255 で AND を取る( ActionScript では、A & 255 というように書きます)と、Aがどんな数であっても、結果は必ず 0 ~ 255 の間に収まります。 255 で AND を取るとは、ある数値を 256 で割った余りを求めることと同じです。 雪のX方向の移動は、三角関数の cos を利用しています。 cos をグラフにすると、規則的な起伏を描く曲線になります。 サンプルではこの特徴をX方向の移動に反映させることで、雪がひらひらと舞い散る動きを実現しているのです。 プログラミングの世界では、三角関数はラジアンという単位を基本にします。 ActionScript の三角関数でも、単位は角度ではなくラジアンを採用しています。 三角関数やラジアンは数学の話ですが、Flash のテクニカルノートにも記述がありますので、よろしければご参考になさってください。下手な数学の参考書よりも、分かりやすく解説されています。 ・角度と座標の計算 - Flash の三角関数を使う http://www.macromedia.com/jp/support/flash/ts/documents/fl0189.html このページの「 3.ラジアン」の項目で、角度をラジアンに直す式が紹介されています。 ご質問文のサンプルの rad += (k/180)*Math.PI; は、計算順序がテクニカルノートとは違いますけれど、角度をラジアンに直している部分です。 ActionScript の三角関数では、円1周を 360°とし、これを2πラジアンと考えます。 そのため、角度をラジアンに直してから三角関数を求めようとすると、除算や乗算を含む面倒な演算が必要になってしまいます。 こんな複雑な計算をしなくても済むように、コンピュータの好きな数字の1つである 256 を使って、別の方法で cos を求めてみましょう。 円は周知の通り、普通は1周を 360°とします。 しかし、360 は2の累乗ではなく、コンピュータの得意な数字ではありません。 そこで、1周を 256°とする円を想定し、これを2πラジアンと考えることにします。 そもそも、なぜ円1周を 360°と考えるのかというと、360 は様々な数で割り切れるので、円をいくつかに分割する場合に都合のいい数字というだけのことです。 角度を弧の長さで表すラジアンでは、別に、円の1周を 360°にしなければならない理由はありません。256°を2πラジアンと考えてもいいわけです。 角度をラジアンに変換する式は、突き詰めていくと ラジアン=角度 × π ÷ 円1周の角度の半分 となります。 円1周を 256°と想定するのなら、 ラジアン=角度 × π ÷ 128 です。 1周を 256°とする cos は、ActionScript にある Math.cos を使って予め求めて配列変数に入れ、cos テーブルを作ります。 移動処理で cos を求める時は ActionScript の Math.cos ではなく、用意した配列変数から該当する角度の cos を拾うようにします。 角度を整数に限定するなら、該当する角度の cos を単に配列変数から見てくるだけで cos を計算できますから、ラジアンに直すための複雑な計算は不要です。 cos は普通は 360 °(円1周分の角度)が1周期で、それ以降は同じパターンを繰り返します。 今回は 256°という変な円を考えますけれど、256°で1周期という特性は変わりません。 そう考えますと、配列変数を見る位置は角度を円1周分の角度で割った”余り”ということになります。 配列変数のインデックスは 0 から始まりますから、1周が 256°の cos テーブルのインデックスは 0 ~ 255 です。 ここで、先述の AND 演算が役に立ちます。 255 で AND を取ると、256 で割った余りを求めることができます。 つまり、もしも角度が 256°を超えるようなことがあっても、255 で AND を取って配列変数を見るだけで、該当する角度の cos を取得できるというわけです。 処理の重い除算や if 文による判定などが不要になる分、処理は高速です。 今回は高速化が目的ですので、角度は必ず整数であるものとします。 1周を 360°とする ActionScript の cos よりも精度は多少落ちてしまいますけれど、雪の雰囲気を出すためだけならこれでも充分かと思います。 スクリプトにしますと、大体、次のようになります。 (↓各行頭に全角のスペースが入っています。コピーする際はご注意ください) ●フレームに設定するスクリプト //雪の色を決めるためのテーブル clr_tbl = new Array( 0xffffff , 0xffffff , 0xffffff , 0xdddddd , 0xbbbbbb ); //1周が256°のcosテーブルを作る cos_tbl = new Array(); for( i = 0 ; i < 256 ; i++ ) { cos_tbl[ i ] = Math.cos( i * Math.PI / 128 ); } //1周を256°とするcosを返す //引数 angle:角度(単位は°) function Custom_cos( angle:Number ) { //テーブルを参照してcosを返す return( cos_tbl[ angle & 255 ] ); } //ムービークリップを複製 for( k = 0 ; k < 50 ; k++ ) { duplicateMovieClip( this.snow , "snow" + k , k ); } ●ムービークリップ” snow ”に設定するスクリプト /*初期設定*/ onClipEvent(load) { //ステージのサイズを保持 movieWidth = 300; movieHeight = 200; //移動量に関する設定 //i:Y方向 //k:X方向。曲線運動のための角度の増分で、範囲は1~5 i = 1 + Math.random() * 2; k = Math.floor( Math.random() * 5 ) + 1; //X方向の曲線運動に関する角度を保持 angle = 0; //雪のムービークリップごとに、大きさと初期位置に変化を付ける this._xscale = this._yscale = 50 + Math.random() * 100; this._x = -10 + Math.random() * movieWidth; this._y = -10 + Math.random() * movieHeight; //色をランダムに決める snow_color = _root.clr_tbl[ Math.floor( Math.random() * _root.clr_tbl.length ) ]; clr = new Color( this ); clr.setRGB( snow_color ); delete this.clr; delete this.snow_color; } /*移動処理*/ onClipEvent (enterFrame) { //曲線運動のための角度を更新(256°を超えないようにする) angle = ( angle + k ) & 255; //移動処理 this._x -= _root.Custom_cos( angle ); this._y += i; //下端から出たら、ステージ上端に戻す if (this._y >= movieHeight ) { this._y = -5; } //左右の端から出た場合は、初期位置をランダムに選ぶ if ( (this._x >= movieWidth ) || ( this._x <= 0 ) ) { this._x = -10 + Math.random() * movieWidth; this._y = -5; } } なんだか大幅に変わってしまったように見えますが。 主な変更点は、フレームアクションは ・色を決めるための配列変数を用意 ・1周を 256°とする cos テーブルの作成と、cos を返す独自の関数を定義 ムービークリップのアクションは、 ・アルファの代わりに、Color.setRGB で色を付けておく ・X方向の移動の増分に使う k を、小数ではなく整数で扱う ・変数 angle に角度を保持し、これを元に cos を求める といったところで、他はサンプルのままです。 雪の色は、メインのタイムラインに用意した clr_tbl という配列変数に色をRGB値で登録しておいて、この中からランダムに選択しています。 白( 0xffffff )が3つに対し薄いグレー( 0xdddddd )と濃いグレー( 0xbbbbbb )は1つずつなので、白になる確率が高めになっています。 色合いや確率はお好みに合わせて変更してください。 当方の環境ですと、もともとそれほど重くなかったこともあって劇的に速くなったとは言い難いのですが、高速化のポイントとしてはこんなところだと思います。 ところで、ものすごくケチくさいことを言うようですが。 ステージのサイズを保持する変数 movieWidth と movieHeight は _root 階層(メインのタイムライン)に1つだけあれば充分で、各ムービークリップごとに持っている必要はありません。 onClipEvent(load) の中でこれらの変数を定義すると、複製されたムービークリップにも必ずこの2つの変数が定義されてしまい、メモリの無駄使いになります。 この2つを _root に置いて全ムービークリップ間で共有する場合は、ターゲットパスを忘れないよう、ご注意ください。
お礼
大変勉強になります。 >角度と座標の計算 - Flash の三角関数を使う こちらもがんばって理解したいと思います。 ご丁寧に解説していただき本当にありがとうございました!!!
お礼
DPEさんありがとうございます。 解決いたしました! そうなんです、このままだとぼた雪になってしましまして・・・ 解説も大変勉強になりました。 それとこのスクリプトで、 for (k=0; k<50; k++) { duplicateMovieClip(this.snow, "snow"+k, k); } の50と記載されているところの数字をかえると雪の 数を変えれるようですが、10くらいにしないとCPU パワーがかなり食うのですが、他に軽くする方法は あるのでしょうか?