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

第9回座標の天動説と地動説

今回から、MovieClipインスタンスの座標の扱いについて解説する。お題は、マウスポインタの後を追うMovieClipのフレームアクションだ。座標を考えるときは、どこから見た値なのかを意識することが大切になる。

インスタンスとマウスポインタの座標

まず、MovieClipインスタンスの座標とマウスポインタの座標にアクセスするプロパティの確認が必要だ表1⁠。マウスポインタの座標は、調べることができるだけで、設定はできない。

表1 インスタンスとマウスポインタの座標についてのプロパティ
プロパティ説明
mouseXマウスポインタのx座標を、ピクセル数で返す。取得のみで、設定はできない。
mouseYマウスポインタのy座標を、ピクセル数で返す。取得のみで、設定はできない。
xインスタンスのx座標を、ピクセル数で示す。
yインスタンスのy座標を、ピクセル数で示す。

確認のため[ヘルプ][MovieClipクラス][プロパティ]一覧を見ると、デフォルトではこれらのプロパティが表示されていない図1⁠。

図1 ⁠ヘルプ]に表示された[MovieClipクラス][プロパティ]一覧
図1 [ヘルプ]に表示された[MovieClipクラス]の[プロパティ]一覧

しかし、表の上部に「継承されるブロパティを表示」というボタンがある(図1⁠⁠。これをクリックすると、表が拡張されて、上表1の座標のプロパティも現れる図2⁠。

図2 ⁠MovieClipクラス][プロパティ]一覧が拡張して表示されたxとy
図2 [MovieClipクラス]の[プロパティ]一覧が拡張して表示されたxとy

最初の[プロパティ]一覧に表示されていたのは、表の右端の「定義元」がMovieClipと記載されたものだ。実は、これらがMovieClipクラスに定義されたプロパティなのである。

[プロパティ]一覧を拡張すると、それ以外の「定義元」のプロパティも示される。x/ymouseX/mouseYプロパティの定義元には、⁠DisplayObject」と記されている。つまり、これらのプロパティはDisplayObjectクラスに定義されているのだ。前回まで使っていたrotationもこのDisplayObjectクラスのプロパティである。なぜそれらが、MovieClipインスタンスからアクセスできるのか。

多くのクラスは、階層構造を成している。その場合、ベースとなるクラスのプロパティやメソッド一式を引継ぎ、そこに新たなプロパティやメソッドを追加するかたちで新しいクラスが定義される。ベースとなるクラスは一般に「スーパークラス」と呼ばれ、それを拡張したいわば子どものクラスは「サブクラス」という。

DisplayObjectとMovieClipクラスは、このスーパークラスとサブクラスの関係にある[1]⁠。だから、DisplayObjectクラスのプロパティは、MovieClipインスタンスから使えるのである。スーパークラスの機能(プロパティやメソッド)がサブクラスで使えるプログラミングの仕組みを「継承」という。

マウスポインタの水平方向の動きに追随させる?

ではまず、MovieClipインスタンスを、マウスポインタの水平方向の動きに追随させてみる。いきなり水平・垂直両方向の処理を書く前に、できるだけ小分けして確認しながら進めるのは、スクリプティングを効率的に行うためのコツだ。小分けすれば頭を整理しやすいし、問題が起こったときも早期発見・早期治療が可能になる。

スクリプトは、MovieClipのフレームアクションとして記述する。アニメーションの処理だから、Event.ENTER_FRAMEイベントで処理するのが定石だ。すると、つぎのようなフレームアクションでよさそうに思える図4⁠。

addEventListener(Event.ENTER_FRAME, xFollowMouse);
function xFollowMouse(eventObject:Event):void {
  x = mouseX;
}
図4 マウスポインタの水平方向の動きに追随させるフレームアクション
図4 マウスポインタの水平方向の動きに追随させるフレームアクション

ところが[ムービープレビュー]を確認すると、チカチカと点滅したような動きになる。ただ、マウスポインタの水平方向の動きに、反応している様子は伺える。なぜ、このような動作になるのか。ヒントは、初めに確認した[ヘルプ]にある。

