サイトトップ

Director Flash 書籍 業務内容 プロフィール

アッと驚く達人の技Flash MX ActionScript実践技&ウラ技大全

045 キー操作でムービーの表示状態をコントロールする

ID: FB0303002 Page: 111/Line: 4


[p.111「3 カーソルキーでスクロールするソース」のスクリプト]

onClipEvent (keyDown) {
  if (Key.isDown(Key.UP)) {
    _root.IMAP._y -= 2;
    OSI = "UP";
  }
 if (Key.isDown(Key.DOWN)) {
    _root.IMAP._y += 2;
    OSI = "DOWN";
  }
  // [中略]
}


補足

このサンプルスクリプトは、'if'アクションが羅列されています。キーの数分だけの処理を書く訳ですから、ある程度長くなるのはやむをえません。しかし、単に長いというだけでなく、見づらいという印象を受けると思います。それは、どのキーでどのような処理が行われるのかが、最悪([end]キーの場合)スクリプトを最後まで見ないとわからないからです。そうすると、修正が入るたびに、スクリプトを頭から終わりまで見直さなければならないということになります。

キーに対応した処理を定義する部分と、実際のキー操作に応じてその処理を実行する部分とを分けることができれば、スクリプトはずっと見通しがよくなります。そして、スクリプトの仕様が変わった場合にも、修正する場所がすぐにわかります。つまり、メインテナンスがしやすいということです。

そのような観点から構成し直したスクリプトが以下です。書籍のサンプルとは異なり、キー操作でコントロールされるインスタンス(_root.IMAP)のMovieClipアクションに設定しています。

// MovieClip: キー操作でコントロールされるインスタンス_root.IMAP
// MovieClipアクション

onClipEvent (load) { //[A]キー操作に対する処理の定義
//[1]キーに対応した設定するプロパティを設定する配列の生成
actions_array = new Array();
//[2]各キーのインデックスに設定プロパティと値のObjectオブジェクトを格納
actions_array[Key.UP] = {sAction:"UP", _y:-2};
actions_array[Key.DOWN] = {sAction:"DOWN", _y:2};
actions_array[Key.LEFT] = {sAction:"LEFT", _x:-2};
actions_array[Key.RIGHT] = {sAction:"RIGHT", _x:2};
actions_array[Key.PGUP] = {sAction:"ZOOM IN", _xscale:2, _yscale:2};
actions_array[Key.PGDN] = {sAction:"ZOOM OUT", _xscale:-2, _yscale:-2};
actions_array[Key.HOME] = {sAction:"ROTATION R", _rotation:2};
actions_array[Key.END] = {sAction:"ROTATOPM L", _rotation:-2};
}
onClipEvent (keyDown) {   //[B]キー操作に対する処理の実行
  //[3]配列からキーコードを順に取出す
  for (i in actions_array) {
    if (Key.isDown(i)) {   //[4]キーが押されていたら
      //[5]キーに対応した設定するプロパティのオブジェクトを取出す
      oProperties = actions_array[i];
      //[6]オブジェクトからプロパティを順に取出す
      for (j in oProperties) {
        myValue = oProperties[j];   //[7]プロパティ値の取得
        if (isNaN(myValue)) {   //[8]プロパティが数値でなければ
          this[j] = myValue;
        } else {   //[9]プロパティが数値なら
          this[j] += myValue;
        }
      }
      //[10]情報表示用のMovieClipのfunctionを実行
      _parent.IMC.xUpdateInfo(this);
    }
  }
}

[A]どのキーが押されたらどういう処理をするかは、'onClipEvent (load)'イベントハンドラアクションにまとめて定義してあります。対象となるキーは複数で、数は変動することが考えられます。複数のデータを格納するには、配列(Arrayオブジェクト)やObjectオブジェクトがよく用いられます。今回は、配列を使用しました。

'Key.UP'や'Key.DOWN'などのプロパティは、各キーのキーコード値を返します。つまり、整数です。しかも、コードは他のキーと重複することがありません。整数インデックスで値を管理する配列に適した状況です。

[1]'onClipEvent (load)'イベントハンドラの第1ステートメントでは、Arrayオブジェクトを初期化して配列のインスタンスを生成しています。この配列に、各キーに対応した処理のためのデータを格納します。

[2]'Key.UP'や'Key.DOWN'など各キーコードをインデックス番号として、処理すべき変数やプロパティのデータを格納します。このデータはObjectオブジェクトで作成することにしました。複数のプロパティとその値を設定するには、Objectオブジェクトインスタンスを使うと便利です。このObjectインスタンスを使うという手法は、ActionScriptのメソッドでも'MovieClip.localToGlobal'や'MovieClip.duplicateMovieClip'(補足解説「032 ランダムに犬の足跡を表示する」参照)などで用いられています。Objectインスタンスを作成してプロパティを定義するには、以下のように記述します。

{プロパティ1の名前:プロパティ1の値 , プロパティ2の名前:プロパティ2の値, ... };

上記のスクリプトでは、プロパティsActionに処理内容を示すタイトルのストリング、それに各キーごとに設定するMovieClipのプロパティと増減値を定義しています。プロパティの数には制限がありません。拡大/縮小('Key.PGUP/Key.PGDDN')の場合には、'_xscale'と'_yscale'の2つのプロパティを設定しています。

以上が、キーごとの処理の定義部分です。処理内容に変更や追加があったら、この'onClipEvent (load)'イベントハンドラアクションの定義内容を修正すればよいということです。

