複数のブロックに一括してアクションを行うプログラムを解説します。
このページの内容は、複数のドアを開閉するの繰り返し処理をforeachに変更するなど簡素化したものです。
サンプルプログラム
まずはワールドの詳細設定のIn-game scriptsがオンのワールドに、電力が供給されているステーションやラージシップを用意し、Programmable Blockといくつかのドアを設置しましょう。
ブロックAでブロックBを操作する際は、ブロックAが、Bを操作して良い立場である必要があります。今回の場合はプログラマブルブロックとドアのOwner(所有権者)が「Nobody」か「Me」でどちらのブロックも同じになっていればとりあえずOKです。
サンプルプログラムの完成形
Programmable Blockのエディタを開いて、以下のプログラムを貼り付けてください。
public void Main(string argument){ var targets = new List<IMyDoor>(); GridTerminalSystem.GetBlocksOfType(targets);
foreach(var obj in targets){ obj.ApplyAction("Open"); } }
このプログラムをRun(実行)すると、その船にある全てのドアの開閉が切り替わります。
基本編解説
上記は「Interface nameがIMyDoorのブロックを全て取得し、取得したブロックすべてにOpenというアクションを行う」プログラムです。以下で各部について解説します。
2行目:ブロックを入れるリストを作る
var リストの名前 = new List<インターフェースネーム>();
↓
var targets = new List<IMyDoor>();
まずは2行目。ブロックを入れるリストを任意の名前で作ります。今回はリストの名前を「targets」としました。
「new List<>()」の山括弧<>の間に、Interface name(ブロック名とは別の、プログラムで扱うための名前)を書くことで、リストに入れられるブロックの種類を指定します。
今回扱いたいのはドアなので、公式ガイドからDoorのInterface nameを探すと、「IMyDoor」とあるのでこれを設定しました。
ガイドが掲載された当時はなかったSliding DoorやAirtight Hangar DoorもIMyDoorの対象に含まれているので、同じスクリプトで動いてしまいます。
3行目:ブロックをリストに追加する
探す対象範囲.GetBlocksOfType(リストの名前);
↓
GridTerminalSystem.GetBlocksOfType(targets);
GetBlocksOfTypeは、ピリオドの左側で指定した対象から、括弧()内で指定したリストに、その船にあり、リストに入れることが可能な種類のブロックを追加します。
ブロックを探す対象は、その船のブロック全体を指す「GridTerminalSystem」にします。
入れる先のリストには、先ほど用意したtargetsを指定しました。
先ほどのリストはドア類だけが入るので、船にあるドア類がリストに入ります。
5~7行目:リストに入れた全てのブロックにアクションを実行させる
5行目と7行目:繰り返し処理
foreach(var 取り出した項目 in リストの名前){ // 繰り返す処理 }
↓
foreach(var obj in targets){ // 繰り返す処理 }
5行目から7行目。リストの中のブロックすべてに同じ操作を行うため、foreach文を使います。
foreach文は、inの右で指定したリスト内のブロックを一つずつ取り出して左側の変数に入れ、そのたびに波括弧{}の中の処理を1回行うことを、リストが終わるまで繰り返します。
リストの項目をその周の間だけ入れる変数の名前はリスト名とおなじく任意で構いません。今回はオブジェクトの略で「obj」としました。
括弧()内のinから後には、操作対象の変数に何を入れるかを書くので、先ほど用意した「targets」リストを指定しました。
6行目:ブロックのアクション
操作対象.ApplyAction(アクション名);
↓
obj.ApplyAction("Open");
6行目が実際に操作する内容の部分です。
ApplyActionは、括弧()内にアクション名を入れることで、対象のブロック1つにそのアクションを行わせます。
上記では、foreach文によって今取り出されている項目である「obj」を扱う対象として設定しました。
次にアクションの内容です。公式ガイドからDoorのActionsを探すと、
「Openというアクション名が、ターミナルやツールバーでのOpen/Closedを指す」ことがわかります。なので、括弧内には「"Open"」と入力しました。
ちなみに、ガイドのとおり開けるだけは"Open_On"、閉じるだけは"Open_Off"です。実用的にはこれらのほうが使用機会が多いと思います。
引用符の有無についてですが、初心者はとりあえず「ApplyAction()の括弧内にアクションの名前を直接書くときは""で囲う」とだけ把握しておきましょう。
基本の解説は以上です。
応用編:特定の名前を持つドアだけを開閉する
foreach文の中で条件を指定して、特定の名前を持つドアだけが開閉するようにしてみましょう。
先にターミナルメニューでいくつかのドアの名前を変更し、名前の適当な部分に「Alpha」と入れておきましょう(例:「Door 2 Alpha」)。
先ほどのプログラムから6行目の
obj.ApplyAction("Open");
を削除して代わりに次のように書きます。
string name = obj.CustomName; if (name.Contains("Alpha")){ obj.ApplyAction("Open"); }
if文は括弧()の中の条件が満たされている(true)場合に波括弧{}の内容を実行します。
今回は、foreach文の中でまず今扱っているブロック名を読み取っておき、その中に「Alpha」という文字列が含まれていれば開閉を実行し、そうでなければ無視するプログラムになります。
応用編のスクリプトの完成形
上記の変更を行った結果は以下のようになります。
public void Main(string argument){ var targets = new List<IMyDoor> (); GridTerminalSystem.GetBlocksOfType(targets);
foreach(var obj in targets){ string name = obj.CustomName; if (name.Contains("Alpha")){ obj.ApplyAction("Open"); } } }
応用編の解説
変更結果の1行目:ブロック名の読み取り
string 変数の名前 = 対象.CustomName;
↓
string name = obj.CustomName;
ブロックの名前を入れる場所として、今回は「name」という名前でstring(文字列)型の変数を作りました。
.CustomNameは前に付けた対象となるブロックのCustomName、つまりターミナルメニューで設定できるブロックの名前を読み取る機能なので、先ほどと同様に現在扱っているブロック(obj)を指定し、そのCustomNameをname変数の中身として設定しています。
変更結果の2行目:if文の条件
if (比較対象となる文字列.Contains("文字列")){
↓
if (name.Contains("Alpha")){
.Contains()は、ピリオドの前に繋いだ文字列の中に、()内の文字列が含まれていればtrueになります。
今回は、先ほどブロックの名前を書き込んだ「name」変数を前に置き、比較用の文字列は「Alpha」としました。
この場合なら、「name変数の中身」に「Alpha」が含まれているかどうかを判定します。
ここも「任意の文字列を直接書くときは二重引用符""が要る」とだけ把握して追々知っていけば良いでしょう。
おまけ
if (obj.CustomName.Contains("Alpha")){
文字列をArgument欄から読ませた例
void Main(string argument){ var targets = new List<IMyDoor> (); GridTerminalSystem.GetBlocksOfType(targets);
foreach(var obj in targets){ string name = obj.CustomName; if (name.Contains(argument)){ obj.ApplyAction("Open"); } } }
public void Main(string argument){ List<IMyDoor> targets = new List<IMyDoor> (); GridTerminalSystem.GetBlocksOfType(targets);
foreach(IMyDoor obj in targets){ obj.ApplyAction("Open"); } }