Adobe Flash CS3 Professional ActionScript 3.0 □02 スクリプトによるアニメーション
○02-01 関数・メソッドを使う ●タイムラインで1秒をカウントする
スクリプト02-001■メインタイムラインの第1フレームアクションでムービークリップインスタンスを回転
メインタイムラインの上記第1フレームアクション(スクリプト02-001)は、メインタイムラインに配置されたムービークリップインスタンスbar_mcの角度を指定するプロパティrotationに6を加算します。メインタイムラインは1秒12フレームがループ再生されますので、1秒ごとに第1フレームアクションが実行され、6度ずつ回転し、60秒で1回転(360度回転)することになります。 しかし、この秒針は、時間の経過が正確ではありません。フレームレートが12fpsに設定されていても、1秒間で必ず12フレーム再生されるとはかぎらないからです。 Flashのアニメーションは、原則としてすべてのフレームを再生・表示します。あるフレームの表示に時間がかかったとしても、その後の再生フレームをスキップしたりしません。そのため、アニメーションの処理負荷の高さや、再生環境の仕様(スペック)によって、実際のフレームレートは変わってしまいます。また、フレームレートそのものが、ミリ秒単位の正確さを備えたものではありません。 ●getTimer()関数の使い方 スクリプトを記述したフレームを選択して、[アクション]パネルにgetTimer()と記述したら、この関数名をドラッグしてハイライトし、パネルの[ヘルプ]ボタン(ショートカットキー[F1])をクリックしてみましょう(図02-003)。[ヘルプ]パネルが開いて、getTimer()関数の説明が表示されます(図02-004)。 図02-003■[アクション]パネルで関数を選択して[ヘルプ]ボタンを押す
[ヘルプ]にはActionScript 3.0について、そのプログラミングに関する説明のほか、個々の関数(メソッド)やプロパティの使い方を解説したリファレンス(辞書)が備わっています。[アクション]パネルで関数を選択して表示されたのはこのリファレンスの解説です。 初心者には難しい内容も含まれており、邦訳に難のある箇所や、ときおり情報自体の誤りが見つかることもあります。けれども、その情報量においては、ActionScript 3.0に関するもっとも詳しいドキュメントです。やみくもにGoogle検索する前に、まずヘルプを確認することが大切です。そこで、本書ではヘルプの読み方についても、折にふれて説明を加えることにします。 図02-004■[ヘルプ]パネルに表示されたgetTimer()関数の解説
[ヘルプ]の[getTimer()関数]の項の最初に示されているのが、関数のシンタックス(前掲Word 01-002「シンタックス」参照)です。 public function getTimer():int publicは、ユーザーが使えるように「公開された」という程度の意味に捉えて、当面気にしなくて構いません(publicの意味については、クラス定義で詳しく解説します)。functionは関数であることを示します。関数は「メソッド」と呼ばれることもあります。getTimer()は関数の呼出し方を表し、括弧()内が空なのは引数(パラメータ)がないことを意味します。 括弧()に続くコロン(:)の後に示されているのは、戻り値のデータ型です。intは整数のデータ型です。Number型が小数値(プログラミングでは「浮動小数点数値」と呼ばれます)を取れるのに対して、int型には整数値しか与えることができません(後述Tips 02-015「数値のデータ型」参照)。 したがって、シンタックスの記載からは、この関数はgetTimer()と書いて呼出すと整数値が返されるとわかります。具体的にどのような値が返されるのかは、シンタックスの後に説明されています。
Flash Playerが「初期化」されるというのは、Flash Playerが起動して、SWFムービーが再生できる状態になることを意味します。つまり、getTimer()関数は、Flash Playerがスタートしてからの経過時間をミリ秒(1/1000秒単位)で返すということです。 ヘルプはさらに、「戻り値」やスクリプトの「例」についても詳しく紹介しています。けれど、当面はここまで理解すれば十分でしょう。
●getTimer()関数で時間の経過を調べる
getTimer()関数が返す経過時間はミリ秒ですから、1000で割れば秒の値になります。秒針は1秒に6度回転しますので、得られた経過秒数に6を乗じて、ムービークリップインスタンスの角度に設定すればよいでしょう(スクリプト02-003)。 12フレームで1秒をカウントした前のムービー(図02-002)では、フレームループのたびに6度を加算(+=)しました。しかし、getTimer()関数を使った計算では、経過秒数そのものが増えていきますので、6掛けた値を加算ではなく代入(=)していることにご注意ください。 スクリプト02-003■getTimer()関数で取得したミリ秒を秒数に直して角度に設定
ダブルスラッシュ//は「行コメント区切り記号」演算子(前掲Word 01-003「演算子」参照)と呼ばれ、この記号以降の1行はスクリプトとしては無視されます。無視される部分の記述をコメントといい、[アクション]パネルのデフォルト設定ではグレーで表示されます(図02-005参照)。コメント行区切り記号//を使う目的は、おもにふたつあります。 第1は、文字どおりコメントとして、スクリプトを書いた人が注釈やメモを加えるためです。上記スクリプト02-003のように、フレームアクションの記述場所や処理内容の説明を添えると、スクリプトがわかりやすくなります。コメントは、ステートメントの後に書き加えることもできます。その場合、ステートメントはもちろん有効で、コメント行区切り記号//の後のその行の残りがコメントと認識されます。 第2に、動作確認のため一部ステートメントの処理を一時的に外したり、修正前の記述を無効化しつつ履歴として残したりするために用いられます。ステートメントをコメント区切り記号で無効化することを、「コメントアウト」といいます。たとえば、上記スクリプト02-003でtrace()関数の[出力]結果を確認し終えたら、最終的なムービーには不要ですので、つぎのようにコメントアウトすればよいでしょう。 // trace(nSeconds); // 確認用
上記スクリプト02-003を[ムービープレビュー]で試すと、秒に換算された経過時間が、たとえばつぎのように[出力]されます(図02-007)。ただし、具体的な数値は、環境などによって変わります。 図02-007■秒に換算された経過時間が[出力]パネルに表示
フレームアクションの実行は秒の切り替わりのタイミングとは、少しずれています。また、他に処理やアニメーションを加えれば、フレームアクションの実行間隔にも遅れが生じることは十分考えられます。ですから、フレーム数は少なくした方が、より細かいタイミングで、時間の経過と秒針のアニメーションとを同期させることができるでしょう。そこで、タイムラインのフレーム数を、計2フレームに縮めてみます(図02-008)。 図02-008■タイムラインを2フレームに縮める
なお、連続したフレームの終端に[Ctrl](Windows)または[command](Macintosh)キーを押しながらマウスポインタを合わせると、カーソル形状が左右方向の矢印(←→)に変化します。そのまま左右にドラッグすれば、連続したフレームの長さを縮めたり伸ばしたりすることができます(図02-008・前掲Tips 01-011「連続したフレームの長さを変える」参照)。 [編集者用注釈] Tips 02-004は話題重複のため削除。 [ムービープレビュー]を行うと、秒針は1秒刻みではなく、約1/6秒間隔で滑らかに回転します。これをつぎは、スクリプトで1秒刻みの動きにしてみましょう。
●Math.floor()メソッドで小数点以下を切捨てる この小数点以下を切捨てるのが、Mathクラスのfloor()メソッドです。今の段階では「クラス」というのは、さまざまな関数やプロパティを集めて、ひとつのカテゴリーにまとめたものと考えればよいでしょう。そして、前述(Word 01-005「関数」)のとおり、クラスに定義された関数を「メソッド」と呼びます。 つまり、Mathクラスという数学的な計算をするカテゴリーに属する、小数点以下を切捨てる関数がfloor()メソッドです。floor()メソッドはMathクラスに属しますので、ドット(.)を使って、Math.floor()と記述します。ここでまた、リファレンスの説明を確認しましょう(図02-009)。 図02-009■Math.floor()メソッドについての[ヘルプ]の解説
まず、シンタックスから見ていきます。publicは、当面気にしないことにしました。その後にstaticという用語があります。日本語では「静的」と訳されます。これは、メソッドへのアクセスの仕方を示しています。 public static function floor(val:Number):Number 水平座標や角度のプロパティx、rotationにアクセスするとき、ターゲットとして操作対象のインスタンスを指定しました。メソッドの場合にも、ターゲットの指定は必要になります。したがって、メソッドはつぎのようなかたちで呼出します(括弧()の中の引数に角括弧[]がついているのは、ヘルプやリファレンスの記載ではオプションであることを示します。すなわち、指定される場合もあれば、されない場合もあります)。なお、ターゲットのことを「参照」と呼ぶこともあります。 【メソッドの呼出し】 static(静的)なメソッドというのは、このターゲットあるいは参照がクラス名そのものになることを意味します。つまり、ムービークリップのプロパティのように個々のインスタンスをターゲットに指定するのでなく、つねにクラス名を参照して呼出します。Mathクラスのfloor()メソッドであれば、いつもMath.floor()で呼出せばよいということです。
つぎに、メソッドに渡す引数(パラメータ)は、数値または式です。「式」には、四則演算の計算式はもちろん、たったひとつの変数や、関数の呼出しも含まれます。処理結果の値が得られる(返される)ものは、すべて式になります。ただし、Math.floor()メソッドで引数に続くコロン(:)の後にNumberと指定されているのは、引数がNumber型つまり数値でなければならないことを示します。 そして、戻り値は、引数に指定された数値の小数点以下を切捨てた整数値です。もっとも、データ型はintでなく、Numberで指定されています。ここで「切捨て」とは、対象となる数値以下のもっとも近い(大きい)整数値を求めることです。
リファレンスの説明から、Math.floor()メソッドは、つぎのような構文で使えることがわかります。「変数」には、「小数値」を小数点以下で切捨てた整数値が代入されます。「小数値」には、式が入っても構いません。 var 変数:Number = Math.floor(小数値); それでは、前に作成したスクリプト02-003に、Math.floor()メソッドの処理を加えて、秒針が1秒刻みで回転するように書替えてみましょう(スクリプト02-004)。 スクリプト02-004■取得したミリ秒をMath.floor()関数により1秒刻みの値にして回転
[1]上記フレームアクション(スクリプト02-004)の3行目、コメントを除いた第1ステートメントは、以前(スクリプト02-003)のまま変更がありません。 [2]フレームアクションの4行目、もとのスクリプト(02-003)の第2ステートメントについては、取得される秒数値の確認を終えましたので、コメントアウトしました。再度秒数値を確認したいときには、先頭の//(コメント行区切り記号)を削除すれば、[ムービープレビュー]時ふたたび[出力]パネルに秒数値が約1/6秒間隔で表示されます。 [3]フレームアクションの5行目、新たな第2ステートメントに、Math.floor()メソッドの処理を加えました。変数nSecondsに代入された小数値の秒数を、Math.floor()メソッドの引数に渡して、1秒単位の整数にします。整数の秒数値に6度を乗じてインスタンスの角度に設定すれば、1秒刻みで秒針のムービークリップインスタンスが回転します。 なお、変数に6を掛けたnSeconds*6を、Math.floor()メソッドの引数に指定しないよう注意しましょう。そうすると、角度の値が小数点以下で切捨てられ、1度単位で秒針が回転してしまいます。 ○02-02 変数を使う
●秒針のアニメーションを0秒からスタートする では、前のムービーのスクリプト02-004を、つぎのように書替えればよいでしょうか。変数nStartに、第120フレームに到達したときのgetTimer()関数の戻り値を代入しています。しかし、これでは秒針は0秒を指したまま、ピクリとも動かなくなります(図02-011)。 図02-011■0秒の位置で動かない秒針
上記のスクリプトを第120フレームアクションとして記述すれば、第1ステートメントで変数nStartには第120フレームに到達したときのgetTimer()関数の値が代入されます。けれど、変数nSecondsに経過時間を代入する、第2ステートメントの右辺は第1ステートメントとまったく同じです。 もちろん、第120フレームに到達したとき、ふたつの変数nStartとnSeconds値は同じでないと、秒針は0からスタートしません。しかし、問題はこのフレームアクションが、ループ処理されたときです。経過秒数を新たに取得する変数nSecondsの値とともに、最初に第120フレームに到達したときの秒数を保持すべき変数nStartの値も更新されてしまうのです。ふたつの変数値がつねに等しい訳ですから、秒針は0からまったく動かないことになります。 この問題を解決するには、変数nStartの値が書替えられないようにすることです。方法は、いくつか考えられます。たとえば、変数nStartの値はひとつ前の第119フレームで設定するようにして、アニメーションの繰返し(ループ)処理は第120フレームアクションで実行する方法もありえます(この場合厳密にいえば、nStartの値は第120フレーム到達時より、1フレーム分つまり1/12秒ほど早くなります)。 しかし、本書では、スクリプトはできるだけひとつの場所にまとめて書くようにします。ひとまとまりであるはずの処理があちこちに細切れで書かれていると、全体の流れを把握しにくくなるからです。とくにこの章では、最終的に秒針のムービークリップシンボル内に、スクリプトをまとめます。すると、[ライブラリ]からムービークリップシンボルをステージにドロップしただけで、そのインスタンスはただちに秒針として動作するようになります。つまり、コンポーネントのようなパーツ化を目指そうということです。
ではまずは、再生ヘッドが秒針のアニメーションを開始するフレームに到達したときの経過秒数は、秒針のムービークリップシンボル内の第1フレームに変数nStartとして設定することにしましょう。秒針のムービークリップをシンボル編集モードで開いて、スクリプト用のレイヤーを追加したら、つぎのフレームアクション(スクリプト02-006)を記述します(図02-012)。 スクリプト02-006■秒針のムービークリップにスタート時の秒数値を変数として設定
図02-012■ムービークリップシンボルに第1フレームアクションを記述
実質のステートメントは、変数nStartにgetTimer()関数の戻り値を秒数に直して代入する1行だけです。確認のため、第2ステートメントで、その秒数値をtrace()関数で[出力]しています。メインタイムラインのフレームアクションは、以前のスクリプト02-004のまま、まだ変更する必要はありません。 [ムービープレビュー]を実行すると、12fpsで第120フレームに秒針のムービークリップインスタンスを配置してあれば、秒針が表示された最初に1度だけ約10の数値が[出力]パネルに表示されるはずです(図02-013)。 図02-013■秒針のアニメーション開始時の経過秒数が[出力]
ムービークリップシンボルの中には1フレームしかありません(図02-012)ので、再生ヘッドの移動が発生しません。したがって、その第1フレームアクションは、1度しか実行されないことになります(Tips 01-010「フレームアクションと画面の描画」参照)。これで、秒針のアニメーション開始時の経過秒数を変数nStartに設定し、その値を変わらず保持することができます。 それではつぎに、メインタイムラインのフレームアクション(スクリプト02-004)に修正を加えて、秒針のムービークリップシンボルから設定した変数nStartの値を利用することにします。 ただし、メインタイムラインからムービークリップシンボル内で定義した変数nStartには、単にnStartと記述しただけではアクセスすることはできません。なお、値を調べたり設定するために変数やプロパティにアクセスすることを、変数・プロパティを「参照する」と表現することもあります。 前章01-05「変数はメモリ」で、変数は「メモリ」だと説明しました。もう少し詳しくいうと、フレームアクションでは、この「メモリ」は原則としてタイムラインごとに管理されます。つまり、メインタイムラインで定義された変数はメインタイムラインにメモリされ、ムービークリップ内で定義された変数はそのインスタンスにメモリされるのです。そうした変数の参照の仕方は、丁度プロパティにアクセスする場合と同じです。つまり、ターゲットパスをドット(.)で指定したうえで、変数を参照する必要があります。
たとえば、メインタイムラインにムービークリップインスタンスmy_mcを配置し、メインタイムラインからmy_mcに定義された変数myVarを参照するには、つぎのように記述します。これは、インスタンスmy_mcのxプロパティにアクセスするとき、my_mc.xと書くのと同じです。 my_mc.myVar これで、ムービークリップインスタンスbar_mc内に定義した変数nStartを、メインタイムラインから参照する方法がわかりました。よって、メインタイムラインのフレームアクション(スクリプト02-004)は、つぎのように書替えられます(スクリプト02-007)。 スクリプト02-007■ムービークリップの変数をもとに回転角をコントロール
[ムービープレビュー]を実行すると、秒針のアニメーションは0秒の位置からスタートします。ただし、最初に一瞬、0から少しずれた角度で秒針が表示されます(図02-014)。この現象は、最終的にムービークリップシンボル内にスクリプトをまとめることで解消します。ですからこの問題の理由も、その際に改めてご説明することにします。 図02-014■最初に一瞬0の位置からずれた角度の秒針が表示
●変数について
ここで、「予約語」というのは、オンラインヘルプ[ActionScript 3.0 のプログラミング]の[ActionScript 言語とシンタックス] > [シンタックス]の項に、「キーワードと予約語」として一覧表が掲げられています(Tips 02-009)。 厳密には、この「予約語」に含まれなければ、ActionScriptで使われている関数・メソッド名やプロパティ名その他のキーワードを使っても、それ自体は許されます。また、自作の(カスタム)クラスを作成する場合には、あえて既存のメソッドと同じ名前のメソッドを定義するという場合もありえます。けれど、クラスの仕組みや定義済みの名前をあえて使う意味が理解できるまでは、ActionScriptですでに使われている名前は用いないことをお勧めします。
つぎに、フレームアクションで定義した変数は、前述のとおり、原則としてその宣言を行ったタイムラインにメモリされます。このようにタイムライン上に保持される変数を、「タイムライン変数」と呼びます。タイムライン変数を参照するには、それが定義されたタイムラインまたはムービークリップインスタンスをターゲットに指定する必要があります。 変数についてお話しする3つめは、名前のつけ方です。識別子でありさえすれば、スクリプトの動作上問題は生じません。しかし、一般的に使われている名前のつけ方に従っておくと、同じ習慣をもつ人同士でプログラムが理解しやすくなります。 [1]識別子は、変数名やインスタンス名、関数・メソッド名、プロパティ名まで含めて、小文字で始め、基本的には小文字を使います。たとえば、xやrotationプロパティ、trace()関数、Mathクラスのfloor()メソッド(Math.floor())などは、すべて小文字です。ただし、複数単語で構成される名前は、第2単語以降の頭を大文字にします。curentFrameプロパティやgetTimer()関数、gotoAndPlay()メソッドなどがその例です。この慣例は、多くのプログラミング言語で踏襲されています。
[2]「接頭辞」や「接尾辞」を使うと、便利なことがあります。「接頭辞」(prefix)は先頭に、「接尾辞」(suffix)は末尾につける記号です。いずれも、その識別子にどのようなデータが格納されているのかを示す記号が付されます。たとえば、本書では数値を代入する変数には、頭に数値(Number/Numeric)を示す"n"をつけています。これが接頭辞です。 数値の1に1を足すと、もちろん2になります。けれど、ActionScriptでは、文字列にも足し算(+演算子の処理)が定義されています。文字の"1"に"1"を足せば、ふたつの文字をつなぎ合わせて"11"になります。つまり、a=b+cというステートメントがあったとしても、そのデータが数値か文字列かによって、処理内容は異なることになります。
変数名に、格納されているデータが数値か文字列か区別できる記号がついていれば、その処理内容がわかりやすくなります。もちろん変数宣言で型指定をしていれば、データ型は明らかです。しかし、それは変数宣言のステートメントにかぎった話です。それ以降の処理について、接頭辞も接尾辞もなければ、変数宣言にさかのぼらないとデータ型は確かめられません。
ただ、接頭辞をデータ型に完全に一致させる必要はないでしょう。たとえば、数値には浮動小数点数値を扱うNumberのほか、整数のint型もあります。初めにint型で指定した変数を、小数値の処理が必要になって、Number型に変更するということは考えられます。 データ型は変数宣言の型指定だけ変えればよいのに対して、変数名はそれを使ったすべてのステートメントが修正の対象になります。すべてのステートメントを書替えようとすれば、間違いや見落としも生じ得ます。変数名については数値演算をすることがわかれば十分で、それ以上の詳しいデータ内容は型指定に委ねてよいでしょう。ですから、本書では小数値も整数値も、変数の接頭辞には"n"を使います。
接頭辞を使うとよいことのもうひとつは、予約語やActionScriptの定義済みの名前との重複が防げることです。たとえば、"start"とか"stop"といった単語は、識別子として使いたくなることが少なくありません。けれど、startはPrintJobやSound、Tweenなどのクラス、stopはMovieClipやTimer、Tweenなどのクラスのメソッド名と重複します。だからといって、別の単語を探すのも面倒です。このとき、数値を代入する変数なら、nStartとかnStopという名前にすると、簡単に重複が避けられます。そうすれば、変数の名前に悩まなくて済みます。 「接尾辞」は、記号を変数の末尾につけるという以外、目的などはとくに接頭辞と変わりません。本書でムービークリップインスタンス名の末尾につけた"_mc"は、接尾辞の例です。一般のプログラミング言語では、接尾辞を使うことはあまり多くないようです。しかし、ActionScriptでは、[アクション]パネルまたはスクリプトウィンドウ内で、接尾辞をつけた識別子に続けてドット(.)を打つと、「コードヒント」が表示されます(図02-015)。 図02-015■接尾辞をつけるとコードヒントが表示される
「コードヒント」は、そのインスタンスに対して使えるプロパティやメソッドの一覧を表示するポップアップメニューです。項目はマウスや矢印キーで選択することもできますし、ドット(.)に続けて文字をタイプし始めると、その文字で始まる項目がハイライトされます。[Enter](Windows)または[return](Macintosh)キーで、選択が確定します。 もっとも、接尾辞を使わなくても、変数(var)宣言で型指定をすれば、その指定した型をもとにコードヒントは表示されます。ですから、コードヒントを利用するために接尾辞を使う必要性は、型指定をサポートするFlash MX 2004/ActionScript 2.0以降ではあまりありません。ただ、接尾辞によるコードヒントの表示は、Flash MX/ActionScript 1.0から採用されています。したがって、ActionScriptを書く人たちの間では、接尾辞は識別子の内容を示す記号として比較的広く知られています。 本書は、識別子をつける際、接尾辞が定められているデータについてはそれを用い、接尾辞がとくにないデータについては接頭辞を使うようにします。接頭辞・接尾辞は、必ずしも使わなければならないというものではありません。わかりやすい名前のつけ方を、予め決めておくことが大切なのです。会社やプロジェクトチームでそうした規則を定めたなら、もちろんそれに従って構いません。 ○02-03 関数(function)を定義する ●秒針が最初に一瞬ずれる訳 − NaN(非数) −
そして、メインタイムラインのフレームアクション(スクリプト02-007)に、確認のためにつぎのようなtrace()関数のステートメントを追加します(図02-016。追加先は、どの行でも構いません)。trace()関数には、カンマ(,)区切りで複数の引数を渡すことができます。引数の値は[出力]パネルに、スペース区切りの1行で表示されます。 trace(bar_mc.nStart, nSeconds-bar_mc.nStart);
[ムービープレビュー]を行うと、[出力]パネルには以下のような結果が表示されます(具体的な数値は、環境によって変わります)。ムービークリップのフレームアクション(スクリプト02-006)は、変更していません。したがって、最初に1度だけ変数nStartの値が、[出力]パネルに表示されます。値がスペース区切りで1行にふたつ[出力]されるのは、メインタイムラインで繰返し実行されるフレームアクション(図02-016)のtrace()関数の結果です。 図02-017■trace()関数から[出力]パネルに表示された値
すると、[出力]パネル(図02-017)の第1行目にふたつNaNと表示されているのは、メインタイムラインのtrace()関数の結果だということになります。NaNは「非数」(Not a Number)と呼ばれる、特別な値です。Numberで型指定された変数に、まだ値が設定されていないときに返されます。そして、パネルの第2行目に数値がひとつだけ表示されているのは、ムービークリップからの[出力]です。
スクリプトには、実行の順序があります。フレームアクションは、親のタイムラインから先に処理されます。つまり、最初にメインタイムラインのフレームアクション(図02-016)が実行され、その後ムービークリップのフレームアクション(スクリプト02-006)が処理されるのです。ということは、ムーピークリップ内のフレームアクションで変数nStartの値が代入される前に、1度メインタイムラインのフレームアクションが実行されてしまうことを意味します。 Numberで型指定された変数に、値を設定する前にアクセスすれば、NaNと認識されます。そして、NaNに対しては、どのような数値演算を行おうが、結果はNaNになってしまいます。したがって、最初のメインタイムラインのフレームアクション(図02-016)は、インスタンスbar_mcのrotationプロパティにNaNを設定してしまいます。その結果、角度のずれた秒針のインスタンスが表示された訳です。
メインタイムラインのフレームアクション(図02-016)がループ処理される2回目以降は、ムービークリップインスタンスbar_mcに変数nStartがすでに設定されていますので、意図したとおりに秒針が回転することになります。[出力]パネルの表示(図02-017)の第3行目以降で、ムービークリップインスタンスbar_mcの変数bar_mc.nStartと経過秒数nSeconds-bar_mc.nStartのふたつの値が正しく数値として示されているのは、そのことを示します。 対処法は、いくつか考えられます。たとえば、メインタイムラインの第1フレームにはフレームアクションを置かず、まずムービークリップインスタンスを先に登場させてしまってもよいでしょう。すると、ムービークリップ内のフレームアクションが実行されて、変数nStartは設定されます。そして、メインタイムラインのフレームアクションを第2フレームに記述して、第3フレームから第2フレームにループ処理するやり方です。 実はこれは、Flash 4の頃の手法です。もちろん、処理としてとくに問題は生じません。ただ、修正や応用がしにくく、使い回しに向かない構成です。また、スクリプトをできるだけひとつの場所にまとめようという、本書のスタイルにはそぐわないといえます。 つぎに考えられるのは、メインタイムラインのフレームアクションでムービークリップインスタンスbar_mcのrotationプロパティに値を設定する前に、変数bar_mc.nStartの値がNaNでないことを確認することです。NaNであったら、値をプロパティに設定しなければよいでしょう。これは、あとでご紹介する条件判定のifステートメントを使えば可能です。このような処理が必要であったり、適切と考えられるケースもあります。 しかし、本章では関数(function)を定義することによって、処理をまとめていこうと思います。関数は、スクリプトで自由に作成することができます。そのようなスクリプトで定義した関数は、ActionScriptのビルトイン(定義済み)関数に対して、「ユーザー定義関数」と呼ばれることもあります。 ●関数の定義と呼出し 関数を使うためには、ふたつのステップが必要です。(1)第1は、関数の「定義」です。これは、関数というかたちで、処理内容をタイムラインにメモリする操作に当たります。(2)第2は、関数の「呼出し」です。一旦メモリした関数は、いつでも何度でも呼出して実行することができます。 このふたつのステップは、ネットで音楽を入手して聴く場合と似ています(表02-004)。関数の定義は、音楽データをネットからダウンロードする手順に相当します。音楽データはディスクに記録するのに対して、関数はRAMにメモリするという違いがあるだけです。このステップは、再生(音楽)あるいは呼出し(関数)の前にやっておかなければなりません。ただし、内容に変更がないかぎり、1度だけ行えば足ります。 いったんダウンロード(音楽)や定義(関数)が済めば、あとはいつでも好きなときに、何度でもディスクあるいはメモリから再生または呼出しすることが可能になります。 表02-004■関数とネットの音楽を比較
今回はメインタイムラインのフレームアクションに記述した処理(図02-016)を、そっくりそのまま関数(function)として、秒針のムービークリップ内のフレームアクションに定義します。秒針のムービークリップシンボル内には、1フレームしかありませんので、第1フレームアクションも1度しか実行されません。しかし、関数の定義ですから、1度実行するだけで足ります。 そのうえで、関数の呼出しを、メインタイムラインの第1フレームアクションから行います。すると、メインタイムラインのループ再生により、第1フレームアクションは繰返し実行されることになります。したがって、関数も繰返し呼出されて、秒針のアニメーションが実行されるという構成です。 関数(function)は、以下のように定義します。関数の記述は、その定義のキーワードfunctionで始めます。関数名は、もちろん識別子です。この関数を呼出すと、関数の本体と呼ばれる中括弧{}内に記述したステートメントが実行されます。ステートメント数は、1行にかぎらず任意です。
ユーザー定義関数にも、ActionScriptのビルトイン関数・メソッドと同じように、引数や戻り値を指定することができます。関数名の後の丸括弧()内に指定されている引数は、角括弧[]で括られています。前述のとおり、角括弧[]はヘルプやリファレンスではオプションであることを示します。
今回は、引数も戻り値も使いません。したがって、()の中は空欄になります。()の後のコロン(:)に続けて、戻り値のデータ型を指定します。戻り値がない場合には、データ型としてvoidを指定します。なお、引数や戻り値を指定する、もう少し高度な関数の定義は、後の章でご紹介します。 新たに秒針のムービークリップシンボル内に定義する関数名(識別子)は、xRotateとしましょう。すると、ムービークリップのフレームアクションに定義する関数xRotate()は、以下のような構文になります。なお、本書では関数(メソッド)は、変数(プロパティ)と区別するために、丸括弧()付きで「関数名()」のように表記します。 function xRotate():void {
それでは、メインタイムラインの処理(図02-016)を、functionとしてムービークリップシンボル内の第1フレームアクションに移行しましょう(スクリプト02-009)。関数名は、xRotateです。中括弧{}内の関数本体には、メインタイムラインの第1フレームアクションに記述されたステートメントを、カット&ペーストすればよいです。 スクリプト02-009■ムービークリップシンボルのフレームアクションに関数を定義
ただし、ムービークリップインスタンスbar_mcのrotationプロパティを設定するステートメントは、記述場所がムービークリップシンボル内に変わりましたので、ターゲットを2箇所変更する必要があります。rotationプロパティと変数nStartはターゲットがこのインスタンス自身になりますので、bar_mcの参照を削除します。メインタイムラインの修正前のステートメントも、比較のためにコメントアウトして残しました。 関数の定義は、これでできました。あとは、メインタイムラインのフレームアクションから、この関数を呼出せばよいです。関数の呼出しは、つぎのような構文で行います。
ターゲットは、変数と同じく、関数の記述されているインスタンスを参照します。引数は、角括弧[]内に記載されていますから、オプションです。関数定義に引数が指定されていれば、それに対応して、呼出しするときに引数を渡す必要があります。 今回は、ターゲットがムービークリップインスタンスbar_mcで、関数名はxRotate、そして引数は定義されていませんので、つぎのように呼出すことになります。 bar_mc.xRotate(); このステートメントを、メインタイムラインの第2フレームアクションとして記述します(キーフレームを追加します)。第1フレームでは、ムービークリップの第1フレームアクションまだ処理されないうちに、最初の呼出しが行われてしまうからです。スクリプト用レイヤーの第1フレームは、空白キーフレームにしておきます(図02-019)。 図02-019■メインタイムラインの第2フレームアクションから関数を呼出す
[ムービープレビュー]を行うと、秒針のアニメーションが正しく実行されます。 ○02-04 setInterval()関数を使う ●setInterval()関数で繰返し処理を行う var ID番号を格納する変数:uint = setInterval(呼出す関数, 実行間隔のミリ秒); setInterval()関数には、ふたつの引数があります。第1引数が関数で、第2引数はミリ秒を示す数値です。第1引数として渡した関数が、第2引数に指定した一定のミリ秒間隔で繰返し呼出されます。 setInterval()関数は、戻り値として整数を返します。この整数は、setInterval()関数の設定に対する、いわば整理番号です。この整数は、setInterval()関数の設定をクリアして、繰返し処理を中止するときに必要になります。今回は、とくに設定をクリアする処理は、予定していません。けれど、後で必要になったときのために、変数に取得しておく癖をつけた方がよいでしょう。
setInterval()関数の戻り値を代入する変数には、uintという型指定がしてあります。これは、intのタイプミスではありません。int型はプラス・マイナスを含めた整数であるのに対し、uint型はマイナスを含まない整数になります。
では、秒針のムービークリップシンボルの第1フレームアクションに、setInterval()関数を使ったステートメントを追加します。呼出す関数はxRotateです。同じムービークリップ内に定義されている関数ですから、ターゲットは省略して構いません。実行間隔は、100ミリ秒としましょう(スクリプト02-010)。 なお、スクリプトを記述しているタイムライン(ムービークリップ)の変数・関数やプロパティを参照する場合、ターゲットを省略せずに明示したいときには、thisキーワードを用います。たとえば、以下の[1]と[2]のステートメント群は、それぞれ同じ処理になります(nStartは宣言済みの変数、xRotate()は定義済みの関数とします)。 スクリプト02-010■ムービークリップシンボルのフレームアクションにsetInterval()関数を追加
setInterval()関数を使うときに重要なのは、第1引数の関数に丸括弧()はつけないということです。丸括弧()をつけると、functionを呼出してしまい、その戻り値をsetInterval()の第1引数として渡すことになってしまいます。functionを呼出すのではなく、functionとしてタイムラインにメモリされている処理内容を、setInterval()関数に渡すのです。 前に関数の定義と呼出しを、音楽のダウンロードと再生にたとえました。setInterval()関数の引数にfunctionを指定するのは、携帯に着信メロディデータを設定するのと似ています。着信メロディの設定は、携帯の着信音として楽曲のデータをメモリさせるのであって、メロディを再生する訳ではありません。再生は、着信したときに、携帯が自動的に行います。 setInterval()関数の第1引数にfunctionを指定するとき、丸括弧()をつければ呼出しになってしまいます。丸括弧()をつけないと、そのfunction名でタイムラインにメモリされている処理内容そのものを参照することになります。そして、setInterval()関数は、第2引数で指定された実行間隔のミリ秒数が経過するたびに、第1引数として渡された参照によりfunctionの処理を呼出すということなのです。
さて、これでメインタイムラインから、関数を呼出す必要がなくなりました。フレームアクションは不要になり、繰返し処理がなくなりましたので1フレームだけで足ります(図02-020)。 図02-020■1フレームのみでスクリプトもなくなったメインタイムライン
[ムービープレビュー]を行うと、秒針が正しく時を刻みます。また、このムービークリップシンボルをステージにドラッグ&ドロップするだけで、インスタンスは秒針のアニメーションを行います。いわば秒針のパーツができ上がったのです。 ●setInterval()関数の注意点 第2に、setInterval()関数の第2引数に指定した実行間隔のミリ秒数は、厳密な時間間隔で処理される訳ではありません。Flashは、アニメーションをひとつの重要な処理として扱っています。setInterval()関数の処理は、そのアニメーションの合間に行われます。ですから、実行間隔を100ミリ秒と指定したとしても、厳密に100ミリ秒間隔で処理が行われる訳ではありません。また、アニメーションの処理が多ければ、実行間隔に大幅な遅れが生じることもありえます。
第3に、アニメーションは、あくまでフレームレートで表示されるということです。スクリーンの描画は、フレームレートで更新されます。setInterval()関数の第2引数の実行間隔を100ミリ秒に指定しても、フレームレートが1fpsであれば、画面は1秒間隔でしか書替わりません。したがって、アニメーションは、1秒刻みでぎこちなく動くことになります(図02-021)。 図02-021■アニメーションはフレームレートで表示される
そうすると、スクリプトでアニメーションを行おうとする場合には、フレームレートに合わせて描画更新時に処理する方が無駄は少なそうです。次節02-05では、その手法をご紹介します。setInterval()関数は、スクリーンの描画と関係なく一定の時間間隔で行いたい処理や、フレームレートよりも頻繁にチェック・更新したい処理などに用いるのがよいでしょう。 ○02-05 イベントリスナーを使う
●イベントリスナーとは そうすると、そのイベントの受取り方を、知っておかなければなりません。ActionScript 3.0では、「イベントリスナー」という仕組みにより、イベントを処理します。
イベントリスナーを使う手順は、ホテルでモーニングコールをお願いするときと似ています。モーニングコールは、まずフロントを内線で呼出し、時刻を指定して、電話をかけてくれるよう依頼します。イベントリスナーを設定するには、インスタンスに対してaddEventListener()メソッドを呼出し、イベントを指定して、実行すべき処理を関数(function)で定義します。この実行する関数を、イベントリスナーもしくはリスナー関数と呼びます。
モーニングコールの場合、フロントは指定された時刻になったら、依頼人の部屋に電話をかけます。イベントリスナーでは、インスタンスは指定されたイベントが発生したとき、定義された関数を呼出します。addEventListener()メソッドの構文は、つぎのとおりです。 ターゲットインスタンス.addEventListener(イベント, 呼出す関数) たとえば、タイムラインに配置したムービークリップインスタンスmy_mcにイベントリスナーを設定して、enterFrameイベントで関数xAnimate()を呼出すには、以下のようなスクリプトを書きます。 my_mc.addEventListener("enterFrame", xAnimate); 第1に、addEventListener()メソッドの第1引数となるイベント名は文字列(Word 02-001「文字列」参照)で指定します。つまり、ダブルクォーテーション(")でイベント名enterFrameを括る必要があります。第2に、addEventListener()の第2引数に指定する関数(function)は、setInterval()関数と同じく参照ですので、呼出しの丸括弧()はつけません。関数の定義の仕方も、setInterval()と同様です。 ただし、さらに第3として、定義した関数に引数(eventObject)があることにご注目ください。前述(02-03「関数(function)を定義する」)のとおり、「関数定義に引数が指定されていれば、それに対応して、呼出しするときに引数を渡す必要があります」。逆に、関数呼出しのとき引数が渡される場合には、それに対応して、関数定義にも引数を指定しておかなければなりません。 イベントリスナーに指定した関数は、イベント発生時に、インスタンスから呼出されます。そのときインスタンスは、イベントについての情報が格納されたイベントオブジェクトと呼ばれる引数をひとつ渡します。したがって、リスナー関数にも、引数をひとつ指定しておく必要があるのです。渡された引数を受取らないと、ActionScript 3.0ではエラーを生じます。
引数は、任意の変数として指定します。関数定義の括弧()の中は、変数の宣言と同じです(前掲Tips 02-011「関数(function)の引数は変数」)。ただし、変数のvar宣言と異なるのは、関数を呼出すときに引数として渡された値が、括弧()内に指定した変数に自動的に格納されるという点です。var宣言と同じく、データ型も指定できます。 引数のデータ型は、指定するイベントによって異なります。enterFrameイベントの場合は、Event型で指定することになります。イベントオブジェクトには、今回はとくにアクセスする必要はありません。ですから、イベントオブジェクトについては、後で改めて解説します。 ●イベントリスナーを使ったスクリプティング
図02-022■イベントリスナーを用いたフレーアクション
スクリプト02-011の(コメントを除く)第2ステートメントで、addEventListener()メソッドを呼出しています。ターゲットを省略していますので、スクリプトを記述しているムービークリップがイベントリスナーの登録先インスタンスとして参照されます。第1引数のイベントは"enterFrame"で、第2引数として呼出すリスナー関数(function)はxRotateです。 関数xRotate()の実質的な処理内容は、以前のスクリプト02-010と(確認用のtrace()関数のステートメントを除いて)変わりません。ただし、前述のとおり、リスナー関数にはイベントオブジェクトが引数として渡されるため、function定義に引数をひとつ宣言しておかなければなりません。引数は、識別子であれば、名前は任意です(前述Tips 02-011「関数(function)の引数は変数」参照)。データ型は前述のとおり、Event型を指定します。 [ムービープレビュー]で確認すると、秒針のムービークリップインスタンスが、1秒ごとに時を刻みます。アニメーションの表現上は、setInterval()関数を使った場合と異なるところはありません。しかし、スクリーンの描画更新と同期してアニメーションが実行されていますので、処理に無駄がないといえます。 ○02-06 タイムライン変数とローカル変数 ●クリック時のイベントリスナーを加える addEventListener("click", xStartClock); 問題は、リスナー関数xStartClock()として、どのような処理を行うかです。まず、もとのスクリプト(図02-022)の(コメントを除いた)第2行目に記述した、enterFrameイベントが指定されているaddEventListener()メソッドの呼出しを、リスナー関数の本体{}内に移行してみましょう(図02-023)。 図02-023■秒針のインスタンスをクリックするとアニメーションが開始する
[ムービープレビュー]を確認すると、とくにエラーが出ることもなく、針のムービークリップインスタンスをクリックすれば、アニメーションが開始します。ただし、針のアニメーションが、0秒の位置から開始しません。経過時間により、秒針のスタートする角度がまちまちになってしまいます。 これは、(コメントを除いた)第1ステートメントで、開始時刻を変数に取得しているからです(図02-023)。つまり、ムービークリップインスタンスへのクリックをする前に開始時刻が設定されているので、たとえば30秒待ってクリックすれば、秒針のインスタンスは30秒経過した位置から回転を始めることになるのです。 ●タイムライン変数とローカル変数の違い
まず、[コンパイルエラー]パネルにエラーの原因として示された[ソース]は、xRotate()関数内でrotationプロパティを設定する以下のステートメントです。 rotation = Math.floor(nSeconds-nStart)*6; つぎに、パネルの[説明]には、そのステートメントにおけるnStartが「未定義」だとされています。なお、「プロパティ」と表現されているのは、「変数」と同じ意味です。ActionScriptでは、「プロパティ」と「変数」は、質的に同じものとして扱われます(前述Tips 02-007「変数とプロパティは同じ」参照)。 問題は、なぜ変数nStartが未定義と認識されたのかです。以下のステートメントで、変数nStartはvar宣言されています。そして、このステートメントを関数xStartClock()内に移行する前には、このようなエラーは発生しませんでした。実は、関数本体でvar宣言した変数は、「ローカル変数」という特別な扱いがなされます。 var nStart:Number = getTimer()/1000; 以前(02-02「変数を使う」)に、フレームアクションに宣言された変数は、「原則として」タイムラインにメモリされると説明しました。その「例外」が、関数本体でvar宣言された「ローカル変数」なのです。ローカル変数は、タイムラインに保持されません。関数が実行されている間だけ確保される、特別な場所にメモリされます。そして、関数の処理が終われば、原則としてその特別な場所は、メモリからクリアされます。 「ローカル」(local)というのは、ここでは「地方」ではありません。特定のかぎられた場所、「局所」という意味です。つまり、var宣言を行った関数本体というかぎられた場所の中でのみアクセスできるのがローカル変数なのです。したがって、関数の外や他の関数からは、ローカル変数にアクセスすることはできません。これが[コンパイルエラー]の示した内容です。
では、エラーをなくし、秒針をクリックしたら0秒(12時)の初期位置から時を刻むようにするには、どうしたらよいでしょう。第1に、nStartはローカル変数として宣言すべきではありません。他の関数(xRotate())からアクセスできるようにするためには、通常のタイムラインに保持される変数として宣言する必要があります。本書では、このタイムラインに保持される変数を、「タイムライン変数」と呼びました。 第2に、変数への値の代入は、関数xStartClock()内で行わなければなりません。そうしないと、秒針のムービークリップインスタンスが、初期位置からスタートしないからです。つまり、今回は変数の宣言と代入とは別のステートメントとして、分けて処理すればよいということになります(スクリプト02-012)。 スクリプト02-012■変数を関数の外で宣言したムービークリップシンボルのフレームアクション
フレームアクション(スクリプト02-012)の第1ステートメントで変数をvar宣言しましたので、nStartはタイムライン変数として定義されます。そして、関数xStartClock()の本体で変数nStartに対して行った代入は、タイムライン変数の値として保持され、関数外や他の関数からアクセスすることが可能になります。 [ムービープレビュー]で動作を確認すると、エラーを発生することなく、秒針のムービークリップインスタンスをクリックしたとき、0秒(12時)の初期位置からアニメーションが始まります。
●ローカル変数の意義 第1に、メモリに優しいということです。ずっと保持する必要のない値は、ローカル変数に格納することにより、関数の実行が終わればメモリからクリアされます。したがって、メモリの無駄づかいが防げます。もっとも、その節約できるメモリというのは、通常微々たるものです。けれど、わざわざ無駄を放っておく必要はなく、またちりも積もれば山となるともいえます。 第2に、変数値の設定が、関数の外部に影響を与えません。そのため、同じ変数名を他の処理で使っても、意図しない影響を及ぼして、トラブルを発生させることが防げます。つまり、バグが発生する可能性を減らせるということです。 たとえば、テスト用にふたつの関数を定義してみます(スクリプト02-013)。ひとつ目の関数xCountUp()は、呼出すたびにタイムライン変数nの値を1ずつ加算し、加算後の新たな変数値をtrace()関数で[出力]パネルに表示します。ふたつ目の関数xSquare()には、呼出すときに引数として数値をひとつ渡します。すると、その引数の値を2乗して、その計算結果をtrace()関数で[出力]します。 スクリプト02-013■タイムライン変数は他の関数からもアクセスできる
関数の呼出しに引数を渡す場合、すでに述べたとおり(「02-05 イベントリスナーを使う」)それに対応して、関数定義にも引数を宣言する必要があります。引数は呼出しで渡される個数と、関数定義に宣言された個数とが一致しなければなりません。なお、複数の引数は、関数の呼出しでも宣言でも、カンマ(,)区切りで指定します。 関数xSquare()には、数値の引数をひとつ渡します。すると、関数定義でも、同じくひとつの変数を宣言して、受取る必要があるのです。引数の名前は、通常の変数と同じく、任意の識別子で指定します。関数定義の丸括弧()内に変数名を記述することが引数の宣言になりますので、varキーワードは記述しません。 数値xのy乗は、Math.pow()メソッドを使って、Math.pow(x, y)で求められます。引数iで受取った数値を2乗するなら、Math.pow(i, 2)となります。上記スクリプト02-013で、引数iの2乗の計算結果を、変数nに代入していることに注意しましょう。 上記フレームアクション(スクリプト02-013)に、関数のテスト用のステートメントを3行追加してみます。タイムライン変数nの値を1ずつ加算する関数xCountUp()の呼出しを、単純に3回繰返します。
関数xCountUp()は、呼出すたびにタイムライン変数nの値を1加算してtrace()関数で[出力]します。したがって、[出力]パネルには1ずつカウントアップされた数値が、つぎのように1から3まで、3行にわたって表示されます(図02-025)。 図02-025■関数xCountUp()は1ずつカウントアップした数値を[出力]
さらに、テスト用ステートメントを2行追加します。引数に渡した数値を2乗して[出力]する関数xSquare()を1回呼出してから、もう1度関数xCountUp()を実行してみましょう。[出力]結果は、各ステートメントの後にコメント行として加えておきます。
追加した4行目のステートメントで、関数xSquare()に引数4を渡して呼出しましたので、4の2乗の16が[出力]されました。それに続けて関数xCountUp()を呼出すと、3行目のステートメントで3まで加算されていた変数nに関数xSquare()の結果16が代入されてしまったために、その値に1を加算した17が[出力]されています。 もちろん、それが意図した結果なら構いません。しかし、整数をカウントアップするxCountUp()と、引数に渡した数値を2乗するxSquare()がそれぞれ独立した関数だとすれば、上記スクリプトの最後のステートメントは4を[出力]することが期待されます。その場合には、ふたつの関数がたまたま同じ名前のタイムライン変数nを使ってしまったために、xSquare()の処理がxCountUp()の結果に、意図しない影響を及ぼしてしまったことになります。 このようなときローカル変数を使えば、他の関数が使う変数にはまったく影響を与えません。関数xSquare()の本体で使う変数名はnのまま、これをvar宣言してローカル変数に変更してみます(スクリプト02-014)。 スクリプト02-014■ローカル変数は他の関数からアクセスできない
前のスクリプト02-013をテストしたときと同じ、5行のステートメントを加えて[ムービープレビュー]で確かめてみましょう。[出力]結果は、つぎのようになります。
関数xSquare()を呼出した4行目までの[出力]は、以前と変わりません。しかし、そのあとの5行目のステートメントでもう1度関数xCountUp()を呼出すと、タイムライン変数nの値には影響がなく、3行目に関数を呼出した結果の3に1加算した4が[出力]されました。 このようにタイムライン変数と同じ名前のローカル変数を宣言することも、文法的にはとくに問題はありません。ローカル変数が宣言されていれば、それが優先的にアクセスされるので、同じ名前であってもタイムライン変数には影響を与えません。関数本体にその名前のローカル変数がなければ、タイムライン変数が検索され、その値にアクセスします。
ローカル変数として宣言すべきなのは、関数xSquare()の変数nのように、関数実行後に値を保持しなくてよい場合です。関数xSquare()は、毎回引数を受取り、その値を使った計算結果を変数nに格納します。変数nの値は、渡される引数の値によって毎回変わりますので、その結果は保持する必要がありません。 それに対して、関数xCountUp()では、呼出すたびに変数nの値を1ずつ加算し、その値を次回の呼出し時にも参照しなければなりません。したがって、この場合のnは、ローカル変数でなく、タイムライン変数として宣言しておく必要があるのです(表02-006)。 表02-006■タイムライン変数とローカル変数の比較
秒針のムービークリップを回転させたスクリプト02-012でも、関数xRotate()で経過秒数を格納したnSecondsは、ローカル変数として宣言してありました。経過秒数は、関数が呼出されるたびに新しい値を取得して計算し直しますので、以前の値を保持しておく必要はないからです。 しかし、関数xStartClock()でアニメーション開始時の秒数を設定する変数nStartは、その値を後で呼出す関数xRotate()からつねに参照しなければなりませんでした。したがって、ローカル変数でなく、タイムライン変数として宣言し、値を保持する必要があったのです。
○02-07 イベントのことをもう少し知ろう ●イベントを定数で指定する 具体的には、"enterFrame"の替わりにEvent.ENTER_FRAME、"click"に替えてMouseEvent.CLICKという定数でイベントを指定することが可能です。まずは、スクリプト02-012のイベントの指定を、この定数に書替えてみましょう(スクリプト02-015)。 スクリプト02-015■addEventListener()メソッドに定数でイベントを指定する
文字列と比べて、タイプする文字数が増えるだけで、何がよいのかわからないかもしれません。しかし、まず文字数については実際に入力してみればわかるとおり、クラス名(EventやMouseEvent)に続けてドット(.)を打ったときコードヒントが出てくれますので、さほどタイプするキーの数が増えることはありません(図02-026)。それに、定数は正しく入力すると、文字のカラーが(デフォルトではブルーに)変わります。この点は重要です。 図02-026■addEventListener()メソッドに渡すイベントを定数で指定する
イベントを文字列で指定すると、もちろんコードヒントは出ませんし、文字のカラーも文字列であることを示す(デフォルトではグリーンになる)だけです。たとえば、間違ってイベント名の頭文字を大文字にして"EnterFrame"とタイプしても、スクリプトを書いているときに気づくきっかけがありません。さらに、[ムービープレビュー]を実行しても、文字列で指定したイベントが存在しないことについては、何のエラーも起こりません。 イベントを定数で指定すれば、第1にコードヒントでタイプミスが防げ、第2にシンタックスカラーでActionScriptに定義済みの名前(識別子)であることが確認できます。さらに[ムービープレビュー]を行うと、第3として、指定したイベントが存在しないときには[コンパイルエラー]が発生します。ですから、確実なスクリプトを書くためには、イベントは定数で指定した方がよいでしょう。
●イベントオブジェクトをつくるクラス 秒針のアニメーションのスクリプト02-015を確認してみましょう。イベントにMouseEvent.CLICKを指定すると、リスナー関数はMouseEventクラスのイベントオブジェクトを受取ります。イベントがEvent.ENTER_FRAMEであれば、リスナー関数が受取るのはEventクラスのオブジェクトになります。つまり、リスナー関数の引数のデータ型は、これらイベント定数をもったクラスで指定するのです。ですから、イベントを定数で指定すれば、リスナー関数が受取るイベントオブジェクトのデータ型も自動的にわかる訳です。 イベントオブジェクトは、イベントにまつわるさまざまな情報をもっています。その詳しい内容や具体的な利用の仕方については、後の章で解説していきます。ただ、ここでイベントオブジェクトのもつ情報とそのアクセス方法を、ごく簡単にご紹介しておきましょう。 まず、イベントオブジェクトを、そのままtrace()関数で[出力]してみましょう。スクリプト02-015で、マウスクリックのイベントMouseEvent.CLICKに対して指定したリスナー関数xStartClock()に、引数として受取ったeventObjectを[出力]するつぎのステートメントを挿入します(図02-027)。 trace(eventObject);図02-027■trace()関数でMouseEventオブジェクトを[出力]
[ムービープレビュー]でムービークリップインスタンスをクリックすると、trace()関数により[出力]パネルにMouseEventオブジェクトの情報が表示されます。その[出力]は、たとえばつぎのような内容になります。表示されたのは、イベントオブジェクトのプロパティです。プロパティの種類や数は、そのイベントオブジェクトを作成するクラスによって異なります。
たとえば、typeプロパティは、イベントリスナーが登録されたイベントを示します。このプロパティ値は、スクリプト02-015を例にとると、eventObject.typeと記述して参照することができます。また、ctrlKeyやaltKey、shiftKeyというプロパティにより、クリックしたときWindowsではそれぞれ[Ctrl][Alt][Shift]キー、Macintoshなら[command][option][shift]キーを押していたかどうか調べることができます。 なお、イベントオブジェクトからアクセスできるプロパティは、この[出力]に表示されたものだけではありません。イベントリスナーに対してイベントを伝えたインスタンスは、イベントオブジェクトのcurrentTargetプロパティで参照することができます。さらに、インスタンス名はnameプロパティで取得することができますので、試しに上記trace()関数の引数をつぎのように書替えてみましょう。 trace(eventObject.currentTarget.name); すると、秒針のムービークリップインスタンスをクリックしたとき、そのインスタンス名であるbar_mcが[出力]パネルに表示されます。 ○Column 02 コードヒントを利用する ●予めタイムラインに配置したインスタンス var my_mc:MovieClip; そして、[ムービープレビュー]を行うと、[コンパイルエラー]パネルに以下のようなエラーが表示されます(図Column 02-001)。 1151: 定義 my_mc (名前空間 internal) にコンフリクトが存在します。図Column 02-001■タイムラインに配置したインスタンスをフレームアクションで宣言
これは、タイムラインに配置されたインスタンスは自動的に認識されるため、スクリプトで宣言を行うと重複とみなされてしまうためです。つまり、タイムライン上のインスタンスは宣言が不要で、宣言がなくともスクリプトは問題なく動作します。けれど、そうすると型指定によるコードヒントの表示ができなくなります。
したがって、ステージ上のインスタンスについてコードヒントを表示したいときは、インスタンス名に接尾辞をつける必要があります。コードヒントを表示するクラスとその接尾辞の一覧は、下表Column 02-006のとおりです([ヘルプ]の[Flashユーザーガイド] > [ActionScript] > [スクリプトの記述と管理] > [コードヒントのトリガ]参照)。なお、参考までにFlash 8/MX 2004/MXで使えるかどうかも記載しておきます。 表Column 02-006■コードヒントを表示するクラスと接尾辞の一覧
●thisキーワード その場合には、コメントの記述により、コードヒントを表示すべきクラスが指定できます。スクリプトの冒頭に、以下のようなコメントを記述します。コメント行区切り記号演算子//の後にクラス名を指定し、半角スペースに続けてthisキーワードとセミコロン(;)を書きます。 // クラス名 this; たとえば、フレームアクションでthisを使う場合なら、MovieClipクラスのコードヒントを表示するために、つぎのように記述します。 // MovieClip this; すると、そのスクリプトペイン(スクリプトを記述するウィンドウ)内で、thisに続けてドット(.)を打つと、MovieClipクラスのコードヒントが表示されます(図Column 02-003)。 図Column 02-003■コメントでthisにMovieClipクラスのコードヒントを出す記述
作成者: 野中文雄 Copyright © 2001-2007 Fumio Nonaka. All rights reserved. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||