[B]実際にキーが押されたときのMovieClipに対するコントロールは、書籍のスクリプトと同じく'onClipEvent (keyDown)'イベントハンドラで行っています。[B]の'onClipEvent (load)'イベントハンドラで、各キーに対する処理内容はすべて配列に格納されています。ですから、MovieClipのコントロールは、その配列の内容をすべて確認して実行すればよいことになります。したがって、'if'アクションの羅列は必要なく、代わって'for..in'アクションでキーコードや処理すべきプロパティを取出して確認しています。

[3]'for..in'アクションは、オブジェクトにユーザーが設定した変数やプロパティをすべて取出して処理します。配列を処理するには、'for'アクションが使われることが多いです。しかし、'for'アクションは、インデックスの「番号」を順にカウントアップしてエレメントを調べていきます。今回はキーコードをインデックスにしたので連番でなく、番号が飛び飛びになっています。こういうときは、'for..in'アクションを使うと番号の連続性は関係なく、設定されているプロパティだけを順々に取出すことができます。配列の場合、取出されるプロパティというのはインデックス番号になります。

[4]取出されたインデックス番号は、キーコードです。したがって、'Key.isDown'メソッドを使って、そのキーが押されているかどうかを判定することができます。

[5]キーが押されていたら、配列からそのキーコードのインデックスに格納されているObjectインスタンスを取出します。インスタンスにアクセスするには、配列アクセス演算子'[]'を使います。

[6]取出したObjectオブジェクトには、複数のプロパティが定義されています。これらをすべて調べるには、また'for..in'アクションを使います。'for..in'アクションをオブジェクトに対して使用すると、プロパティ名を取出すことができます。

[7]オブジェクトに定義したプロパティ名で値を調べる場合も、配列アクセス演算子'[]'を使います。oPropertiesに設定されているプロパティsActionの値を取出して変数myValueに代入するには、以下のように記述します。

myValue = oProperties["sAction"];

2つめの'for..in'アクションでは、プロパティ名は変数jに格納されますので、その値を使ってプロパティ値を調べています。

[8]今回のムービーの処理では、MovieClipのプロパティ値(たとえば'_x'や'_rotation')は加算することになっています。そこで、'isNaN'関数を使って値が数値(でない)かどうかを調べて、処理を分岐しています('NaN'は数値でない(Not a Number)を意味する特別な変数です。なお、「値がNaNかを調べる」参照)。

'isNaN'関数が'true'を返し、プロパティ値が数値でなければ(具体的にはsActionについては)、値を(加算でなく)更新します。プロパティを設定する場合にも、配列アクセス演算子'[]'が使用できます。

[9]プロパティの値が数値の場合には、現在値に値を加算します。配列アクセス演算子'[]'は、ドットシンタックスと同じ処理に使うことができます(詳しくは、オンラインヘルプ「ActionScript辞書」の「[](配列アクセス)」項を参照)。たとえば、以下の2つのステートメントは、同じ処理です。配列アクセス演算子'[]'中に指定するプロパティ名は、ストリングであることにご注意ください。

this._x += 2;

this["_x"] += 2;

[10]最後に、コントロール後のMovieClipのプロパティ情報を表示します。情報の表示用には、別のMovieClipインスタンス_root.IMCが用意されています。この情報表示のためのスクリプトは、インスタンスIMCに'function'として設定することにしました。'function'名はxUpdateInfoです。引数としてこのコントロール対象のMovieClipインスタンス自身(の参照)である'this'を渡して、この'function'を実行しています。

情報表示用MovieClipインスタンス_root.IMCに設定したMovieClipアクションは、つぎのとおりです。

// MovieClip: 情報表示用インスタンス_root.IMC
// MovieClipアクション
onClipEvent (load) {   //初期設定
  function xUpdateInfo(my_mc) {   //情報表示用のfunction
    VQ = my_mc.sAction;
    VX = my_mc._x;
    VY = my_mc._y;
    VZ = my_mc._xscale;
    VR = my_mc._rotation;
  }
}

MovieClipインスタンスに対するfunction定義は、通常'onClipEvent (load)'イベントハンドラアクションに記述します。'onClipEvent (load)'ハンドラは、初期設定を実行するのに適しています。'function'中で行っている処理は、基本的に書籍のサンプルスクリプトと違いはありません(プロパティや変数のターゲットバスが引数my_mcに変更されていることと、処理内容のテキストがsActionに格納されていることくらいです)。

しかし、プロパティ値を得るターゲットパスを'function'の引数my_mcにしたことには、意味があります。引数にすることで、ターゲットとなる_root.IMAPのインスタンス名に依存しなくなります。つまり、IMAPというインスタンス名を変更しても、このMovieClipアクションは修正する必要がありません。

同じことは、前述_root.IMAPのMovieClipアクションについてもいえます。コントロールされるMovieClip自体にスクリプトを記述したことにより、ターゲットパスは省略するかあるいは'this'でよくなっています。したがって、このMovieClipアクションもインスタンス名には依存しないのです。唯一ターゲットパスを特定しているのは、表示用のMovieClipである_root.IMCの'function'を呼出すときだけです。

このようにインスタンス名の決め打ちをしないスクリプティングを心掛けることにより、メインテナンスの手間を省くことができます。また、他の場面やプロジェクトにも流用しやすい汎用的なスクリプトにもなるのです。

_____

作成者: 野中文雄
作成日: 2003年3月3日


Copyright © 2001-2017 Fumio Nonaka.  All rights reserved.