print と format を使用するより MAXScript デバッガが優れている点は、ブレークしたときに、ローカル変数、呼び出しツリーの変数 (それぞれのスタック フレーム)、グローバル変数を確認できることです。このうちのいずれかを使用してあるスコープに入ると、そのスコープの変数にアクセスできます。
たとえば、スクリプト プラグインのイベント ハンドラでブレークするとします。通常の場合は、スクリプト プラグインのローカル変数やパラメータを確認できません。デバッガを使用すると、ローカル変数やパラメータを確認できるだけではなく、値を変更してから実行を続けることもできます。
何らかの MAXScript エラーが発生し、エラー トレースバックで出力される値を調べただけでは問題を把握することはできませんが、もう少し掘り下げて他の変数を調べれば、問題を正確に把握できるようになります(そのため、十分な情報を得られることを期待して、print ステートメントや format ステートメントを追加します)。
3ds Max はマルチスレッドであり、ブレークポイントでは複数のスクリプトがさまざまなスレッドで動作していることがあります。レンダリング中にスクリプト プラグインかコントローラでブレークすると、一般的にこのような状態になります。この場合のブレークポイントや例外では、ブレークポイントや例外が発生したスレッドがデバッガの既定値になります。ただし、[ブレーク] (Break)ボタンをクリックしてブレークした場合は、メイン スレッドが既定値になります。別のスレッドで何が実行されているかを確認することもできます。
スクリプトを実行して関数を呼び出すと、それぞれの関数呼び出しによって独自のスタック フレームが作成されます。スタック フレームには、その関数呼び出しに関連したローカル変数が含まれます。それぞれのスタック フレームでは、次の変数が表示されます。
Parameters - 関数の引数
Locals - ローカル変数
Externals - 関数で使用されるローカル以外の変数
Owner - メソッドの所有者の Parameters/Locals/Externals
例:
以下を実行した場合の例:
v = 0 r = 0 ( local pi = 3 for i = 1 to 1000000 do (ss = random e pi; v += ss; v += r; if i == 999999 do throw "A") )
[ブレーク] (Break)をクリックすると、以下が出力されます。
# ** thread data: threadID:3364 ** ------------------------------------------------------ ** [stack level: 0] ** In i loop; filename: C:\Program Files\Autodesk\3ds Max 2010\ui\macroscripts\; position: 94; line: 6 ** member of: anonymous codeblock -- Parameters: -- i: 260174 -- Locals: -- ss: 2.79242 -- i: 260174 -- Externals: -- owner: <CodeBlock:anonymous> -- pi: 3 -- r: Global:r : 0 -- V: Global:V : 744008.0 -- Owner: -- Locals: -- pi: 3 -- Externals: ** ------------------------------------------------------ ** [stack level: 1] ** called from anonymous codeblock; filename: C:\Program Files\Autodesk\3ds Max 2010\ui\macroscripts\; position: 126; line: 6 -- Locals: -- pi: 3 -- Externals: ** ------------------------------------------------------ ** [stack level: 2] ** called from top-level
最初の行ではどのスレッドかがわかります。多くの場合、これは重要ではありません。次にそれぞれの呼び出しのスタック フレームをダンプしながら、関数呼び出しの調査を始めます。このケースでは、関数呼び出しとして内部で処理される for ループの本体、外側括弧の中のコード、for ループを実行するリスナーの 3 レベルがあります。
レベル 0 では、最初に関数名 (i loop)、次にこの関数の所有者が出力されます。このケースでは、外側括弧で定義されるコード ブロックです。このコード ブロックは、名前が付いていないので匿名です。その他のコード ブロックには名前が付きます。
例:
たとえば上のコードをツールバーにドラッグして MacroScript を作成し、MacroScript を実行して[ブレーク] (Break)をクリックすると、最初の数行は次のようになります。
** thread data: threadID:2224 ** [stack level: 0] ** In i loop; filename: C:\3dsmax8\UI\MacroScripts\DragAndDrop-Macro1.mcr; position: 186 ** member of: codeblock macroScript: DragAndDrop_Macro1
次にパラメータが表示されますが、FOR ループの場合は FOR ループ カウンタです。ここに表示される値は、関数に渡された値です。次はローカルです。ss と i の 2 つがあります。変数 i (for ループ カウンタ) に新しい値が割り当てられると、その新しい値が表示されます。次に外部が表示されます。関数内で使用される変数がありますが、ローカル変数ではありません。外側スコープ、グローバル スコープ、その他の外部スコープのうちいずれかで定義されています。owner 変数では、関数の所有者にアクセスできます。たとえば関数がスクリプト プラグイン内にあった場合、所有者はスクリプト プラグイン インスタンスになります。これにより、所有者の変数の取得と設定ができます。
最後に所有者がある場合は、所有者の情報が表示されます。このケースではそれほど重要ではありません。次のスタック レベルで同じものが表示されるからです。しかし一般的にはそうではありません (スクリプト プラグイン、MacroScript、ロールアウトの関数)。
次のスタック レベルでは、関数の呼び出し者の情報、つまり匿名コード ブロックの情報がダンプされます。
変数「pi」の値を変更することを検討してください。変数を変更できるのは、変数にアクセスできる場合に限られます。このケースでは、「owner.pi」を使用して for ループ関数内から「pi」にアクセスできます。
ただし、関数呼び出しをネストしている場合は、その方法で取得することはできません。現在のスタック レベルを目的のレベルに設定して変数を設定する必要があります。
例:
>> setframe 1 ** ok >>locals ** thread data: threadID:2224 ** [stack level: 1] ** In anonymous codeblock -- Locals: -- pi: 3.1 -- Externals: >> setvar pi 3.5 3.5 >> getvar pi 3.5
例外が発生したエラー トレースバックと上記を比較してください。
-- Error occurred in i loop -- Frame: -- ss: 2.99878 -- i: 999999 -- called in anonymous codeblock -- Frame: -- pi: 3 -- Runtime error: A
MAXScript デバッガには[停止] (Stop)ボタンもあります。ブレークを実行した後、[実行] (Run)をクリックすると、コードの実行が継続されます。[停止] (Stop)をクリックすると、スクリプトの実行が停止します。