サンプルプログラム/ドアの状態をチェックする

Last-modified: 2017-01-19 (木) 19:17:02

今回は、ブロックの状態を読み取る方法の練習として、ドアの開閉状態を読み取ってテキストパネルに表示してみます。


基本編

電源のほかに必要なブロックと設定

ブロックの設定
ブロック備考
テキストパネル×1名前は「Text panel Out」
Show text on screenをオンにしておく
プログラマブルブロック×1このスクリプトを保存しておく
ボタンパネル×1設定は後で説明
ドア×2~4別々の名前を付けておく

スクリプトの完成形

先に全体像を提示しておきます。

public void Main(string argument) {
   var targetDoor = GridTerminalSystem.GetBlockWithName(argument) as IMyDoor;
   bool doorOpen = targetDoor.Open;
   string statusText = doorOpen.ToString();
   var targetPanel = GridTerminalSystem.GetBlockWithName("Text panel Out") as IMyTextPanel;
   targetPanel.WritePublicText(argument + " : " + statusText, false);
}

処理の流れ

public void Main(string argument) {
    // ドアを取得する
    // ドアの状態を読み取る
    // 取得したドアの状態を文字列にする
    // テキストパネルを取得する
    // テキストパネルに書き込む
}

第1段階:ドアの情報を読み取る

ドアを取得して変数に入れる

var 変数名 = GridTerminalSystem.GetBlockWithName(ブロック名) as インターフェースネーム;

var targetDoor = GridTerminalSystem.GetBlockWithName(argument) as IMyDoor;

これまでのサンプルでやってきたことと同じです。hello, worldで少し触れた短い書き方を使用しています。

変数の名前は対象にするドアということでtargetDoorにしました。

ブロックの名前は「文字が流れるテキストパネル」と全く同様に、argument欄から取っています。


インターフェースネームは公式ガイドから探します。「Door」の「Interface name」を探すと「IMyDoor」とあるのでこれを設定します。

ドアの開閉状態を読み取って変数に入れる

変数の型 変数の名前 = 対象.フィールド名;

bool doorOpen = targetDoor.Open;

ブロックを入れた変数の後ろにピリオド「.」を挟んでフィールド名を書くことで、該当する情報を得ることができ、変数に入れるなどの処理を行えます。これを利用し、開閉状態を読み取って変数に保存します。

ブロックからどんなフィールドを読み取れるのかは、公式ガイドから探します。

今回はドアが開いているかどうかを調べたいので、「Door」の「Fields」を探すと、「bool型のOpen」が見つかります。

名前の羅列しかないので実際に試さないと「開いているかどうかを指すのは多分これ」としか分かりませんが、Openであっているのでこれを使います。

bool型は、booleanや真偽値などとも呼ばれ、true(真)とfalse(偽)の二種類の状態だけがある、「フラグが立っているかどうか」というイメージそのものデータ型です。

この結果を入れるために、同じbool型の変数doorOpenを作り、読み取った結果を入れています。

ドアが持つOpenというフィールドを読み取った結果は、開いていればtrue、閉まっていればfalseになります。

第2段階:取得した状態を文字列にする

変数の型 変数の名前 = 内容;

string 変数の名前 = doorOpenの中身を文字列に変換;

string statusText = doorOpen.ToString();

結果を書き込み用の文字列にするために、左辺ではいつものように、statusTextという名前でstring(文字列)型の変数を作ります。


右辺では、ToStringメソッドというC#の処理を使って、trueまたはfalseというbool型の「状態」から、単なる文字列に変換した結果を得ています。その結果を「=」で変数statusTextに入れました。

第3段階:テキストパネルに書き込む処理

パネルを取得して変数に入れる

var 変数名 = GridTerminalSystem.GetBlockWithName(ブロック名) as インターフェースネーム;

var targetPanel = GridTerminalSystem.GetBlockWithName("Text panel Out") as IMyTextPanel;

hello, worldと同様です。

「Text panel Out」という名前のパネルをtargetPanelと名付けた変数に入れます。

パネルに書き込む

対象.WritePublicText(書き込む文字列, 追記するか);

targetPanel.WritePublicText(argument + " : " + statusText, false);

書き込みについてはこれまで通りです。

ボタンごとに違う文字列を表示するで触れた、文字列を繋ぐ方法で、argumentに入っているドアの名前と、直接書いた空白とコロン、さきほど用意したドアの状態の文字列を繋いで「ドアの名前 : ドアの状態」という形式の文をつくり、追記せずに上書きしています。

ブロックの設定と実行

プログラマブルブロックの準備が終わったら、ボタンパネルの設定を行います。


各ボタンのアクションに、プログラマブルブロックの「Run」をドラッグ&ドロップし、表示されたargumentダイアログに状態を調べたいドアの名前を入力します。


調べたいドアを設定したボタンを押すと、そのボタンに設定したドアの名前と共に、開いていればtrue、閉じていればfalseが表示されます。


応用として、タイマーブロックを使って文字が流れるテキストパネルのように1つのドアを対象に繰り返し実行し場合、1秒ごとに開いているかどうかを監視するような使い方が可能です。

応用編1:状態を元に、条件分岐を使ってわかりやすい形式に変える

「true」と「false」ではわかりにくいですから、条件を満たしているときだけ処理を行う方法で、「Open」と「Close」という具体的な内容を書くようにしてみます。

スクリプトの完成形

