Macromedia Flash非公式テクニカルノート

if/else if/elseアクションを使った処理

ID: FN0109008 Product: Flash

Platform: All
Version: 5.0

1. 処理の流れ
'if'アクションは、条件を評価して、判定が'true'であればステートメントを実行します。'else'アクションを含むと、結果が'false'の場合に、指定されたステートメントを実行します。さらに、'else if'アクションは、最初の'if'で条件が'false'と評価されたときに、さらに条件を指定してステートメントを処理することができます。

以下のサンプルスクリプトをMovieClipのオブジェクトアクションに設定すると、水平方向に往復を繰り返します。左右の折り返し座標は、左が0で右が550(デフォルトのステージの両端)、移動の速度は1フレーム10ピクセルです。これらの初期値は、'onClipEvent (load)'ハンドラで設定しています。なお、MovieClipの'_X'プロパティは、基準点の座標です。折り返し座標に達したかどうかは、この基準点をもとに計算しています。サンプルスクリプトで使用しているメソッド・アクション・演算子などについて、詳しくは「ActionScript辞書」をご参照ください。

//初期設定
onClipEvent (load) {   //MovieClipが表示されたとき実行
   nDirection = 1;   //移動方向: 1が右/-1が左
   nStep = 10;   //1フレーム当たりの移動速度(ピクセル)
   nMinX = 0;   //左の折り返し地点の座標
   nMaxX = 550;   //右の折り返し地点の座標
}
//アニメーション処理
onClipEvent (enterFrame) { //フレーム移動時に実行
   nNextX = _x+nStep*nDirection;   //つぎの移動先のx座標を計算
   if (nNextX>=nMaxX) {   //つぎの移動先座標が右の折り返し地点を超えた場合
     _x = nMaxX;   //右の折り返し地点の座標に移動
     nDirection = -1;   //移動方向を左(-1)に設定
   } else if (nNextXn<=MinX) {   //つぎの移動先座標が左の折り返し地点を超えた場合
     _x = nMinX;   //左の折り返し地点の座標に移動
     nDirection = 1;   //移動方向を右(1)に設定
   } else {   //その他(左右の折り返し地点の中間)の場合
     _x = nNextX;   //つぎの移動先の座標に移動
   }
}

'else if'は、'else'アクションの中に'if'アクションを記述(ネストあるいは入れ子に)したのと同じ処理になります。上述のスクリプトで条件判定の部分は、以下のように記述することもできます。'else if'アクションを使った方が、スクリプトは見やすくなります。

if (nNextX>=nMaxX) {
   _x = nMaxX;
   nDirection = -1;
} else {
   if (nNextX<=nMinX) {
     _x = nMinX;
     nDirection = 1;
   } else {
     _x = nNextX;
   }
}

なお、'else if'アクションは、「ActionScript辞書」に記載がありません。ただ、これは単なる漏れだと思われます。ActionScript Dictionary(ActionScript辞書英文改訂版)には、掲載されています。

2. 条件の順序
条件が'true'と評価されると、指定されたステートメントを実行して、そのレベルの条件分岐処理は終了します。続く'else if'の条件を同時に満たす場合であっても、そのステートメントは実行されません。したがって、条件を判定する順序は重要です。この点を理解して、うまく整理すると、すっきりとしたスクリプトを書くことができます。

2000年問題で、閏年が注目されました。閏年は、4で割れる年です。ただし、100で割り切れる場合には、例外として閏年になりません。さらにその例外として、400で割り切れる場合には閏年です。この最後の例外まで考慮していないプログラムは、2000年を閏年でないと判定して、問題の生じる可能性があった訳です。では、閏年を判定する関数をActionScriptで書くとどうなるでしょう。これは、例外から先に処理していくと、見やすい構造になります。

