ActionScript 3.0で始めるオブジェクト指向スクリプティング

第11回MovieClipをスクロールさせる―条件判定

サムネールを水平に並べてスクロールさせるメニューのインターフェイスがある図1⁠。スクロールする方向やスピードは、マウスポインタの位置によって変わる。今回と次回の2回にわたって、このようなMovieClipのアニメーションをつくってみたい。今回のポイントは、条件を判定して分岐する処理の書き方だ。

図1 サムネールがマウスポインタの位置に応じてスクロール
図1 サムネールがマウスポインタの位置に応じてスクロール

ループする水平スクロール―ifステートメント

まずは、これまでの復習として、毎フレーム5ピクセルで水平方向右に単純にスクロールするMovieClipのフレームアクションを書いてみようスクリプト1⁠。スクリプトを書くときは、いきなり目的の動作を実現しようとするのでなく、処理を小分けにして段階的に進めていくことが大切だ。

上級者でも、ひとつのミスもなく、1回で動きを完成することはたやすくない。小分けにして作成と確認を繰返していけば、問題が出たときも、その調査対象を限定できる。事件の早期解決には、何より容疑者の絞り込みが重要なのだ。

スクリプト1 MovieClipインスタンスを水平スクロールさせる
// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 5;
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
  x += nSpeed;
}

毎フレームの描画更新は、DisplayObject.enterFrameイベントで受取る。MovieClipインスタンスにこのイベントのリスナー関数を登録して、関数内では初期値として定めたピクセル数をインスタンスのDisplayObject.xプロパティに代入している図2⁠。このアニメーションの処理については、これ以上説明の必要はあるまい。

図2 インスタンスを毎フレーム10ピクセル水平方向右にスクロールさせるフレームアクション
図2 インスタンスを毎フレーム10ピクセル水平方向右にスクロールさせるフレームアクション

次は、ステージ右端を超えたら、左端にループしてスクロールを続ける処理だ。インスタンスの水平座標がステージ右端を超えたかどうかの条件を判定する必要がある。ここで、ifステートメントを使う。シンタックスは、次のとおりだ。

if (条件) {
  // 条件が満たされた場合の処理
}

今回の条件は、インスタンスのDisplayObject.xプロパティの値が、ステージ右端の座標値つまりStage.stageWidthを超えたかどうかである。

この条件を表す式は、数学の時間に習った不等式と同じく、不等号<>で表す。等しい場合を含めるときは、等号を右に添える<=>=⁠。注意しなければならないのは、両辺の値が等しいこと(等価)を示すには、等価演算子==が用いられることだ。ActionScriptでは、等号=は代入の演算子として区別される。

MovieClipインスタンスの水平座標がステージ右端を超え、if条件が満たされたなら、インスタンスを左端に移動する。ステージ左端の水平座標は、もちろん0である。すると、条件判定のifステートメントは、次のように記述すればよさそうに思える。

if (x>stage.stageWidth) {   // ステージ右端を超えたら
  x = 0;   // ステージ左端に移動
}

実際、[ムーピープレビュー]を確かめると、ステージ右端を超えたインスタンスは、また左端から現れてスクロールを続ける図3⁠。アニメーションが、インスタンスひとつであれば、差支えはないかもしれない。しかし、並べてスクロールすると、問題が明らかになる。

図3 インスタンスはステージ右端を超えたら左端からスクロール
図3 インスタンスはステージ右端を超えたら左端からスクロール

なぜなら、ステージ右端からはみ出すピクセル数は、インスタンスによって最小1ピクセルから最大5ピクセルまで異なる可能性がある図4⁠。そのピクセル数に関係なく、インスタンスをステージ左端の水平座標0に移動すると、インスタンス同士の間隔が変わってしまう。つまり、ステージ右端を1ピクセルだけ超えて0ピクセルに移動したインスタンスは、5ピクセル超えてようやく0ピクセルにループしたインスタンスより4ピクセル早く進むことができ、後続のインスタンスとは間隔が開いてしまうのである。

図4 ステージからはみ出すピクセル数はインスタンスによって変わる
図4 ステージからはみ出すピクセル数はインスタンスによって変わる

インスタンスの間隔を変えないためには、一律に同じ座標に移すのではなく、一定の距離左に移動すればよい。つまり、水平座標からステージ幅を差引くのである。現在値から数値を差引くときは、演算子-=を用いる。

前述スクリプト1にこの条件判定の処理を加えたのが、以下のスクリプト2である。

スクリプト2 インスタンスがステージ右端を超えたらステージ幅分左に移動
// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 5;
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
  x += nSpeed;
  if (x>nStageRight) {   // ステージ右端を超えたら
    x -= nStageWidth;   // ステージ左端に移動
  }
}

マウスポインタの位置でスクロール方向を変える―else/else ifステートメント

次は、マウスポインタの位置によって、MovieClipインスタンスのスクロールする方向を変えてみる。ポインタの位置がステージ中央より左寄りならインスタンスを右にスクロール、そうでなければ左にスクロールするように処理を書き加えよう。ここでまた条件判定が必要だ。

