ここでは、エクスプレッションのフロー制御文でよくある誤りの解決方法について説明します。
エクスプレッションで while ループや do ループ、for ループを使用する場合は、ループのテスト条件で評価される変数またはアトリビュートの値を必ず変更するようにしてください。この変更を忘れると、Maya が応答しなくなる場合があります。
Balloon というオブジェクトを作成し、while ループを使用してアニメーション再生の 3 秒後以降に Balloon の Y スケーリングを大きくするケースについて考えてみましょう。
while (time > 3) Balloon.scaleY = time;
このエクスプレッションでは、アニメーション時間が 3 秒を超えた後も Balloon のスケール Y (scaleY)アトリビュートに time の値が大きくなりながら代入されると思われるかもしれませんが、実際には time が 3 を超えるすぐに Maya が応答しなくなります。このとき、while 条件は true なので、while ループ文 Balloon.scaleY = time は無限に繰り返されます。
アトリビュートはエクスプレッション内部で文によって設定されますが、エクスプレッションの実行が終了するまでは、アトリビュートの実際の更新は行われません。この例ではエクスプレッションが決して終了しないため、Maya が応答しなくなってしまいます。
while ループ内の time を 3 以下の値に変更しないかぎり、文は無限に実行されます。
Maya を停止せずに目的の結果を得るには、次のエクスプレッションを使用します。
if (time > 3) Balloon.scaleY = time;
time キーワードの詳細については、「time および frame キーワード」を参照してください。
Cone と Ball というオブジェクトを作成し、while ループを使用して Ball の移動 Y (Translate Y)アトリビュートを Cone の移動 Y アトリビュートにリンクするケースについて考えます。
while (Cone.translateY > 0) Ball.translateY = Cone.translateY;
一見すると、このエクスプレッションでは Cone の移動 Y アトリビュートが 0 より大きい場合は、Ball の移動 Y アトリビュートに Cone の移動 Y アトリビュートが代入されるように思われます。
実際には、Cone の移動 Y アトリビュートが 0 より大きくなるとすぐに Maya が応答しなくなります。このとき、while 条件は true なので、while ループ文 Ball.translateY = Cone.translateY は無限に実行されます。
ユーザ インタフェースでどんな操作をしても、Cone の移動 Y (translateY)アトリビュートは変更されず、同じ位置(0)に留まります。
while ループ内部の Cone.translateY を 0 以下の値に変更しないかぎり、文は無限に実行されます。
Maya を停止せずに目的の結果を得るには、次のエクスプレッションを使用します。
if (Cone.translateY > 0) Ball.translateY = Cone.translateY;
== 演算子を使用して float (浮動小数点)型の変数またはアトリビュートを 0 と比較すると、エクスプレッションが正しく動作しない場合があります。cosd などの組み込み関数が返す値がちょうど 0 であると決めてかかったような場合に、こうした状況がよく発生します。
float $x = cosd(90); if ($x == 0) print("This equals 0.\n"); else print("This doesn't equal 0.\n");
このエクスプレッションを実行すると、次の結果が表示されます。
This doesn't equal 0.
90 度のコサインは数学的には 0 ですが、cosd (90)関数が返す値は 6.123e-17 です。この値は極めて 0 に近いものの、正確には 0 ではありません。通常は 0 と同じとして扱われますが、コンピュータによる浮動小数点数の内部処理では、0 より大きい小数としてコンピュータ内部に格納されます。
この問題を解決するには、次のようなエクスプレッションを使用して値を比較します。
float $x = cosd(90); if (($x > -0.0001) && ($x < 0.0001)) print("This equals 0.\n"); else print("This doesn't equal 0.\n");
このエクスプレッションを実行すると、次の結果が表示されます。
This equals 0.
$x の値が -0.0001 ~ 0.0001 の範囲にあるかどうかをテストすることによって、適切な print 文が実行されるようになります。cosd (90)が返す値は、上記の if 文の数値比較で指定した 0 付近の狭い範囲内にあります。