(2018.8.7. 公開) (2018.8.26. 対象をバージョン 11 系列に変更)
マウスやタッチスクリーンが「押された」ことを知るには、love.mousepressed()
というコールバックを使えばよい。
function love.mousepressed(x, y, button, istouch)
-- (x, y): マウスの座標
-- button: ボタンの番号 (1: 左、2: 右、3: 真ん中)
-- istouch: タッチスクリーンなら true, そうでなければ false、
end
さっそくプログラム例。画面を円が移動していく。マウスでクリックするたびに、その円が2つに割れて、小さい円になる。どうってことなさそうだけど、案外ハマるよ。
-- サンプルプログラム 12-01 main.lua
function love.load()
love.graphics.setBackgroundColor(1, 1, 1)
width = love.graphics.getWidth()
height = love.graphics.getHeight()
c = {{width / 2, height / 2, 64, 100, 1.0}} -- x座標、y座標、半径、スピード、方向
end
-- 点 (x1, y1) と (x2, y2) の間の距離を返す
function distance(x1, y1, x2, y2)
local xx = x1 - x2
local yy = y1 - y2
return math.sqrt(xx * xx + yy * yy)
end
function love.mousepressed(x, y, button, istouch)
local ii
for i, a in ipairs(c) do -- 配列 c の各要素について調べる
if distance(x, y, a[1], a[2]) < a[3] then -- ヒットしたか
table.remove(c, i)
if a[3] > 2 then
-- 新しい小さい円を2つ作る
table.insert(c, {a[1], a[2], a[3] / 1.414, a[4] * 1.2, a[5] + love.math.random()})
table.insert(c, {a[1], a[2], a[3] / 1.414, a[4] * 1.2, a[5] - love.math.random()})
end
break
end
end
end
function love.update(dt)
for i, a in ipairs(c) do
local x, y = a[1], a[2]
local dx = a[4] * dt * math.cos(a[5])
local dy = a[4] * dt * math.sin(a[5])
x = x + dx
y = y + dy
if x < a[3] or x > width - a[3] then
a[5] = 3.1415927 - a[5] -- 左右反転
x = x - 2 * dx
end
if y < a[3] or y > height - a[3] then
a[5] = -a[5] -- 上下反転
y = y - 2 * dy
end
a[1], a[2] = x, y
end
end
function love.draw()
love.graphics.setColor(0, 0, 1)
for i, a in ipairs(c) do
love.graphics.circle("fill", a[1], a[2], a[3])
end
end
上のようにリアルタイム性の高い場合は、「クリックした瞬間」に処理すればよいが、一般的には「マウスで何かを押すと、その部分の色が変わる」→「ボタンを離した瞬間に処理が行われる」という手順が普通である。このため、「押された」→「まだ押されてる」→「離された」という一連の流れをプログラムに組み込んでみる。
例として、画面にボタンを表示して、それを「押す」→「離す」という操作で何かメッセージを出してみる。水色の四角がボタン。押されると緑色になり、離されると元に戻って「呼んだ?」というメッセージが表示される。
マウスボタンを離す操作、およびマウスポインタを動かす操作は、以下のコールバックで処理する。
function love.mousemoved(x, y, dx、dy, istouch)
-- (x, y): マウスの座標
-- (dx, dy): 直前に呼ばれた時からの移動量
-- istouch: タッチスクリーンなら true, そうでなければ false、
end
function love.mousereleased(x, y, button, istouch)
-- (x, y): マウスの座標
-- button: ボタンの番号 (1: 左、2: 右、3: 真ん中)
-- istouch: タッチスクリーンなら true, そうでなければ false、
end
処理は次のように進める。まず、ボタンが押されているかどうかを示す変数を1つ決める(ここでは pressed
とする)。値の意味は次のように決めておく。
値 | 意味 |
0 | マウスボタンは押されていない |
1 | マウスボタンが押されている ポインタは画面ボタンの枠の中 |
2 | マウスボタンが押されている ポインタは画面ボタンの枠の外 |
love.mousepressed()
が呼ばれたら、マウスポインタの座標を調べて、画面ボタンの枠の中にあれば、pressed
を 1 にする。pressed
が 0 でない間は、love.mousemoved()
で、ポインタが画面ボタンの枠から外れれば pressed
を 2 にし、枠に入っていれば 1 に戻す。love.mousereleased()
では、pressed
が 1 の時に限って、「ボタンが離された」時の処理を行う。
-- サンプルプログラム 12-02 main.lua
-- ipag.ttf (IPAゴシックフォント) が必要
function love.load()
love.graphics.setBackgroundColor(1, 1, 1)
font = love.graphics.newFont("ipag.ttf", 24) -- IPAゴシック、24ポイントのフォントを作る
love.graphics.setFont(font) -- そのフォントを設定
rect = { 20, 20, 80, 40 } -- ボタンの枠
pressed = 0 -- 押されていない
yonda = nil -- ボタンが押されたら、押された時刻が入る
end
function point_in_rect(x, y, rect)
return x >= rect[1] and x <= rect[1] + rect[3]
and y >= rect[2] and y <= rect[2] + rect[4]
end
function love.mousepressed(x, y, button, istouch)
if button == 1 and point_in_rect(x, y, rect) then
-- マウスがボタンの枠の中で押された
pressed = 1 -- 「押された」状態にする
end
end
function love.mousemoved(x, y, dx, dy, istouch)
if pressed ~= 0 then
if point_in_rect(x, y, rect) then
pressed = 1 -- 押されている
else
pressed = 2 -- まだ押されているがボタンの枠から外れた
end
end
end
function love.mousereleased(x, y, button, istouch)
if pressed == 1 then -- 枠の中で押されていた
yonda = love.timer.getTime() -- メッセージ表示のためのタイマーをセット
end
pressed = 0
end
function love.draw()
if pressed == 1 then
love.graphics.setColor(0, 1, 0)
else
love.graphics.setColor(0, 1, 1)
end
love.graphics.rectangle("fill", rect[1], rect[2], rect[3], rect[4], 10, 10)
if yonda then
if love.timer.getTime() - yonda < 5 then
-- ボタンが離されてから5秒間メッセージを表示
love.graphics.setColor(0, 0, 0)
love.graphics.print("呼んだ?", 120, 20)
else
-- 5秒たったら yonda を nil に戻す
yonda = nil
end
end
end
ラズパイでタッチスクリーンを使いたいと思ったのだが、どうも素のままのビルドではだめらしい。私が使っているのは Elecrow の5インチディスプレイで、ADS7846 をコントローラとする抵抗式タッチスクリーンがついている。Raspbian に tslib
を入れれば X window なしでも利用できるのだが、LÖVE ではうまくいかない。下のようなエラーメッセージが出てしまう。
INFO: The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list <https://discourse.libsdl.org/> EVDEV KeyCode 330
SDL がタッチスクリーンを認識していないらしい。環境変数などをいろいろいじってみたが、結局 SDL2 にパッチを当てて再ビルドする必要があった。「インストール」のページに改訂版を置いておきましたので、お試しください。パッチは SDL-2.0.8 専用。作成には Cedric Paille さんの SDL2-PI を参考にした。
なお、このバージョンでは、タッチスクリーンはマウスとして認識される。また、他のタッチスクリーン(特に純正の7インチタッチスクリーン)での動作は未確認。いろいろと不完全だが、SDL2, LÖVE がきちんと対応するまでは辛抱するしかない。純正スクリーンについては、入手できれば動作確認したいと思っています。
目次