TLfres (日本語)

TLfres について

TLfres の目的は指定の画面解像度でゲームを実行できるように作成することを非常に容易にすることです。これを使用してもグラフィックスのコード書き直しは要求されません!

このライブラリの使用条件は ZLIB ライセンスです。

準備

モジュールにある全ての関数は TLfres 名前空間に存在しており、従ってグローバル変数への干渉を心配する必要はありません。ゲームでは LÖVE 標準解像度である 800×600 を使用して構築されている仮定します:

  1. ゲームのフォルダへ tlfres.lua を保存します。
  2. main.lua の先頭へ local TLfres = require "tlfres" の行を追加します。
  3. love.draw() の始行へ TLfres.beginRendering(800, 600) の行を追加します。
  4. love.draw() の終行へ TLfres.endRendering() の行を追加します。
  5. 現在の尺度係数値が必要ならば、 TLfres.getScale(800, 600) を呼び出してください。
  6. love.mouse.getPosition を呼び出すのではなく TLfres.getMousePosition(800, 600) を呼び出してください。
  7. love.graphics.setPointSize(x) を呼び出すのではなく love.graphics.setPointSize(x * TLfres.getScale()) を呼び出してください (Love は点の大きさを自動的に変更しません)

よくある質問と回答

Q) この関数を love.graphics.scale の代わりに使う理由は?
A) 指定解像度にて画面を等しく伸張するには技巧的な算術を要求されますが、 TLfres ではそれを処理することができるからです。さらに、ほとんどの人々は伸張されたグラフィックスを嫌います。 ― そのため、 TLfres の letterboxing (レターボックス化) オプションを使用するべきです。画面を伸張する代わりに、正確な比率で大きさを変更し、必要であれば上部と下部へ暗幕帯を描画します。
Q) どの解像度 / アスペクト比率に対応していますか?
A) 全部対応しています。
Q) 非標準の解像度を使用してゲームを作成しました。 TLfres に対応するために全部変更しなければらないのでしょうか?
A) いいえ! ゲーム構築時の解像度で TLfres.beginRendering() を呼び出してください (詳細は後述)。

関数

TLfres.beginRendering

TLfres.beginRendering(width, height, centered)

なにか描画する前に love.draw() の一行目で、この関数を呼び出してください。これは現在の画面解像度で必要とされる尺度と座標変換 (並進移動) です。絶対画面座標で描画する場合は、この関数の呼び出し前 (または endRendering() の呼び出し後) に描画処理をしてください。

number width
対象となる Canvas の幅。
number height
対象となる Canvas の高さ。
boolean centered (false)
true ならば (0, 0) の座標は Canvas の中央となり、そうでなければ左上角となります。

TLfres.endRendering

TLfres.endRendering(letterboxColor)

すべて描画した後に love.draw() の最終行で、この関数を呼び出してください。画面表示範囲外にあるグラフィックスのトリミングをするためにレターボックスを描画します。デフォルトのレターボックスは黒色です。

table letterboxColor ({0,0,0, 255})
レターボックスの配色を RGBA で指定します (love.graphics.setColor と同じです)。デフォルトは黒色です。

TLfres.getScale

TLfres.getScale(width, height)
number width
コードで指定された Canvas の幅。
number height
コードで指定された Canvas の高さ。

TLfres.getMousePosition

TLfres.getMousePosition(width, height)

これは通常、 love.mouse.getPosition を呼び出すときに使用してください。返される位置は指定の寸前になります。

number width
コードで指定された Canvas の幅。
number height
コードで指定された Canvas の高さ。

tlfres.lua

local lwGetMode     = _G.love.window.getMode
local lgPush        = _G.love.graphics.push
local lgPop         = _G.love.graphics.pop
local lgTranslate   = _G.love.graphics.translate
local lgScale       = _G.love.graphics.scale
local lgRectangle   = _G.love.graphics.rectangle
local lgSetColor    = _G.love.graphics.setColor
local lmGetPosition = _G.love.mouse.getPosition
local min = math.min

