For ループ

for ループを使用すると、配列またはオブジェクト セットなど、ある範囲の数、時間値、一連の値の集合を繰り返すことができます。

for ループの構文を以下に示します。

for <var_name> [, <index_name>[, <filtered_index_name>]] ( in | = )<sequence> ( do | collect ) <expr>

ここで、<var_name> は、ループ値を保持するループ項目変数の名前です。<sequence> は、ループの値のソースです。

<index_name><filtered_index_name> はループのインデックスを保持するオプションの変数です。<index_name> は、フィルタ式(where)の影響を受けません。また、元の値の位置に対応します。<filtered_index_name> は、フィルタ リスト内の値の位置です。これら 2 つのインデックスの違いについては、以下の例を参照してください。 3ds Max 2021 以降 で使用可能です。<sequence> は、次のいずれかです。

<expr> to <expr> [ by <expr> ] [while <expr>] [where <expr> ]
<expr> [while <expr>] [ where<expr> ]
<expr> to <expr> [ by <expr> ] [where <expr> ]
<expr> [where <expr>]

例:

    for i = 1 to 10 do print i -- sequence numbers
    for item in table1 do x = x + item.height -- sequence an array
    for t in 0f to 100f by 5f do sliderTime=t -- sequence time (given as frames, here)
    bigones = for obj in $box* -- you can sequence pathnames!
    where obj.height > 100 collect obj -- collect the big boxes into an array
    for i,j,k = 12 to 24 where (mod i 3 == 0) do ( -- filter numbers divisible by 3
      format "val:% index:% filtered index:%\n" i j k
    )
    --> produces this output:
    val:12 index:1 filtered index:1
    val:15 index:4 filtered index:2
    val:18 index:7 filtered index:3
    val:21 index:10 filtered index:4
    val:24 index:13 filtered index:5

最初の <sequence> 形式は従来の数ループ、最初の <expr> 値は開始値、to <expr> 値は制限値、オプションの by <expr> 値はループ値の増分です。使用できる値のタイプは整数浮動小数点、および時間です。by の値が指定されない場合、既定値は 1 になります。

<sequence> の 2 つ目の形式は、配列または ObjectSet などの順序付けできるコレクションであり、すべての値を繰り返し、コレクションの連続要素をループ値に代入します。MAXScript には、PathName 値、現在の選択セット、子ノード、オブジェクト上のモディファイヤのスタックなど、シーケンス コレクションがいくつかあります。for ループ内でコレクションを使用する場合の注意事項については、「コレクション」を参照してください。

オプションの while <expr> テストが指定されている場合、このテストで false と評価されたら for ループは終了します。while テスト式は、ブール値(true/false)に評価されます。

パフォーマンスに関する警告

exit 構文を使用したループの脱出が try/catch によって内部的に実装されていますが、これは非常に低速です。

したがって、パフォーマンス上の理由から、exit の使用よりも while テストの使用が推奨されます。while 式は where 式より前に評価されます。

例:

    function findByClass _obj _className =
    (
    local notFound = true
    local res = 0
    local searchName = _className as name
    for i = 1 to _obj.NumBakeElements() while notFound do
    (
    local myElement = _obj.GetBakeElement i
    if myElement.enabled do
    (
    local eleName = (classof myElement as string) as name
    if eleName == searchName do
    (
    res = i
    notFound = false
    )
    )
    )
    return res
    )

<sequence> ソース形式は、true または false に評価されるオプションの where <expr> を受け取ります。where 式は各ループの最初で評価され、where 式の値が true の場合にのみループ本体が実行されます。

do <expr> 形式は、ソース内の値ごとに 1 回だけ本体式を評価します。ループ変数は、あたかもローカルで宣言され、毎回連続したループ値で初期化されているかのように見えます。do <expr> 形式での for ループが式として使用された場合、その戻り値は常に OK です。

collect <expr> 形式は、ループ反復から式の値を収集してその値を配列内に格納し、for ループの結果として配列を生成します。これは、シーンからオブジェクトの一連の選択を収集するのに便利です。where 式を collect 形式の for ループとともに使用すると、where 式が、true になる値だけが収集されます。これは、フィルタ処理した反復値のサブセットを収集する場合に使用できます。また、for ループでの別のコレクションのフィルタ処理として、where 式を使わずに dontCollect を使用してコレクションに特定の値を追加しないようにすることもできます。

変数のスコープ」で解説されているように、for ループは新しいスコープのコンテキストを作成します。for ループのインデックス変数のスコープは、同じ名前の変数が既に存在する場合でも、常に for ループの範囲内にあります。for ループが終了すると、for ループのインデックス変数にアクセスできなくなります。for ループ内で作成された変数のスコープは、常に for ループの範囲内に存在します。 以下に例を示します。

例:

    obj=box()
    avg_pos=[0,0,0]
    offset_pos=[100,100,0]
    -- new for loop index variable obj created even though
    -- a variable named obj already exists, scope is for loop
    for obj in $* do
    (
    -- new variable pos created, scope is for
    -- loop offset_pos already exists outside
    -- for loop, its value will be used
    pos=obj.pos-offset_pos
    -- avg_pos already exists outside for loop,
    -- its value will be used for loop index since variable
    -- obj goes out of scope
    avg_pos += pos
    )
    avg_pos /= $*.count