読者です 読者をやめる 読者になる 読者になる

Minecraftとタートルと僕

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

sleep実装からイベントを学ぶ(5)―タイマーイベントとは

タイマーイベントってなに?

一言で言うならば、「時限発火式のイベント」です。

これだけじゃあんまりなのでもう少し詳しく説明すると、
あらかじめ時間(秒)を指定してタイマーをスタートしておく。その時間が経過することで発生するのがタイマーイベントです。
発生したタイマーイベントは、いつものos.pullEvent()で拾います。

さあ具体例を挙げましょう。

timer_id = os.startTimer(30)

ename, tid = os.pullEvent("timer")

if ename == "timer" and tid == timer_id then
  print("FIRE!!")
else
  print("ERROR")
end
  • まず、os.startTimer(秒数)でタイマーをスタートします。
    • ここでは、30秒後にタイマーが発火するようにしかけています。
  • またこのとき、os.startTimer()はタイマーID(数値)を返します。
    • 複数のタイマーが同時に動いているときにはこのIDで区別をつけましょう。
    • ここでは、タイマーIDを変数timer_idに入れています。
  • os.pullEvent("timer")でタイマーイベントを拾います。
    • 返し値は、イベントネームと、そのタイマーイベントのIDです。
  • IF文で、そのイベントがタイマーイベントであること、そしてタイマーIDが間違いなく、最初にセットしたタイマーのものであることを確かめたら"FIRE!!"しています。

sleep()の理解

さあこれで、今回のテーマであるsleep()関数が理解できますね。

function sleep( _nTime )
  local timer = os.startTimer( _nTime )

  repeat
    local sEvent, param = os.pullEvent( "timer" )
  until param == timer
end
  • 変数_nTime秒後に発火するようにタイマーをスタートしておく
  • このタイマーのIDは、変数timerに代入
  • pullEventでタイマーイベントを拾い
  • 拾ったタイマーイベントのIDをいれた変数paramが、最初に設定したタイマーIDと同じ場合に、repeatループを抜けて、sleep関数も終了。
  • なお、repeat~untilでわざわざループさせている理由は、他の場所で設置されたタイマーが不幸にもこのタイミングで発火したとき、pullEvent()が間違えてそれを拾ってしまう可能性があるからです。その場合は、repeat構文の条件式で「このタイマーじゃないし!」と否定(false)されるので、再度repeatループを続けることになります。
  • このようにして、正しいIDのタイマーにのみ反応するよう、sleepは作られています。
  • 変数宣言の頭についている「local」って何?
    • そういえば、これまで何度も使っているのに説明をしていませんでした。良い機会ですので、Luaにおける変数の取り扱いについて別記事で説明しましょう。

まとめ

sleepってつまり、なにやっている関数なの?
指定した秒数のタイマーをしかけて、それが発火するまで待機する関数です。

あぁぁぁぁ、長々と連載してきて、まとめるとこれだけなんですよね*1・・・・・・。
でも、ここまでの記事を読んでくれたら、イベントについての理解はかなり深まったはず。たぶん。

*1:本当は、coroutineの話とかしてtoo long without yieldingの話もしたいけど、さすがに話が脱線しすぎるし。それはまた別の機会かな。