前回は、MovieClipインスタンスを水平スクロールさせ、その移動方向をマウスポインタの位置に対応させた。今回はさらに、スクロールスピードも、マウスポインタの位置に連動させよう。
前回作成したスクリプト4(図1)に修正を加えていく(サンプルファイルは第11回「MovieClipをスクロールさせる―条件判定」の2ページ目からダウンロードできる)。
マウスポインタの中央からの水平位置にスピードを比例させる
まず、マウスポインタのステージ中央からの水平位置に、インスタンスがスクロールするスピードを比例させたい。その場合、ステージ中央とマウスポインタとの水平座標の差を取ればよい。その結果の数値は、マウスポインタの水平位置がステージの左側か右側かによって、正負の符号が変わる。そのため、前回のスクリプト4に加えられている、スクロール方向を判定するif条件の処理は、もはや要らなくなる。
したがって、水平スクロールするピクセル数nNewSpeedを決める処理は、元のスクリプト4を以下のように修正する。なお、修正の経過がわかるように、元のステートメントはコメント化して残した[1]。また、ブロックコメント区切り記号を使うと、開始の演算子/*から終了の演算子*/まで、複数の行をまとめてコメントにすることができる。
もっともスピードを、ステージ中央からのマウスポインタの水平位置に単純に比例させたのでは、少し問題がある。マウスポインタをステージ中央付近で動かしていればよいものの、ステージの端にポインタを移動すると1フレーム当たりの移動距離がステージ幅の約半分のピクセル数になってしまうからだ。2フレームでステージ外に飛出してしまったのでは、左右どちらに移動しているのかももはやわからない。
そこで、スピード制限が必要になる。最高速度は、毎フレーム±20ピクセルとしよう。つまり、ステージ中央とマウスポインタとの水平座標の差が±20を超えたら(20より大きいか、-20より小さかったら)、移動ピクセル数を±20に設定し直すということだ。これは、if条件を使う処理の復習問題として丁度よいだろう。上述の修正で変数nSpeedが使われなくなったので、改めて最高速度の正の値20を納めることにする。
以上の修正を加えたMovieClipインスタンスのフレームアクションが、以下のスクリプト001である。[ムービープレビュー]で確かめると、マウスポインタの水平位置が中央から遠くなるほど、インスタンスのスクロールスピードが増す(図2)。
なお、上記スクリプト1には、新たに変数 nSensitivityが追加された。そして、ステージ中央とマウスポインタとの水平座標の差に、この値が掛合わされて、水平移動するピクセル数 nNewSpeedに代入されている。この変数nSensitivityは、マウスポインタの水平位置にスクロールスピードが比例する度合いを調整する係数だ。
この係数がない場合、スクロールするピクセル数そのものは、変数nSpeedを用いたif条件のステートメントによって±20の範囲内に抑えられている。しかし、移動ピクセル数を単純にステージ中央とマウスポインタとの水平座標の差に比例させれば、ポインタをステージ中央から左右各20ピクセル動かしただけで最高速度に達してしまう。
比例係数として変数nSensitivityの値0.2を掛け合わせることによって、ステージ中央からマウスポインタを左右100ピクセル(= 20/0.2)動かさないと、最高速度にはならなくなる。つまり、スピードの微調整がしやすくなるということだ。
プロパティ値の有効桁数
できあがったスクリプト1は、実際に使ったとき少々不具合を生じることがある。このフレームアクションの設定されたインスタンスを複数、横にすき間なくびったりと並べて、10分程度以上スクロールさせ続けてみる。すると、すき間がなかったはずのインスタンス間に間隔が空いたり、逆に重なったりしてしまう(図3)。
これはインスタンスの座標のプロパティ値に、誤差のあることが原因だ。たとえば、[プロパティ]インスペクタで、x座標値として「123.456789」と入力してみよう(図4)。すると、実際に設定される値は「123.4」となり、以降の端数は切捨てられてしまう。
ActionScriptでも、DisplayObject.x
プロパティに小数点以下の端数がある数値を設定すると、小数点以下第2位までの値に丸められてしまうのだ。前述のように複数のインスタンスにフレームアクションを設定した場合も、それぞれに毎フレーム設定される座標値は端数が毎回切捨てられる。そのカットされる数値の大きさは、当然インスタンスによって変わってくる。その違いが誤差になる訳だ。
小数点以下第3位以降の端数が小さいといっても、デフォルトのフレームレート(12fps)で1秒間に12回10分以上処理を繰返せば、累積の差が1ピクセル以上になっても不思議はない。その差が、インスタンス同士の間隔のばらつきとして現れることになる。
しかし、変数は最大で小数点以下15桁の値を保持できる[2]。したがって、座標値を変数に入れて扱えば、目に見える誤差が出ない十分な精度で処理できる。そこで、座標値を新たな変数nXに入れて処理するよう修正したのが、次のスクリプト2だ。
注目してほしいのは、変数nXにDisplayObject.xプロパティの値を代入したのは、変数宣言の初期化時のみだということである。リスナー関数xScroll()内では、変数nXに対して座標計算の処理を行う。そして、関数xScroll()の最後のステートメントで、DisplayObject.xプロパティに変数nXの値を設定している。つまり、変数宣言時を除いて、処理は変数値をプロパティに代入する一方通行のみのなのである。
これはたとえば、JPEG画像を作成する場合と同じ考慮だ。 JPEG画像に修正が必要なとき、そのJPEGファイルを開くのではなく、劣化しない形式(PNGやPSDなど)で保存しておいた元の画像に手を加えるだろう。JPEGファイルを開いて再びJPEG保存すれば、画像がさらに劣化してしまうからだ。
変数も宣言時にプロパティの初期値を保持したら、以降は2度とプロパティ値で上書きしない。それをしてしまうと、プロパティのもつ誤差により、変数値が「劣化」することになる。したがって、上記スクリプト2では、値の設定を変数からプロパティへの一方通行としているのだ。これで、横に並べたインスタンスをスクロールさせ続けても、ピクセル単位の誤差が生じることは防げる(図5)。
マウスポインタに連動してインスタンスをスクロールさせるムービーはこれで完成だ。次回は、キーボードのキーで、インスタンスをコントロールしてみたい。
今回解説した次のサンプルファイルがダウンロードできます。