local TLfres = {}

local lastMouseX, lastMouseY = 0, 0
local currentlyRendering

-- 内部ヘルパー関数
local function _getRawMousePosition(width, height)
   local x, y = lmGetPosition()
   local w, h = lwGetMode()
   local scale = min(w/width, h/height)
   return (x - (w - width * scale) * 0.5)/scale, (y - (h - height * scale) * 0.5)/scale
end

-- これは通常、 love.mouse.getPosition を呼び出すときに使用してください。
-- 返される位置は指定の寸前になります。
function TLfres.getMousePosition(width, height)
   local x, y = _getRawMousePosition(width, height)
   if x >= 0 and x <= width and y >= 0 and y <= height then
      lastMouseX, lastMouseY = _getRawMousePosition(width, height)
   end
   return lastMouseX, lastMouseY
end

-- 
-- 希望する寸法と現在の寸法から現在の尺度を計算します。
-- レンダリングブロックから呼び出す場合は、引数 width と height は必要に応じて指定してください。
function TLfres.getScale(width, height)
   if currentlyRendering then
      width  = width  or currentlyRendering[1]
      height = height or currentlyRendering[2]
   end
   local w, h = lwGetMode()
   return min(w/width, h/height)
end

-- 拡大と中央揃えにより現在のウィンドウに width×height を収めます。
-- 0,0 は Canvas の左上です。また centered が true ならば中央になります。
-- この関数は love.graphics.push の前とレンダリング後 love.graphics.pop の次行で使用してください。
function TLfres.beginRendering(width, height, centered)
   if currentlyRendering then
      error("Must call tlfres.endRendering before calling beginRendering.")
      return
   end
   currentlyRendering = {width, height}
   lgPush()

   local w, h = lwGetMode()
   local scale = min(w/width, h/height)
   lgTranslate((w - width * scale) * 0.5, (h - height * scale) * 0.5)
   lgScale(scale)
   if centered then
      lgTranslate(0.5 * width, 0.5 * height)
   end
   return scale
end

local _black = {0, 0, 0, 255}

-- 座標変換から復帰します。letterboxColor が true ならば黒色でレターボックスの暗幕を描画します。
-- letterboxColor には {r, g, b, a} テーブルを指定できます。
function TLfres.endRendering(letterboxColor)
   if not currentlyRendering then
      error("Must call tlfres.beginRendering before calling endRendering.")
      return
   end
   local width, height = currentlyRendering[1], currentlyRendering[2]
   currentlyRendering = nil
   lgPop()

   local w, h = lwGetMode()
   local scale = min(w/width, h/height)
   width, height = width * scale, height * scale

   lgSetColor(letterboxColor or _black)
   lgRectangle("fill", 0, 0,  w,  0.5 * (h - height)) -- 上
   lgRectangle("fill", 0, h,  w, -0.5 * (h - height)) -- 下
   lgRectangle("fill", 0, 0,  0.5 * (w - width), h)   -- 左
   lgRectangle("fill", w, 0, -0.5 * (w - width), h)   -- 右
end

return TLfres

用例

local TLfres = require "tlfres"

local CANVAS_WIDTH = 800
local CANVAS_HEIGHT = 600
local POINT_SIZE = 1

function love.mouse.getPosition() -- 標準関数をヘルパー関数でオーバーライドします。
   return TLfres.getMousePosition(CANVAS_WIDTH, CANVAS_HEIGHT)
end

function love.draw()
   tlfres.beginRendering(CANVAS_WIDTH, CANVAS_HEIGHT)

      love.graphics.setPointSize(tlfres.getScale()*POINT_SIZE) -- 点の大きさは自動的に変更されませんので、手動で乗算をしてください。
      love.graphics.points(400, 300) -- 画面寸法の変更に関係なく描画は Canvas の中心で行います。

   tlfres.endRendering() -- 黒色でレターボックスを描画します。
end

そのほかの言語