Minecraftとタートルと僕

PCゲームMinecraftのMOD「ComputerCraft」の情報を集めたニッチなブログです。

sleep実装からイベントを学ぶ(8)-インタラクティブなプログラムを作る

はじめに

さて、イベントに関する連載もそろそろ大詰めです。
これまで学んだ内容をフルに使って、いろいろと操作ができる、インタラクティブなプログラムを作ってみましょう。

これまで紹介したプログラムは、ターミナル画面上でマウスをクリックしたり、キーボード入力をすることで操作を行いました。具体的には、キーボードでキャラクタ「@」を動かしたり、メニューを選択したりするプログラムを紹介しました。

でも、これらプログラムを使っているうちに思いませんでした?
「毎回、右クリックしてターミナル画面を呼び出すのがめんどくさいんですけど!!
それにターミナル画面は小さいので、外部モニタにもっと大きく表示したい!!」

そこで今回は、次のようなプログラムを紹介したいと思います。

プログラムの紹介

まず、次のようにコンピュータとモニタを設置してください。
金色のAdvancedではなく、普通のコンピュータ・モニタでも問題ありません。
金色のAdvanced Monitorを使ってください。普通のモニターではダメです。

f:id:hevohevo:20140105185823p:plain:w450

コンピュータに対して、上(top)と下(bottom)と右(right)にモニターが隣接していることが重要です。右側のモニタはここまで大きくしなくても大丈夫。

そして、次のプログラムを打ち込んで実行してみましょう。

プログラムを実行したら、3つのモニタ、どれでも良いので「右クリック」してください。
次のように右側の大きなモニタに文字が表示されたら成功です。

f:id:hevohevo:20140105191110p:plain:w450

ちょっと見づらいですが、この図では、右のモニタに「monitor_touch / right / (22, 15)」と表示されています。この「right」の部分ですが、下のモニタを右クリックすると「bottom」と表示されますし、上のモニタだと「top」と表示されます。

何をするプログラムかもうわかりましたね。

「モニタを右クリックして発生する"monitor_touch"イベントを拾い、その内容を表示するプログラム」です。

プログラムの解説

  • L9 「local event, side, x, y = os.pullEvent("monitor_touch")」

この部分がこのプログラムの最重要ポイントです。
"monitor_touch"イベントだけをos.pullEvent()で拾っています。

このイベントは、次のような特徴を持っています。

monitor_touchイベント

  • 外部モニタを右クリックすると発生
  • 第1返値(プログラム中では変数eventに代入): "monitor_touch"
  • 第2返値(同、side): どの方向にあるモニタか("right"、"top"など)
  • 第3返値(同、x): モニタのどの位置をクリックしたか。そのX座標(数値)
  • 第4返値(同、y): モニタのどの位置をクリックしたか。そのY座標(数値)

つまり、隣接しているどのモニタをクリックしたかだけではなく、そのモニタのどの位置をクリックしたかも返してくれる、とても親切なイベントが発生するのです。

【補足】string.format()について

もうひとつこのプログラムのポイントが、L14にあるstring.format()関数です。

string.format("%s / %s / (%d, %d)", event, side, x, y)

string.format()関数を使って文字列を作成し、それを右側のモニタに書き込んでいます。

この関数ですが、他のプログラム言語をかじったことがある人なら誰でも知っている有名な関数ですね。
使い方は、Luaリファレンスを見てください。
……え? プログラミング初心者にはこのリファレンス読んでもわからないって?
ええ。僕もこれを読みましたが、C言語(やJava言語)などのstring.format()関数の知識があること前提に書いてますね。 初心者を完全に無視w ひどいw*1

この関数はとても高機能なので、使い方を全て説明するとひどく長くなります。ここでは、今回のプログラムでどのように使っているかということだけ簡単に説明しましょう。
「そんなの知っているよ!」という人は、次の大見出しまで、読み飛ばし推奨です。


