mieki256's diary



2020/01/05() [n年前の日記]

#1 [love2d] love2dで簡単なペイントアプリモドキを書いてみたり

love2d を使って、簡単なペイントアプリっぽいものを書いてみたり。

こんな感じになった。環境は Windows10 x64 1909 + love2d 11.3。

simplepaint_ss01.gif

ソース。 :

_conf.lua
function love.conf(t)
  t.version = "11.3" -- love2d version
  t.window.title = "Simple paint - love2d"
  t.window.width = 800
  t.window.height = 600

  -- VSync Off
  t.window.vsync = 0

  -- t.window.fullscreen = true
  -- t.window.fullscreentype = "exclusive"
end

_main.lua
-- Simple paint on love2d

function love.load()
  love.graphics.setDefaultFilter("nearest", "nearest")
  font = love.graphics.newFont(20)

  scrw = love.graphics.getWidth()
  scrh = love.graphics.getHeight()
  canvas = love.graphics.newCanvas(scrw, scrh)

  bg = make_checker_canvas(scrw, scrh)

  love.graphics.setCanvas(canvas)
  love.graphics.clear(0, 0, 0, 0)
  love.graphics.setCanvas()

  mx, my = 0, 0
  req_clear_canvas = false
  req_export = false

  msg_timer = 0
  msg_str = ""
end

function love.update(dt)
  mx, my = love.mouse.getPosition()

  if req_clear_canvas then
    -- clear canvas
    req_clear_canvas = false
    msg_timer = 0.75
    msg_str = "Clear canvas"
    love.graphics.setCanvas(canvas)
    love.graphics.clear(0, 0, 0, 0)
    love.graphics.setCanvas()
  end

  if love.mouse.isDown(1) then
    -- draw brush
    love.graphics.setCanvas(canvas)
    love.graphics.setColor(0, 1, 0, 1)
    love.graphics.circle("fill", mx, my, 8)
    love.graphics.setCanvas()
  end

  if req_export then
    -- export canvas
    req_export = false
    msg_timer = 0.75
    local filename = os.date("%Y-%m-%d_%H-%M-%S") .. ".png"
    if export_canvas(canvas, filename) then
      msg_str = "Export " .. filename
    else
      msg_str = "Can not export."
    end
  end

  if msg_timer > 0 then
    msg_timer = msg_timer - dt
    if msg_timer <= 0 then
      msg_timer = 0
    end
  end
end

function love.draw()
  love.graphics.setCanvas()
  love.graphics.clear(0, 0, 0, 1)

  -- draw bg
  love.graphics.setColor(1, 1, 1, 1)
  love.graphics.draw(bg)

  -- draw canvas
  love.graphics.draw(canvas)

  -- draw cursor
  love.graphics.setColor(1, 1, 1, 1)
  love.graphics.circle("line", mx, my, 8)

  -- draw text
  love.graphics.setFont(font)
  love.graphics.setColor(1, 1, 1, 1)
  if msg_timer > 0 then
    love.graphics.print(msg_str, 2, 40)
  end

  love.graphics.print("C)lear S)ave", 10 * 10, 2)
  love.graphics.print("FPS: " .. tostring(love.timer.getFPS()), 2, 2)
end

function love.keypressed(key, isrepeat)
  if key == "escape" then
    -- ESC key to exit
    love.event.quit()
  elseif key == "s" and msg_timer == 0 then
    req_export = true
  elseif key == "c" then
    req_clear_canvas = true
  end
end

function export_canvas(canvas, filename)
  local imagedata = canvas:newImageData()
  local filedata = imagedata:encode("png")

  local filepng = io.open(filename, "wb")
  if filepng ~= nil then
    filepng:write(filedata:getString())
    filepng:close()
    return true
  end
  return false
end

function make_checker_canvas(w, h)
  local cnavas = love.graphics.newCanvas(w, h)
  cnavas:renderTo(
    function()
      local start = true
      local sz = 8
      local x, y
      for y = 0, (h - 1), sz do
        local fg = start
        for x = 0, (w - 1), sz do
          local c = fg and 0.6 or 0.4
          love.graphics.setColor(c, c, c, 1)
          love.graphics.rectangle("fill", x, y, sz, sz)
          fg = not fg
        end
        start = not start
      end
    end
  )
  return cnavas
end

conf.lua と main.lua を任意のフォルダに入れて、「love フォルダ名」で実行できる。

少し解説。 :

やってることは以下。
  • 初期化処理(love.load()内)で、ウインドウサイズと同じサイズの Canvas を作成して。
  • 更新処理(love.update(dt)内)で、マウス左ボタンが押されてたら Canvas に緑色の丸を描画。
  • 描画処理(love.draw()内)で、Canvas を画面に描画。

conf.lua 内で、t.window.vsync = 0 を書いて、VSYNC を無効にしてるあたりにちと注意、だろうか。

love2d は、何も設定しないデフォルト状態なら VSYNC が有効になっている。その状態だと更新処理が60FPS前後で呼ばれるので、マウスを動かして画面に何か描こうとすると、軌跡(?)がかなり飛び飛びになってしまう。 *1

しかし、VSYNCを無効にすれば、更新処理が呼ばれる頻度が多くなるので、それほど飛び飛びにはならなかった。手元の環境では、500FPS前後で更新処理が呼ばれてるっぽい。

もっとも、本来は、マウスカーソルが動いた時だけ、距離に応じて線を引くように実装すべきかなと…。そう考えると、マウスカーソルを動かした時に呼ばれるコールバック関数( _love.mousemoved() )を用意して処理したほうがいいのかもしれない。

love2d の API についても一応メモ。
  • love.graphics.setCanvas(canvas) で、指定した canvas を対象にして描画できるようになる。
  • love.graphics.setCanvas() で、デフォルトのキャンバスに対して描画できるようになる。
  • canvas:renderTo(func) で、canvas に対して関数 func の処理を実行することもできる。
  • love.graphics.circle("fill", x, y, r) で、(x,y) を中心にして塗り潰した円を描画。
  • love.graphics.circle("line", x, y, r) で、(x,y) を中心にして線のみの円を描画。
  • love.graphics.rectangle("fill", x, y, w, h) で、四角形を描画。

_love.graphics.setCanvas (日本語) - LOVE
_Canvas:renderTo (日本語) - LOVE
_love.graphics.circle (日本語) - LOVE
_love.graphics.rectangle (日本語) - LOVE

さておき。こういう処理を書けたのだから、お絵描きツールっぽい何かしらを、love2d を使って書くことだって不可能ではなかったりするのかもしれないなと…。

*1: 液晶ディスプレイ側のリフレッシュレート設定によって、VSYNC有効時のFPSが違ってくるのかもしれない。自分は120Hz等の液晶ディスプレイを持っていないので、そのあたりは確認できず。

以上です。

過去ログ表示

Prev - 2020/01 - Next
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project