今回は、ブロックの状態を読み取る方法の練習として、ドアの開閉状態を読み取ってテキストパネルに表示してみます。
基本編
電源のほかに必要なブロックと設定
ブロックの設定 | |
---|---|
ブロック | 備考 |
テキストパネル×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 BlockのInterface 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の条件の中で直接読み取った例
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); }