string.format()はぶっちゃけて言うと、「複数の変数(の値)を埋め込みつつ文字列を作成する関数」です*2
string.format(第1引数, 第2引数以降はいくつでもOK) というふうに解読してください。
第1引数は、Format文字列です。表示したい文字列とその中のどの位置に変数を埋め込むのかという指示を記述した、テンプレート文字列になります。
そして2番目以降の引数として、そのテンプレートの中で使う変数を、埋め込む順番に、ダラダラと並べていきます。

テンプレート文字列の中に変数を埋め込むために、その位置に書式記号を記述します。書式記号はたくさんの種類があるのですが、今回のプログラムでは「%s」と「%d」を使っています。

  • %s: 対応する変数を文字列として読み取り、この位置に埋め込む
  • %d: 対応する変数を数値(整数)として読み取り、この位置に埋め込む

今回のプログラムでは、テンプレート文字列中に計4つの書式記号を使っています。
これはそれぞれstring.format()の第2以降の変数である、第2引数、第3引数、第4引数、第5引数に対応しています。つまり、次のような対応関係です(例:一番目の%sとeventが対応)。

"%s / %s / (%d, %d)"
 ^    ^     ^   ^
event side  x   y

このように指定することで、

monitor_touch / right / (10, 10)

のような表示を可能にしているわけです。
今後はこの関数を説明なしで多用するのでご注意ください。

話を戻して、"monitor_touch"イベントをどう使うのか

相変わらず補足が長いですが、話を戻します。

"monitor_touch"イベントを使うことで、外部モニタの方向のみならずクリックした位置(座標)まで詳細にわかるので、出力装置であるモニタをまるで入力装置のように取り扱うことができます。
つまり、モニタがプログラムのコントローラーになるわけですね。

例としてどのようなプログラムを紹介するか悩んだのですが、応用範囲の広さを考えて次のようなプログラムを取り上げることにしました。

予定1「モニタボタンによる画面表示操作」プログラム
  • コンピュータに隣接した巨大モニタを表示専用モニタとする。
    • 表示専用モニタの中央にキャラクタ「@」を表示する。
    • また同時にモニタの一番上に、どのような操作をしたかという情報も表示する。
  • コンピュータに隣接したもうひとつの(小さな)モニタをコントロール用モニタとする。
    • コントロール用モニタの表示領域を縦2×横3に6分割し、縦2×横3の計6個のボタンを作成する(もちろん物理的に分割するのではなく、プログラム内で計算*3して表示エリアを仮想的に6分割する)。
    • また、表示されたボタンを右クリックすることで、表示専用モニタに表示されているキャラクタ「@」を上下左右に自由に動かしたり、キャラを初期位置に戻したり(リセット)、プログラムそのものを終了(exit)したり、さまざまな操作ができる。
予定2「モニタボタンによるタートル操作」プログラム
  • タートルの上にAdovanced Monitor(金色モニタ)を設置
    • モニタは6つのボタンを表示し、ボタンを押すことで真下にあるタートルを操作できる
    • 右回転、左回転、正面に向かってturtle.dig()、インベントリの選択スロットを変更、正面に向かってturtle.place()などを可能に。
    • タートルがモニタから離れると操作ができなくなるので、turtle.forward()などは実装しない
  • このプログラムの発展系として、ワイヤレス通信(rednet API)を使った遠隔操作などが考えられます。つまりはラジコンプログラムです!!
    • この場合ボタン6つでは足りないかもしれませんね。
    • ワイヤレス通信についても解説しないと・・・・・・。

このようなプログラムを次回以降、紹介しようと思います。

それではお楽しみに。

*1:しかも、CCのLuaって一般的なstring.formatの機能のうち、一部の重要な機能が実装されていないのですよ。ひどい、ひどすぎる。せめて小数の有効数字指定くらいは実装してくださいよ。ほんとたのみます(泣)

*2:もっと正確に言うならば、変数を「加工した上で」埋め込むのですが、このあたりを詳しく説明するといくらスペースがあっても足りません。詳しくは「string.format」というキーワードでググるなりして、自分で調べてください。ぶっちゃけ私も、機能がありすぎて一部の機能しか使いこなせていません。

*3:いま、この計算部分をデバッグ中だけどメンドクサイよ!!!