今回は条件を満たす場合と満たさない場合、それぞれにやるべきことがある。条件を満たさない場合の処理は、以下のようにelseステートメントで追加する。条件を満たすかどうか調べることは、条件を「評価」するという。そして、if条件が満たされると、ActionScriptは評価の結果として、条件の式をtrueという値に変換する。そして、条件が満たされなければ、評価の結果はfalseになる。

if (条件) {
  // 条件の評価がtrueの場合の処理
} else {
  // 条件の評価がfalseの場合の処理
}

マウスポインタの座標は、DisplayObject.mouseX/DisplayObject.mouseYで調べられた。ただし、ステージから見た座標が知りたいので、ターゲットはStageオブジェクトにする必要がある。移動方向の変更は、移動ピクセル数の符号をプラスマイナスで切替えればよいスクリプト3⁠。移動ピクセル数の値を変化させるのは、次回の課題とする。

スクリプト3 マウスポインタの位置によりインスタンススクロール方向が左右に変化
// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 5;
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
var nStageCenter:Number = (nStageRight+nStageLeft)/2;   // ステージの水平方向中央の座標値
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
  var nNewSpeed:Number;
  if (stage.mouseX<nStageCenter) {   // マウスポインタがステージ中央より左寄りなら
    nNewSpeed = nSpeed;   // 移動方向を右(正)に
  } else {   // マウスポインタがステージ中央もしくは右寄りなら
    nNewSpeed = -nSpeed;   // 移動方向を左(負)に
  }
  x += nNewSpeed;   // 設定された方向にインスタンスを移動
  if (x>nStageRight) {
    x -= nStageWidth;
  }
}

まず、ステージの水平座標中央の値は、変数nStageCenterとして設定した。この値を計算するとき、ステージ両端の座標を引き算するのでなく、足して平均を取ることに注意しよう。

次に、そのステージの水平座標中央の値とステージから見たマウスポインタのx座標値とを比べる。マウスポインタの座標の方が小さければ、if条件はtrueと評価され、移動方向は右方向つまり移動ピクセル数をプラスのnSpeedとする。条件の評価がfalseなら、移動方向は左で移動ピクセル数はマイナスのnSpeedになる。これらの値は、ローカル変数nNewSpeedに格納する。

あとは、変数nNewSpeedの値をインスタンスのDisplayObject.xプロパティに設定すれば、マウスポインタの位置に応じて水平スクロール方向が切替わる。[ムービープレビュー]で動きを確認してみよう図5⁠。

図5 マウスポインタがステージの中央より右か左かにより水平スクロール方向が変わる
図5 マウスポインタがステージの中央より右か左かにより水平スクロール方向が変わる

スクリプト3で気になるのは、インスタンスがステージ左端を超えたとき、右端にループしないことだ。そこで、条件判定をさらに加えて、ループする処理を組込むことにする。

ステージ右端を超えたら左端にループするifステートメントはすでに記述してある。これにelseステートメントを書き足したのでは、意図する処理にならない。インスタンスがステージの領域内をアニメーションしていて、ループしなくてよい場合まで含んでしまうからだ。さらに条件を追加して、インスタンスがステージ左端の外に移動した場合にループさせたい。このように条件を加えるとき使うのがelse ifステートメントである。

if (条件A) {
  // 条件Aの評価がtrueの場合の処理
} else if (条件B) {
  // 条件Aの評価がfalseかつ条件Bの評価がtrueの場合の処理
} else {
  // 条件Aの評価も条件Bの評価もfalseの場合の処理
}

else ifステートメントはいくつでも追加できるので、何段階もの条件を設定して、それぞれについて処理を記述することも可能だ。また、elseステートメントは、不要なら書かなくてよい。すると、インスタンスが左端を超えたら右端にループする処理は、前のフレームアクション(スクリプト3)に追加すると、次のスクリプト4のようになる。

スクリプト4 インスタンがステージいずれの端を超えても反対の端にループする
// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 5;
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
var nStageCenter:Number = (nStageRight+nStageLeft)/2;
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
  var nNewSpeed:Number;
  if (stage.mouseX<nStageCenter) {
    nNewSpeed = nSpeed;
  } else {
    nNewSpeed = -nSpeed;
  }
  x += nNewSpeed;

  if (x>nStageRight) {
    x -= nStageWidth;
  } else if (x<nStageLeft) {   // ステージ左端を超えたら
    x += nStageWidth;   // ステージ右端に移動
  }
}

これで、インスタンスが左右どちらの端を超えても、反対の端にループしてスクロールを続けるようになった。次回は、ステージの水平方向中央からマウスポインタが離れるほど、速くスクロールさせる処理を加えて、スクリプトのアニメーションを完成させる。

今回解説した次のサンプルファイルがダウンロードできます。

おすすめ記事

記事・ニュース一覧