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

Minecraftとタートルと僕

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

h2touchpanel API 詳細

チュートリアル Lua ComputerCraft Minecraft API

はじめに

次の図のように、外付けモニタ・ターミナル画面にボタンを表示することでタッチパネルを実現するAPIです。

f:id:hevohevo:20140209062030p:plain:w350
f:id:hevohevo:20140209062034p:plain:w500

タッチパネルのボタンを右クリックすると、そのボタンにあらかじめ設定されているコマンド(任意の関数)を実行できます。

  • 任意の関数を設定できるので、例えば次のようなことができます。
    • 標準のAPIだけでなく、そのプログラム内で定義した関数も実行可能
    • "shell.run(ファイル名)"関数を使えば、そのコンピュータ内の任意のプログラムファイルを呼び出して実行可能

たとえば、実行プログラムを選択するメニュー画面が簡単に作れてしまいますね。
あるいは銀行ATMのように0から9までのボタンを表示してパスワード認証させる使い方もできるかも。
アイデアしだいでいろいろできそうです。
f:id:hevohevo:20140209205750p:plain:w300

サンプルコード

本APIを使えば、上記のようなタッチパネル式メニュー画面を簡単に作成することができます。
以下のような短いプログラムでメニュー画面が作れたら楽しそうではありませんか?

  • (2014/02/17:version0.1dに修正。Panel Optionの整備、モニターのscaleを指定可能)
  • (2014/02/11:version0.1cに修正。パネル作成時にoptを省略したときの挙動がおかしいのを修正)
  • (2014/02/11:version0.1bに修正。"cmd"の値に関数(function)を受け付けるようにした)
os.loadAPI("h2touchpanel")

-- button_config: "name"(string) and "cmd"(function) are required.
local bCfg = {}
bCfg[1]={name="open", cmd=function() rs.setOutput("right", true) end}
bCfg[2]={name="close", cmd=function() rs.setOutput("right", false) end}
bCfg[3]={name="pass", cmd=myNewFunc}
bCfg[4]={name="sleep", cmd=runProgram}

-- define function
local myNewFunc = function() print("hello") end
local runProgram = function() sleep(10) shell.run("hevo2.lua") end

local mon = term
--local mon = peripheral.wrap("top")

-- makePanel(button_cfg, col, row, mon) returns Panel-object.
local p1 = h2touchpanel.makePanel(bCfg, 2, 2, mon)
p1:draw()

while true do
  local event, b1 = p1:pullButtonPushEvent() -- returns pushed Button-object

  p1:drawPushedButtonEffect(b1) -- pushed effect
  b1:evalCmd() -- eval(run) function
end

APIのインストール

ソースコード

http://pastebin.com/eK9BW600

ダウンロード

以下のようにpastebinコマンドが一番楽だと思います。

> pastebin get eK9BW600 h2touchpanel

APIとして読み込み

このAPIを使いたいプログラムで以下を記述。

os.loadAPI("h2touchpanel")

使用上の注意

このAPIは、オブジェクト指向プログラミングで作成しています。
そのため、このAPIを使うには以下の手順が必要です。

  1. h2touchpanel.makePanel()でPanelオブジェクトを作成する(これは、Panel.new()のラッパー)。
  2. Panelオブジェクトのメソッドを用いてボタンを表示したり、どのボタンが押されたかを感知する。
  3. 「:」(コロン)記法を使っているので混乱しないよう、ご注意ください。

重要な関数、メソッドの紹介