public void Main(string argument) {
   var targetDoor = GridTerminalSystem.GetBlockWithName(argument) as IMyDoor;
   bool doorOpen = targetDoor.Open;
   string statusText = "Close";
   if(doorOpen) {
       statusText = "Open";
   }
   var targetPanel = GridTerminalSystem.GetBlockWithName("Text panel Out") as IMyTextPanel;
   targetPanel.WritePublicText(argument + " : " + statusText, false);
}

1:変数を作る部分の変更

string statusText = doorOpen.ToString();

変数の型 変数の名前 = 変数の内容;

string statusText = "Close";

今回は、後で「開いていればOpenに書き換える」処理を入れるので、最初は閉まっている前提で「Close」を直接入れておきます。

仮にここまでの変更で動かせば、状態に関係なくCloseと表示されることになります。

2:条件分岐

分岐させる

if(条件) {
    // 条件に合う時に実行される
}

if(doorOpen) {
    // 条件に合う時に実行される
}

if文は、括弧()の中の内容を処理した結果がtrue(真)、つまり条件が満たされている時だけ、波括弧{}の中の処理を実行し、false(偽)なら波括弧{}の中身を無視して後に進みます。


今回の場合、内容がそのままtrueかfalseであるbool型の変数doorOpenを入れているので、doorOpenの中身がtrueの場合に、波括弧{}内の処理が行われます。

分岐した先の処理を書く

変数名 = 新しい内容;

statusText = "Open";

if文の中の処理を作ります。今回の場合は変数doorOpenがtrue、つまり対象のドアが開いているときだけ行われる処理です。

先ほど作って内容を「Close」にしてあった変数statusTextの内容を、「Open」に書き換えています。

実行

必要な設定は同じなので、そのまま保存して実行すれば動作します。

そのボタンに設定したドアの名前と共に、開いていればopen、閉じていればcloseと表示されます。

応用編2:ドア以外のブロックでフィールド読み取りを試してみる

他の用途に変更する練習として、タイマーに設定されている秒数を読み取って表示するように、基本解説のスクリプトを改造してみましょう。

スクリプトの完成形

先に全体像を提示します。

public void Main(string argument) {
   var targetTimer = GridTerminalSystem.GetBlockWithName(argument) as IMyTimerBlock;
   float time = targetTimer.TriggerDelay;
   string statusText = time.ToString();
   var targetPanel = GridTerminalSystem.GetBlockWithName("Text panel Out") as IMyTextPanel;
   targetPanel.WritePublicText(argument + " : " + statusText, false);
}

1:タイマーを取得して変数に入れる

var 変数名 = GridTerminalSystem.GetBlockWithName(ブロック名) as インターフェースネーム;

var targetTimer = GridTerminalSystem.GetBlockWithName(argument) as IMyTimerBlock;

やること自体は全く同じです。

今回はタイマーが対象なので、公式ガイドからTimer BlockInterface nameを探すと「IMyTimerBlock」とあるのでこれを設定します。

2:設定時間を読み取って変数に入れる

変数の型 変数の名前 = 対象.フィールド名;

float time = targetTimer.TriggerDelay;

公式ガイドから「Timer Block」の「Fields」を探すと、

  • bool型のIsCountingDown
  • float型のTriggerDelay

という2つが見つかります。

やはり名前から察して試すしかないのですが、省略して結論から言えば、IsCountingDownはカウントダウンをしている最中かどうか、TriggerDelayが秒数なので、これを利用します。

float型は、小数点以下がある数に対応したデータ型です。

タイマーのカウントダウンはゲーム内では整数なので疑問に思うかもしれませんが、ブロックの数値項目の殆どが裏ではfloat型で扱われています。

この結果を入れるために、同じfloat型の変数timeを作り、読み取った結果を入れています。

3:取得した状態を文字列にする

変数の型 変数の名前 = 内容;

string 変数の名前 = timeの中身を文字列に変換;

string statusText = time.ToString();

これは基本編で行ったものと全く同様で、元データの変数の名前を新しくしたのに合わせて変更しただけです。

同様に、string(文字列)型の変数statusTextを作った際に、変数timeの内容を文字列に変換した結果をその場で入れています。

実行

ボタンパネルに、プログラマブルブロックのRunを、調べたいタイマーブロックの名前をargumentにして設定してください。

実行すると押したボタンに対応したタイマーブロックが何秒に設定されているかが表示されます。

まとめ

今回はブロックのフィールドを読み取る方法を解説しました。

おまけ

フィールドの読み取り結果を変数に入れず、ifの条件の中で直接読み取った例

フィールドの読み取り結果を変数に入れず、ifの条件の中で直接読み取った例

public void Main(string argument) {
   var targetDoor = GridTerminalSystem.GetBlockWithName(argument) as IMyDoor;
   string statusText = "Close";
   if(targetDoor.Open) {
       statusText = "Open";
   }
   var targetPanel = GridTerminalSystem.GetBlockWithName("Text panel Out") as IMyTextPanel;
   targetPanel.WritePublicText(argument + " : " + statusText, false);
}

?: 演算子を使ってもっと省略した例

?: 演算子を使ってもっと省略した例

public void Main(string argument) {
   var targetDoor = GridTerminalSystem.GetBlockWithName(argument) as IMyDoor;
   string statusText = targetDoor.Open ? "Open" : "Close" ;
   var targetPanel = GridTerminalSystem.GetBlockWithName("Text panel Out") as IMyTextPanel;
   targetPanel.WritePublicText(argument + " : " + statusText, false);
}

コメント