//閏年を判定する関数
function xIsLeapYear (nYear) {
   var bResult;   //ローカル変数宣言
  //まず例外から判定
   if (nYear%400 == 0) {   //400で割り切れる
     bResult = true;   //閏年: 'true'を変数に代入
  //400では割り切れない場合
   } else if (nYear%100 == 0) {   //100で割り切れる
     bResult = false;   //閏年でない: 'false'を変数に代入
  //100でも割り切れない場合
   } else if (nYear%4 == 0) {   //4で割り切れる
     bResult = true;   //閏年: 'true'を変数に代入
   } else {   //その他の場合
     bResult = false;   //閏年でない: 'false'を変数に代入
   }
   return bResult; //変数の値を返す
}

3. 見やすさか速さか
閏年判定のスクリプトは、見やすい構造になっています。けれど、処理の速度を考えると、問題がないわけではありません。条件判定は、'true'と評価されたら指定のステートメントを実行して、その処理を抜けます。つまり、先に'true'と判定されれば、後の判定をやらずに済みます。最後の判定まで'true'と評価されなければ、条件の数だけ処理が増えることになります。

そう考えて上述のスクリプトを見ると、真っ先に処理を終えるのは400年に一度の閏年の場合です。逆に、約4分の3を占めるはずの通常の年は、最後の判定まで処理を抜けられません。処理の効率からいうと、これは決して最適とはいえないのです。効率を考えて条件の順序を変えたのが、以下のスクリプトです。

//効率を考えた閏年を判定する関数
function xIsLeapYear (nYear) {
   var bResult;
  //まず普通の年から判定
   if (nYear%4 != 0) {   //4で割り切れない
     bResult = false;   //普通の年
  //4で割り切れる場合
   } else if (nYear%100 != 0) {   //100で割り切れない
     bResult = true;   //普通の閏年
  //100で割り切れる場合
   } else if (nYear%400 != 0) {   //400で割り切れない
     bResult = false;   //例外的に閏年でない
   } else {   //400で割り切れる場合
     bResult = true;   //例外の例外の閏年
   }
   return bResult;
}

任意の年を大量に判定する場合には、このスクリプトの方が処理は速くなります。ただ、見やすい構造とはいえないかもしれません。見やすさと速さのどちらを優先するかは、その処理の内容によります。ゲームのアニメーションを制御するスクリプトでしたら、スピードが重要なことも多いです。閏年を判定する関数の場合には、大量一括処理をするというケースはあまり考えにくいといえます。そのときには、スクリプトの見やすさを優先した方がよいでしょう。

4. もっと速さを
上述の効率を考えたスクリプトには、まだ若干処理速度を改善する余地があります。まず、条件の判定で、0以外の数値は'true'と評価されます。したがって、(nYear%整数 != 0)は、単に(nYear%整数)と記述することができます。つぎに、判定後のステートメントで、結果を一旦変数bResultに代入している点です。これは、条件が'true'と評価された場合には、他の判定を行うことなく処理を抜けることを示すため、このような記述にしました。けれども、変数に代入せず、直接'return'アクションで値を返す方が、簡潔な処理になります。なお、'return'アクションは、値を返して、直ちに関数の実行を終了します(詳しくは、「ActionScript辞書」をご参照ください)。

なお、'?:'条件演算子を使うと、さらに処理が速くなります。'?:'は、条件の評価に対応して値を返す演算子です(詳しくは、「ActionScript辞書」をご参照ください)。Microsoft Excelの'if'関数のようなものと考えればよいでしょう。いつも'if/else if/else'条件処理の代替になるとはかぎりません。ただ、今回の例のように、値を返す処理の場合には、この演算子を使うとスピードが速くなります。

以下が、'?:'演算子を使ったサンプルスクリプトです。処理構造は、上述の効率を考えたスクリプトと同じです。サンプルは見やすいように途中改行を入れていますが、「アクション」パネルの「ノーマルモード」では、'return'アクションのステートメント1行になります。とくに解説はつけませんので、練習問題として考えてみてください。

function xIsLeapYear (nYear) {
   return (nYear%4) ? false :
  ((nYear%100) ? true :
  ((nYear%400) ? false :
  true));
}

_____

作成者: 野中文雄
作成日: 2001年9月21日


© 2001 and beyond Fumio Nonaka All rights reserved.