前回の第22回「MovieClipシンボルにクラスを定義する」では、MovieClipシンボルに設定するクラスEllipticMotionを定義した(図1)。シンボルに設定したクラスは、シンボルのグラフィックやタイムラインなどのアセットに関連づけられる。その結果、インスタンスは、シンボルのアセットをデータとしてもつことになる。
EllipticMotionインスタンスをタイムラインに配置すると、シンボルのグラフィックが表示され、楕円を描いて3D風にアニメーションした(図2)。もっとも、前回のEllipticMotionクラスの処理内容は、以前の第17回「3D風に回転するアニメーション」で書いたフレームアクションに、クラスとして最小限の手を加えたものに過ぎない。
今回は、まずEllipticMotionクラスの処理について、今後の拡張まで考えてデザインを整理してみたい。その後、タイムラインに複数のインスタンスを配置するといった、繰返し処理のテクニックをご紹介しよう。
クラスのデザインを考える
クラスEllipticMotionのスクリプトには、大きく3つの修正を加える。第1に、インスタンスプロパティの整理だ。第2は、それらのプロパティの修正にメソッドを対応させ、さらにメソッド間の呼出しの構成についても手を入れたい。第3に、get/setアクセサメソッドをひと組追加する。
それでは、第1のプロパティの整理からいこう。まず、前回フレームアクションからは、つぎのようにコンストラクタメソッドの引数として、楕円軌道の中心座標やxy半径をPointインスタンスで渡した。したがって、EllipticMotionクラスでもこれらの値を数値でなく、Pointインスタンスのままプロパティとしてもつようにする。
つぎに、EllipticMotionクラスには角度のプロパティとして、度数とラジアンが併存していた。しかし、一方の値がわかれば、他方は変換比率から直ちに導ける。そのため、プロパティは度数のみとし、ラジアンは削除する[1]。最後に、プロパティとして宣言してあった度数からラジアンへの変換比率は、constキーワードを使って「定数」とした。この「定数」の意義については、つぎのスクリプトを見てから説明しよう。
さて、定数はvarでなくconstキーワードで宣言する。それ以外は、ひとつの点を除いて、プロパティと異なることろはない。その違いというのは、「定数」という名前のとおり、設定した値が変更できないことだ。円周率πはギリシャの昔から変わらない。したがって、その値を使った比率は変えないし、変えられない方がよい。そのような場合に、定数を宣言する。ちなみに、プログラミングでは、定数名はすべて大文字にする習慣がある[2]。
EllipticMotionクラスのデザインについて、変更点の第2はメソッドだった。第1のプロパティの整理にともなう修正を、先に済ませておこう。とくに難しいものはない。楕円軌道の中心座標とxy半径をPoint型のプロパティに変えたことと、ラジアン値を定数から計算することに対応させた。
それでは、メソッドの構成も変えていこう。修正のポイントは、以下のようにメソッドrotate()の定義を加えたことだ。DisplayObject.enterFrameイベントのリスナーとしてはこのrotate()メソッドのみを登録し、他のアニメーションのためのメソッドはイベントリスナーからは外した。 rotate()メソッド本体からは、これも新たに定義したsetRotation()メソッドを呼出して、そこからmoveX()、moveY()、 scale()、blur()の各メソッドを実行している。
ただし、メソッドupdate()の呼出しは、setRotation()の中に含めず、rotate()メソッドから行った。また、角度のプロパティ値を加算する処理は、メソッドupdate()からrotate()に取出している。この理由は、クラスEllipticMotionの動作を確かめてから説明することにしよう。なお、イベントリスナーから外したメソッドには引数のイベントオブジェクトが渡されないので、その修正も必要になる。
以上のとおり、EllipticMotionクラスのプロパティを整理し、メソッドのデザイン変更を行ったのが、以下のスクリプト1だ。結果を確かめてみよう。クラスを設定したシンボルが格納されたFlashムービー(FLA)ファイルには、前回と同じフレームアクションを記述すればよい。4つのインスタンスが生成され、90度間隔で楕円軌道を描いてアニメーションする(図3)。
上記スクリプト1には、コンストラクタEllipticMotion()のメソッド本体最後に、これまで説明しなかった2行のステートメントが新たに加わっている。この処理の目的を知るには、rotate()メソッドのイベントリスナーへの登録も含めた3行をコメントアウトして[ムービープレビュー]してみるとよい(図4)。
生成されたインスタンスが、タイムラインの基準点の座標(0, 0)つまりメインの左上隅に表示されてしまう。もちろん、イベントリスナーが登録されていればすぐにrotate()メソッドが呼出され、インスタンスは楕円軌道に配置されて回転のアニメーションに入る。しかし、環境によってはイベント発生までの一瞬、左上隅にインスタンスが見えてしまうかもしれない。
それを避けるには、リスナー関数の呼出しを待たず、コンストラクタからインスタンス配置のメソッドsetRotation()を実行しなければならない。そして、インスタンスを初期位置に表示するためには、角度は変えず(つまりプロパティ値は加算せず)にupdate()メソッドで三角関数値を計算する必要があるのだ。これが、角度のプロパティ値加算をrotate()メソッドに移した理由である。
get/setアクセサメソッドで関連する値も更新する
ところで、メソッドupdate()はsetRotation()の中から呼出してもよくはないだろうか。それでも、特に不都合は起こらない。しかし、理屈としてupdate()メソッドの処理は、いつ行うのがよいか考えてみよう。
メソッドが具体的にやっているのは、角度の値にともなう計算だ。そうだとすれば、角度を変えたときに行うのが一番よい。そこで、 EllipticMotionクラスの第3の修正として、角度の取得・設定をget/setアクセサメソッドとし、update()はsetアクセサメソッドに書替えてしまうことにする。
get/setアクセサメソッドを定義したので、メソッドupdate()の呼出しはコンストラクタおよびrotate()メソッドから削除する。
これで、角度が変更されると同時に、角度に関わる演算が必ず処理されるようになった。今回のEllipticMotionクラスの修正はここまでだ(スクリプト2)。インスタンスのアニメーションについては、とくに変わりはない。インスタンスの重ね順が気になるのは、次回に対処する(図5)。
ループ処理で複数のインスタンスを生成する
今回の残る課題は、フレームアクションで複数のインスタンスを生成する処理だ。同じようなパターンのステートメントを必要な分だけ繰返したいとき、ループ処理という構文を用いる。具体的には、forステートメントを使ってみることにしよう。シンタックスは、つぎのとおりである。
第1の初期設定は、繰返し処理を始める前に行っておく設定だ。多くの場合、処理回数を数えるカウンタ変数の値が設定される。第2は、繰返し処理を継続する条件である。終了条件ではないことに注意が必要だ。また、誤ってfalseにならない条件を指定すると、無限ループに陥ってしまう。第3は、ひとつのループごとに行われる更新処理を記述する。カウンタ変数を使ったときは、その増減の処理(カウントアップ/ダウン)が定番だ。
それでは、Flashムービー(FLA)ファイルのフレームアクションを、forループによる処理に書直してみよう。作成するEllipticMotionインスタンスの数も、6つに増やすことにする(スクリプト3)。
forステートメントでは、第1に初期設定として、カウンタ変数iを整数(int型)で宣言した。第2の継続条件は、カウンタ変数値が変数nCountの値6未満の間だ。第3に更新処理で、カウンタ変数を1ずつカウントアップする。++はインクリメントの演算子で、「+= 1」と同じ処理になる[3]。カウンタ変数iの初期値は0なので、ループ処理は都合6回行われる。
forステートメントのコードブロック{}内では、インスタンスを作成して、それを表示リストに加えている。コンストラクタEllipticMotion()の第1引数に渡す角度は、カウンタ変数iを掛け算して、均等間隔に配置した。なお、コードブロックの中で変数_mcをvar宣言しても、初期化は1度行われるだけなので、エラーになることはない。[ムービープレビュー]を確かめると、6つのインスタンスが楕円軌道に配置されて回転する(図6)。
次回は、インスタンスの重ね順を正しく設定するとともに、アニメーションの回転する速さをマウスポインタの位置に応じて変えてみたい。
今回解説した次のサンプルファイルがダウンロードできます。