forループ。このループ命令は{}コードの中を決められた回数繰り返すことができる。この命令は2つの構文で動かすことが出来る。2つの構文はよく似ているが、処理速度に違いがある。100000回繰り返してみたが、片方のループは2.5倍早く完了した。
1 | for "_i" from 5 to 93 step 7 do {hint str _i}; //96を表示 |
1 | for "_i" from 0 to 1 step 0 do {}; //無限にループする |
1 | for [{_i=5},{_i<=93},{_i=_i+7}] do {hint str _i}; //89を表示 |
1 2 3 | _i = 101; for [{ private "_i" ; _i=5},{_i<=93},{_i=_i+7}] do {}; hint str _i; //101を表示 |
1 2 3 4 5 6 7 8 9 10 11 12 | k = 3; a = {k = k + 0.5; k}; for [{_i=0},{_i<(call a)},{_i=_i+1}] do { diag_log format [ "_i:%1/k:%2" , _i, k]; }; //.rpt出力結果 //"_i:0/k:3.5" //"_i:1/k:4" //"_i:2/k:4.5" //"_i:3/k:5" //"_i:4/k:5.5" //"_i:5/k:6" //"_i:6/k:6.5" |
1 | for [{_i=0},{ true },{_i=_i+1}] do {}; //無限回のループ |
1 2 | _i=5; while {_i<=93} do {hint str _i; _i=_i+7}; //89を表示 _i=5; while {_i<=93} do {_i=_i+7}; hint str _i; //96を表示 |
1 | i=0; while { true } do {i=i+1}; hint str i; //10000を表示 |
1 2 3 4 | spawn { while { true } do {}} //常に無限 call { while { true } do {}} //FSM・イベントハンドラ・initから実行の時10000 call { while { true } do {}} //init.sqf・execVMで実行された時無限 spawn {call { while { true } do {}}} //常に無限 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //イイネ _veh addEventHandler [ "GetIn" ,{_this call isIn}]; _veh addEventHandler [ "GetOut" ,{_this call isOut}]; //控えめに言ってクソ lastVehicle = objNull; lastSeat = "" ; null = [] spawn { private [ "_veh" , "_roles" , "_seat" ]; while { true } do { _veh = vehicle player; if (_veh != player) then { _roles = assignedVehicleRole player; _seat = if (count _roles > 0) then [{_roles select 0},{ "" }]; if (_veh != lastVehicle || _seat != lastSeat) then { lastVehicle = _veh; lastSeat = _seat; [_veh, _seat, player] call isIn; }; } else { if (!isNull lastVehicle) then { [lastVehicle, lastSeat, player] call isOut; }; }; sleep 0.1; }; }; |
forEachループ。これは以前軽く紹介したので、今回は短めに紹介しよう。このループは渡された配列一つひとつに従いループし、値が無くなったら終了する。ループ中に配列の内容を足したり引いたりしてもループ回数には何の影響も与えない。
1 2 3 4 5 6 7 8 9 10 11 12 13 | _array = [1,2,3]; diag_log format [ "_array:%1" , _array]; { _array = _array + [0]; diag_log format [ "_x:%1/_forEachIndex:%2/_array:%3" , _x, _forEachIndex, _array]; } forEach _array; diag_log format [ "_array:%1" , _array]; //.rpt出力結果 //"_array:[1,2,3]" //"_x:1/_forEachIndex:0/_array:[1,2,3,0]" //"_x:2/_forEachIndex:1/_array:[1,2,3,0,0]" //"_x:3/_forEachIndex:2/_array:[1,2,3,0,0,0]" //"_array:[1,2,3,0,0,0]" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | _array = [1,2,3]; diag_log format [ "_array:%1" , _array]; { _array set [(count _array) min 5, 0]; diag_log format [ "_x:%1/_forEachIndex:%2/_array:%3" , _x, _forEachIndex, _array]; } forEach _array; diag_log format [ "_array:%1" , _array]; //.rpt出力結果 //"_array:[1,2,3]" //"_x:1/_forEachIndex:0/_array:[1,2,3,0]" //"_x:2/_forEachIndex:1/_array:[1,2,3,0,0]" //"_x:3/_forEachIndex:2/_array:[1,2,3,0,0,0]" //"_x:0/_forEachIndex:3/_array:[1,2,3,0,0,0]" //"_x:0/_forEachIndex:4/_array:[1,2,3,0,0,0]" //"_x:0/_forEachIndex:5/_array:[1,2,3,0,0,0]" //"_array:[1,2,3,0,0,0]" |
おっと、onEachFrameループを忘れるところだった。これは与えられたスクリプトを毎フレーム繰り返す無限ループだ。例えばフレームレートなどを表示するときなどに便利で、例えばwhile {true}とsleep 0.01ループでGUIのスクリプトを回すとき、1秒に100回HUDを更新することになり、60FPSの時に少し無駄(訳注:1秒につき40回分の処理が無駄)が発生する。こういう時はonEachFrameが適切だ。
1 2 | onEachFrame {hint str diag_fps}; onEachFrame {hint str diag_tickTime}; |
1 2 3 4 5 6 7 8 9 10 11 12 13 | _i = "123" ; onEachFrame { hint str (isNil "_i" ); //"true"を表示し続ける }; cutText [str _i, "PLAN DOWN" ]; //(onEachFrameで)処理がストップすることなく"123"を表示する onEachFrame {hint "1" ; sleep 1; hint "2" }; //.rptはエラーを吐き続ける i = 0; onEachFrame { i = i + 1; hint str i; //0からカウントアップし続ける }; i = 0; //0に再設定 onEachFrame {}; //ループを停止 |
Enjoy,
KK
KK's blog – ArmA Scripting Tutorials: Loops by Killzone Kid
Translated by POLPOX
Translated by POLPOX
補足
while {true}ループ周りの話なんですけど、ごちゃごちゃしてるし私自身もあまり理解していないので、こういう概念が存在することを理解していただければ幸い。あのあたりを深く見ていくと、callだのspawnだのscheduledだのnon-scheduledだのという言葉が出てきてチンプンカンプンなので実体験をもとに書くわけですけど、とりあえず次の図を見てください。
黒の流れにおいて、遅延は一切許されず、スクリプトの処理を待つ列でギチギチに詰まっています。これをnon-scheduledと呼びます。
赤の回り道を回るcallは、この流れの中にあります。
青の道はspawnで分岐した処理を表しています。これは流れの中にはなく、自由に実行されます。これをscheduledと呼び、黒の流れとspawnは同時に処理され(?)、右に進んでいきます。
あ、scheduledだのは覚えなくていいです。
さて、この中でwhileに10000回の制限がかけられているものはどれでしょう。答えは黒と赤の流れです。
理由は、無限ループに入るとその後の処理が全く行えなくなるため(=クラッシュ)です。
そのための制限なんですね。
以上を踏まえて、以下のスクリプトを順にDebug Consoleで実行してみて、その処理の違いをよく観察してみてください。
1 | [] call {i = 0 ; while { true } do {i = i + 1 ; hint str i ;}} |
1 | [] spawn {i = 0 ; while { true } do {i = i + 1 ; hint str i ;}} |
ちなみに、sleepが使えるのは青の道だけです。
0 件のコメント :
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。