はじめに
前回のプログラムによって、タートルを遠隔操作できるようになりました。 メッセージ送信プログラムを実行するときに命令文を引数として与えることで、タートルに対して様々な命令ができます。
しかし、致命的な問題点があります。
それは、一つ命令するたびに毎回関数を文字入力しなくてならず、面倒なことです(面倒はプログラマーの天敵です! 見つけ次第駆除しましょう!)。
この対策として、「自由に関数文字列を送信できるのでどんな命令でもできる」というこれまでのプログラムを、 「キーボードの特定のキーと関数文字列をあらかじめ結び付けておいて、キー操作で命令する」というプログラムに改造してみました。
ソースコードの解説は後回しにして、まずは使ってみましょう。
インストール
送信側・・・今回紹介する新しいプログラムです。
> pastebin get TQ8E9W5f msg_sender2
受信側(タートル側)・・・こちらは前回のものをそのまま使います。
(2014/03/16 19:00 pastebinIDのミスを修正)
> pastebin get 564VSbU7 msg_receiver3
- ダウンロードしたら、受信側(タートル側)プログラムを起動し、待ち受け状態にします。
- 送信側プログラムは、
msg_sender2 30
のように、送信先IDを引数にして実行してください。 あとはキー入力でタートルを自在に操作しましょう。あらかじめ燃料を補給しておくのを忘れないでください。
「キー・送信文字列」対応表
Minecraftのクリエイティブモードのキー操作をイメージして調整してあります。
たとえばキーボードの「w」キーを押すと、"turtle.forward()"という文字列をタートルに送信して、タートルは前進します。
キー | 送信文字列 | 備考 |
---|---|---|
w | turtle.forward() | |
a | turtle.turnLeft() turtle.forward() turtle.turnRight() | 左に平行移動 |
s | turtle.back() | |
d | turtle.turnRight() turtle.forward() turtle.turnLeft() | 右に平行移動 |
space | turtle.up() | |
leftShift | turtle.down() | |
right | turtle.turnRight() | カーソルキー(→)右旋回 |
left | turtle.turnLeft() | カーソルキー(←)左旋回 |
メッセージ受信(タートル側)プログラム バージョン3
ソースコード
前回のものをそのまま使います。
メッセージ送信プログラム バージョン2
ソースコード
重要な部分を解説
変換テーブルの利用
前述の「キー・送信文字列の対応表」通りの挙動を実現するには、まず一番簡単な方法として、IF文による条件分岐を延々と繋げていく方法があります。例えば次のように。
if keyname=="w" then -- wを押した時の処理 elseif keyname == "a" then -- aを押した時の処理 elseif keyname == "s" then -- sを押した時の処理 elseif -- 表の全てのキーについて記述。以下、省略 end
しかしこの方法ですと、新しいキーの追加・削除・変更などのメンテナンス性は最悪ですし、何よりプログラム行数が無駄に長くなりがちです。
そこで、変換テーブルによる実装を試みました。この実装方法はハッシュ(key-value)テーブルを持つプログラム言語でよく使われます。
(L11-20)において、「キー名」「送信文字列」のペアを詰め込んだテーブル「trans_tbl」を用意しています。
例えば、trans_tbl["w"]
のように呼び出すと、そのペア値である"turtle.forward()"が返ってきます。
なおLuaのテーブルは、そのような値がないときには、nilを返します(例:定義されていないtrans_tbl["hogehoge"]
の返値はnil)。
keyイベントの利用
(L24)において、os.pullEvent()
関数を使っています。
この関数はComputerCraftのイベントを待ち受ける関数で、イベント名"key"を引数として与えることにより、キー入力検知します。
具体的には、次のような機能です。
- os.pullEvent(イベント名)
- 何らかのイベントが発生するまで待ち、発生したらそのイベント名とともに様々な関連する値を返す。
- 引数1: イベントの種類についてはこちら。省略したときは(ほとんど)全てのイベントに反応する。今回は"key"イベントについてまとめる。
- 返値1: イベント名(文字列)。"key"イベントならば、"key"
- 返値1: キースキャンコード(数字)。キーボードの各キーに対応した数字(たとえばスペースキーなら57)を返す。
- キースキャンコード: Key (event) - ComputerCraft Wiki
また、ボタン入力で得たキースキャンコードですが、数字であるため、扱いづらいです(57と言われましても・・・)。扱いやすいように、キースキャンコード(数字)からキー名(文字列)に変換してくれる関数を利用しましょう。
- keys.getName(キースキャンコード)
- キースキャンコードを引数として与えると、対応するキーの名前を返す。
- 使用例: keys.getName(57) => "space"
なお、CCのイベントについてより詳しく知りたい方は、以下の「CCチュートリアル目次」より「sleep実装からイベントを学ぶ」の一連の記事をご覧ください。
個別箇所の解説
- L7-9) このプログラムを起動するときに、引数として送信先のIDを指定すること。引数がないときには、エラーメッセージを出して終了します。
- L11-20) 変換テーブルの定義です。テーブルコンストラクタ
{}
を使っています。各行の末尾にこっそりと「,」コンマが入っているので注意(最終行除く)。 - L22) このプログラムを途中でとめるときには、CTRL+Tを押してくださいね。という注意メッセージを表示。
- L23-32) このプログラムのメインループ。
- L24)
os.pullEvent("key")
で、キー入力を検知。変数scancodeに、スキャンコード(数字)が入っています。 - L25) スキャンコード(数字)をキー名(文字列)に変換しています。
- L26) 変換テーブルを用いて、キー名に対応するメッセージに変換しています。
- L27) 押されたキーの名前と、それに対応するメッセージが何かを画面表示。
- 変換テーブルにないキーについては、変数messageの値がnilになっているのでprint()できない。エラー回避のため、
message or "none"
としている。 - この意味は、「messageの値が偽以外ならそのままその値を使い、偽ならば"none"という値を使う」 Luaの決まり文句です。
- 変換テーブルにないキーについては、変数messageの値がnilになっているのでprint()できない。エラー回避のため、
- L29-31) 変数messageの値がある(変換テーブルで変換できた)ときに、メッセージを送信します。
まとめ
送信側プログラムの変換テーブルを編集しさえすれば、いくらでも命令を作ることができます。
たとえば、x="turtle.digDown() turtle.down()"
などもいいですね(キー「x」を押すと、真下掘って下に移動)。
さて、自在に命令を作ることができるのですが、次のような不満はありませんか?
- 「1回のキー入力でもっともっと複雑な動作を行わせたい」
- 「好きな場所に移動させた後、その場所で自分で作ったプログラムを使いたい」(たとえば、回転型直下掘りプログラムとか)
- 「命令文は、turtle.dig()しか使えないの? ファイル内で自分で定義した関数が使いたいんだけど」
あまりイメージ湧かない人のために、ぶっちゃけると 「遠隔操作」で「好きなポイントに移動」して「複雑な穴掘りプログラムスタート」なんてできたら面白そうではありません?
次回は、内容が少しだけ高度になりますが、高度な部分の説明はできるだけさらっと簡単に扱い(これは「おまじない」です)、便利なプログラムの紹介という内容でお送りする予定です。
このプログラムあるととても便利なんですってば!(偏見込み)