Minecraftとタートルと僕

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

こちらのページは更新が滞っており、情報が古くなりつつあります。新しいCC情報サイトをはじめましたので、もしよければご参照ください。今後ともよろしくお願い申し上げます。

「百億のマインクラフトと千億のタートル」(https://hevo2.hatenablog.com/)

sleep実装からイベントを学ぶ(2)―イベントとは

イベントは裏で(ひっそりと)起きているんだ!

タートル君が活動しているときに、僕たちが何かの働きかけを行うと、
タートル君の裏でイベント(Event)が発生します。

たとえば、自動クラフトプログラムが動いているときに、

  • マウスでタートルの画面をクリックすると「mouse_click」というイベントが発生します。
  • キー入力を行うと、「key」イベントが発生します。
  • Wireless通信で何らかのメッセージを受け取ったならば、「rednet_message」が発生します。
  • つながっているレッドストーンケーブルからの信号がONからOFF、あるいはOFFからONに変化したならば「rednet_message」イベントが発生します。
  • (CC1.55以降のversionなら)、タートル君のインベントリの内容が変化したら「turtle_inventory」イベントが発生します。


このようにイベントの種類はたくさんあります。どのようなイベントがあるのかはCC非公式Wikiに日本語で簡潔にまとめてあります。最重要参考資料です。
このチュートリアルを進める間はブラウザの別ウィンドウで表示したままにしておきましょう。

さて、プログラム実行の裏でひっそりと生じたこれらイベントですが、そのままでは捨てられ、忘れ去られてしまいます。プログラム中にイベントを拾う関数を記述しましょう。

イベントを拾い上げる

以下のプログラムを、たとえば「event_test」のようなファイル名で保存し、実行してみましょう。

term.clear()
while true do
  local event, p1, p2, p3 = os.pullEvent()
  print('event=',event)
  print('p1=',p1)
  print('p2=',p2)
  print('p3=',p3)
  print()
end
  • 「term.clear()」で、プログラム開始時に画面表示をすべて消しています。
  • ここでは4つの返値を受け取ることを想定し、それぞれ「event」「p1」「p2」「p3」という変数を用意して代入しています。
  • while trueでループさせているのでプログラムをとめるときにはCTRL+Tを長押ししてください。

さあ、画面をマウスでクリックしてみましょう。そして何かキーを押してみましょう。

f:id:hevohevo:20131222151534p:plain:w500

このような表示がでてくるはずです。
クリックして「mouse_click」というイベントが発生していますし、キーを入力して「key」というイベントが発生しています。

このプログラムで使っている「os.pullEvent()」は次のような関数です。

  • 何かイベントが発生するまでずっと待ち続ける関数
  • イベントが発生したら、複数の返し値(イベントの種類によるが1~5個の範囲)を一度に返す。

たとえば「mouse_click」イベントなら、os.pullEvent()は次のような複数の値を返します。

  • 第1返値(イベント名):"mouse_click"
  • 第2返値(付随するパラメータ1):マウスのどのボタンを押したかを数値で返す。左クリック=1、右クリック=2、中央クリック=3
  • 第3返値(パラメータ2):クリック位置のX座標(横方向)、左上が座標X=1
  • 第4返値(パラメータ3):クリック位置のY座標(縦方向)、左上が座標Y=1


そして「key」イベントなら次のような値を返します。


さてこのプログラムを実際に入力し動かすことで、気になることはありませんか?

注意点1)キー入力を拾い上げるコツ

まず最初に気になるのが、キーコードです。Keyイベントは、キーボードの何かのキーが入力されたときに発生するのですが、たとえば「SHIFT」や「CTRL」キーを押しただけでも発生するのですよね。たとえば「大文字のA」を入力してみましょう。

  • 「SHIFT」キーを単独で押すとキーコード「42」
  • 「a」キーを単独で押すとキーコード「30」
  • 「SHIFT+a」を押すと・・・・・・、「42」と出て、あとは「30」「30」「30」「30」・・・・・・。
  • ・・・・・・これ、「a」と「A」の区別がつくの?

そのために、「どのキーが押されたか」ではなく、「どの文字が入力されたか」というより抽象的な扱いができるイベントが用意されています。
次のようにプログラムを書き換えてみましょう

term.clear()
while true do
  local event, p1, p2, p3 = os.pullEvent("char") -- HERE!
  print('event=',event)
  print('p1=',p1)
  print('p2=',p2)
  print('p3=',p3)
  print()
end

変更部分は3行目のpullEventの引数だけです。
「os.pullEvent("char")」とpullEventにイベント名の引数を与えることで、その他に発生したイベントは無視して、そのイベントだけを取り出してくれます。つまり、どのイベントを取り出すのかというフィルターを設定できるのです。

f:id:hevohevo:20131222154913p:plain:w500

「char」イベントは、この画像にあるように「どの文字が入力されたか」という情報を返します。

  • 第1返値(イベント名):"char"
  • 第2返値(パラメータ1):入力された文字。たとえば「a」「A」など
  • ※基本的に、キーボードのアルファベットや記号にしか反応しない。たとえば、矢印キーなどはこのイベントで拾い上げることができない。

つまり、どの文字が入力されたかを手軽に調べるためにはcharイベントを使い、矢印キーの入力などを扱うためにはkeyイベントを使えばいいわけです。

注意点2)複数の返値って面倒じゃない?

os.pullEvent()は、イベントの種類によって、1個から5個の値を返します。
これまで紹介したプログラムは、それらをひとつずつ変数に代入していましたが、扱うイベントの種類によって、用意する変数の数を変えるのは面倒ですよね。

もっと簡潔に記述する方法を紹介しましょう。

term.clear()
while true do
  local event = {os.pullEvent()}
  for i,v in ipairs(event) do
    print(i, '=', v)
  end
  print()
end

テーブルコンストラクタ「{}」でpullEvent()をくくることで、返ってくる複数の返し値をテーブル(table)ひとつにまとめ、変数eventに代入しています。
これで、一番目の返し値(イベント名)は「event[1]」、2番目は「event[2]」のように添え字で取り扱うことができます。つまり配列のように扱えます。
また、「for i,v in ipairs() do ~ end」は、テーブル(配列)の中身を順番に処理していく決まり文句ですね。イテレータです。

異なる文字入力によって挙動を変えるプログラム例

それでは、以上の内容を踏まえて、次のプログラムを打ち込んでみましょう。

term.clear()
print("Press key: a or A. And press q to exit.")
while true do
  local event = {os.pullEvent("char")}

  if event[1] == "char" then
    if event[2] == "a" then
       print("small a")
    elseif event[2] == "A" then
       print("large A")
    elseif event[2] == "q" then
       print("Terminated: q")
       break
    else
       print("Other char")
    end
  end
end
  • このプログラムは、「char」イベントのみ取り扱います
  • まず、「char」イベントであるかをifで確かめて、
    • その上で、小文字「a」が入力されているなら「small a」、大文字「A」が入力されているなら「large A」と画面表示します。
    • また、小文字「q」が入力されているならwhileループを抜けて、このプログラムを終了します。
    • それ以外の文字が入力されているなら、「Other char」と表示します。

今回のまとめ

  • 色々なイベントが裏でひっそりと起きているんだ!
  • os.pullEvent()でイベントを拾おう。
  • フィルターで、特定のイベントだけを拾うことができる。
  • 「どのキーを押したか」→「key」イベント、「どの文字を入力したか」→「char」イベント
  • if文でイベントの種類や返し値を調べ、分岐させよう。

次回は、keyイベントを使って矢印キーによる操作を紹介しましょう。