makePanel(ボタン設定テーブル, 列数, 行数, モニター, その他オプション)

  • パネルオブジェクトを作成する本APIの最重要関数。
  • 引数1:「ボタン設定テーブル」
    • 必須項目は、ボタンの名前「name」とそのボタンを押して実行する関数「cmd」
    • 必要なボタンの数だけボタン設定テーブルを作成し、本関数に与えること。
  • 引数2: 列数(数字)、横方向のボタンの数
  • 引数3: 行数(数字)、縦方向のボタンの数
  • 引数4: モニター関数テーブル
    • peripheral.wrap()する場合、 色を使うので金色モニターを使うこと。
    • 「mon=term」とすれば、ターミナル画面をタッチパネルにできる。ただし金色コンピュータ必須。
  • 引数5: その他のオプション(Table)。省略可能。詳細についてはソースを確認のこと。
    • leftPos、topPos: パネルの左上の座標。それぞれ数値を指定。
    • rightPos、bottomPos: パネルの右下座標。それぞれ数値を指定。
    • fgColor: ボタンのラベルの色。colors.white など。
    • bgPattern: ボタンの背景色配列。{colors.blue, color.cyan} など。
    • scale: モニターの文字倍率。setTextScale値

Panel オブジェクトのメソッド

以下、作成したPanelオブジェクトを「panel」と表記する。「:」(コロン)記法に注意。

panel:draw()
  • パネルを画面表示する。
panel:pullButtonPushEvent(モニタ方向フィルタ)
  • os.pullEvent()を使って、タッチパネルのボタンが押されるまで待つメソッド
  • 引数1: 複数のモニタがあるときに、方向フィルタを指定するとその方向のモニタにだけ反応する。なお、省略可能。
  • 返値1: イベント名"button_push"。このAPI独自のイベント。
  • 返値2: 押されたButtonオブジェクトを返す。
panel:drawPushedButtonEffect(Buttonオブジェクト)
  • ボタンが押されたとき、そのボタンを強調表示する画面エフェクト。
  • 引数1: 強調表示したいButtonオブジェクト
  • 返値なし

Button オブジェクトのメソッド

以下、Buttonオブジェクトを「button」と表記する。「:」(コロン)記法に注意。

button:evalCmd()
  • そのボタンに設定されているコマンド(関数)を実行する。
  • 引数なし
  • 返値1: 設定されている関数が始めからない場合はfalse。そうでなければtrue。

まとめ

このAPIは、Luaでオブジェクト指向プログラミングをするチュートリアルの一環として作りました。
でもさすがにコード量が多すぎて、解説するかどうか迷い中。
ピンポイントで重要な部分だけ解説するかなぁ。

そもそも解説の需要があるのだろうか。読者の反応がないのでよくわからない。

このh2touchpanel APIと以前作ったh2peripheral APIを組み合わせれば、簡単にラジコンプログラムができますよね。
このあたりを突き進めて行くのも良いですし、あるいは今回のh2touchpanel APIをさらに強化することも考えています。
たとえばこのAPIを使っていて困るのが、ボタンの数が足りないこと。
モニタの解像度の問題で、どうしても一度に表示できるボタンの数が限られてしまうのですよね。
タッチパネルを複数束ねた、PanelGroupオブジェクトを実装しようかな。
Panelオブジェクトを複数保持しており、ボタン操作で次のパネルへ切り替えできるの。

アイデアがいろいろ湧いてきて楽しい。実は計画するときが一番楽しいのではないかと思いつつある今日この頃。

補足

せっかく作ったタッチパネルAPIですが、二番煎じになっていないかふと気になって
CC公式Forumで似たようなAPIが出ていないか調べてみました。

そうすると、
http://www.computercraft.info/forums2/index.php?/topic/14784-touchpoint-api/
というものがががが。

こちらは TouchPoint APIということで、タッチパネルをボタン単位で一つずつ作成・表示するAPIですね。僕のAPIのようにボタンを並べたタッチパネルを作りたかったら、表示する座標を計算しつつ一つずつボタンを配置していかなくてはなりません。

ちなみに使い方はこんなかんじ。僕のと似ているなぁw

--# add a button to the instance
t:add("label", function() print(123) end, 2, 2, 28, 11, colors.red, colors.lime)

--# draw the set of buttons in the instance
t:draw()

--# catch and handle monitor touch events on buttons
--                                  to transform them to button_click events
event, p1, p2, p3, p4, p5 = t:handleEvents(os.pullEvent())

このAPIをぱくれば作成時間が半分以下になっ
で、でも。機能は、こ、こちらの方が上だし!
お、オブジェクト指向プログラミングの勉強だし!