mouseXは、MovieClipインスタンスの(継承した)プロパティだった。ということは、インスタンスによって、その値が異なりうることを意味する。マウスポインタは、コンピュータの画面にひとつしか存在しないのに、である。

理由は、mouseXプロパティが、インスタンスの基準点から見た座標を返すためだ。つまりこの値は、マウスポインタがインスタンスの右側にあればプラスに、左側にあるとマイナスになる。地球から見て太陽が昇ったり沈んだりしている、と考えるようなものだ。つまり、DisplayObject.mouseX/DisplayObject.mouseYは、⁠天動説」のプロパティなのである。

対するDisplayObject.x/DisplayObject.yについては、自分から見た自分の位置というのは意味がない。したがって、自分の配置されたタイムラインつまり親から見た座標を示す。地球は太陽の周りを回っているのであり、その太陽系も宇宙の中で移動している。自らの属する空間から見た自分の位置を考えるというのは、⁠地動説」である。

座標の基準が異なるまま、プロパティに値を代入すれば、当然意図しない動きになる。たとえば、MovieClipインスタンスがメインタイムラインのx座標100ピクセルに、マウスポインタが同じく50ピクセルにあったとする。しかし、MovieClipから見たマウスポインタは左に50ピクセルの位置になるので、インスタンスのDisplayObject.mouseXプロパティは-50を返す図5⁠。

図5 DisplayObject.xプロパティとDisplayObject.mouseXプロパティの値
図5 DisplayObject.xプロパティとDisplayObject.mouseXプロパティの値

-50をインスタンスのDisplayObject.xプロパティに設定すれば、ステージ左端からさらに外側50ピクセルの位置に配置されてしまう。マウスポインタは動かなくても、ステージ左端の外側-50の位置から見れば、DisplayObject.mouseXは100になる。したがって、インスタンスはまた水平座標100ピクセルの位置に戻る。これを繰返すと、点滅したような動きになるのである。

地動説で座標空間を一致させる

問題を解決する方法は、天動説か地動説か、どちらかに基準を合わせることだ。今回は、地動説を採ってみる。つまり、前記フレームアクションのリスナー関数xFollowMouse()内のステートメントで、代入式の左辺であるDisplayObject.xプロパティには、変更を加えない。右辺のDisplayObject.mouseXプロパティについて、そのターゲットを親タイムラインに修正すればよい。

親のインスタンスを参照するプロパティは、DisplayObject.parentだ。このターゲットを加えれば、マウスポインタの水平座標に、インスタンスが追随して移動する。

addEventListener(Event.ENTER_FRAME, xFollowMouse);
function xFollowMouse(eventObject:Event):void {
  x = parent.mouseX;
}

[ムービープレビュー]で、MovieClipインスタンスがマウスポインタの水平方向の動きに追随することを確認しよう。それができたら、垂直方向の動きも同じように追加すればよいスクリプト1⁠。

スクリプト1 MovieClipインスタンスをマウスポインタに追随させるフレームアクション
// MovieClip: マウスポインタに追随させるインスタンス
addEventListener(Event.ENTER_FRAME, xFollowMouse);
function xFollowMouse(eventObject:Event):void {
  x = parent.mouseX;
  y = parent.mouseY;
}

[ムービープレビュー]で確認すると、水平・垂直方向ともインスタンスがマウスポインタの動きに追随するようになる図5※2⁠。

図5 MovieClipインスタンスはマウスポインタの動きに追随する
図5 MovieClipインスタンスはマウスポインタの動きに追随する

では、地動説ではなく、天動説で処理する方法はないか。それは次回説明したい。

図6 MovieClipインスタンスはマウスポインタがステージ外に出る直前の位置で停止
図6 MovieClipインスタンスはマウスポインタがステージ外に出る直前の位置で停止

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

おすすめ記事

記事・ニュース一覧