Tutorial:Drawing Order (日本語)

LÖVE は Z オーダー機構を内蔵していないので、通常はアドベンチャー・ゲームといったもので分かりますが正面またそれぞれの位置に依存するオブジェクトの背面へ自機を自動的に描画するゲームの作成時にある問題に遭遇する場合があります。この教本はこれを非常に極めて単純化した方法にて行う方法を解説します。

注意: この教本において、自機の "正面" であるオブジェクトに言及する場合は自機と画面の中間にあることを意味します。"背面" では自機は画面とオブジェクトの中間にあることを意味します。 最初に、いくつかリソースが必要です:

-- 場面用の背景
scene = love.graphics.newImage("room.png")
-- 動かせる自機
person = love.graphics.newImage("guy.png")
-- 動き回るオブジェクト
object = love.graphics.newImage("ball.png")

よろしい、今は必要とする資源として自機とオブジェクトの位置を内包するいくつかの変数があります:

-- 自機の位置
character = {400,400} -- x,y
 
-- 各々の位置によるオブジェクトの集まり
objects = {}
objects[1] = {550,370}
objects[2] = {220,390}
objects[3] = {600,410}
objects[4] = {300,450}
objects[5] = {400,530}

それらのオブジェクトのリストが Y 位置に順序付けられているか確認してください。これは、それらを描画するときに重要です。一般的なアプリケーションに対しては、まず最初に Lua 関数 table.sort を使用することができます。

function orderY(a,b)
  return a[2] < b[2]
end
table.sort(objects, orderY)

そうではありますが、オブジェクトへインデックスを直接に格納しないように注意する必要があります。オブジェクトのインデックスはソート後に変更します(描画目的でのみコピーを作成したい場合があるかもしれません)。

これらのオブジェクトを描画するには、これを使用します。

love.graphics.draw(object, objects[i][1] - object:getWidth()/2, objects[i][2] -  object:getHeight())

object パラメータは描画する画像を指定しており次の2つの引数は画面状において画像の右上角を何処に描画すべきかを指定します。object[i] で指定された x および y 座標 の水平の中央に指定した画像の下部を配置するために幅および画像の高さの半分を減算します。

オーケー、画面周辺に自機を移動させるためのある方法を作成したと仮定しており、全体のものを描画する準備を終えています (または、そうでなければ違いを理解していないことでありこれでは全く以て無意味です)。これを行う方法を知らないのであれば、支援用に別の教本を数本ほど参照することをお勧めします。簡潔さに関しては love.draw 関数全体を示して次に何が起こるかを説明します:

function love.draw() 
    love.graphics.draw(scene, love.graphics:getWidth() / 2 - scene:getWidth()/2,
        love.graphics:getHeight() / 2 - scene:getHeight() / 2) -- 画面中央に描画します。
 
    local drawn = false -- true 時は自機が描画されます。
 
    for i,v in ipairs(objects) do
        if not drawn and objects[i][2] > character[2] then
            love.graphics.draw(person, character[1] - person:getWidth()/2, character[2] - person:getHeight())
            drawn = true
        end
	love.graphics.draw(object, objects[i][1] - object:getWidth()/2, objects[i][2] - object:getHeight())
   end
 
   if not drawn then -- 人物が下記の全てのオブジェクトならばループ内では描画されません。
      love.graphics.draw(person, character[1] - person:getWidth()/2, character[2] - person:getHeight())
   end
 
   -- 背景オブジェクトをこちらへ
 
end

第一に通常は場面を背面内に描画します (どのような前景オブジェクトであろうと常に正面にあります)。 次に drawn と呼ばれる変数を作成します。これは自機が描画された場合に自機を再度複数回の描画を行わないことを保証するために前景のオブジェクトに自機は存在すべきではないことを教えます。 次に全てのオブジェクトを通過して for ループおよびイテレートに入ります (その順序は最も接近している所から遠く彼方になります)。その後にオブジェクトが自機の前景にあると推測される場合は、自機を描画 (および drawn 変数の設定) すべきかを確認します。この理由は、この for ループを通過して自機の前景にオブジェクトが現れたときに自機を描画するか残りのオブジェクトを描画し続けるまでオブジェクト (この場合は全て同じ画像ですが、そうする必要はありません) を描画するからです。 ループの終端への到達および未だ自機を描画していない場合は描画処理は終了しており自機は全オブジェクトの前景にあることを意味します。

以上です。デモのダウンロードおよび試してみてください。それは非常に単純かもしれませんが、この教本では描画順に関してのみであり、自機がオブジェクトへ衝突している場合またはクリックしたときに自機を移動する場合の確認方法を知りたいのであれば独学でお願いします (このための教本が制作されるまで)。 これが正直なところ不十分ならば、これに関してフォーラムにて自由に意見してください。

関連

代わりに、拡張可能な実装として : Skip list:Drawing Order



そのほかの言語