Skip list:Drawing Order (日本語)
設計思想によりエンジンが対応していないため LÖVE の Z オーダー (重なり、深度、奥行き、描画順序) は面倒です。様々な平面上にある多数のスプライトを扱うのが困難なため、自力でスプライトを順番に描画する必要があります。
これは、スキップリストによるデータ構造で実現できます:
zlist = makeSkipList(3) -- 構造体の推定の大きさは 3 です。
-- それは示されていますが、良い推測は性能の改善になります。
Clown = makeSprite (100, 100, 1, "clown.png") -- x, y, z, image
Frogs = makeSprite (100, 110, 1, "frogs.png") -- Clown と同一平面ですが、後で作成されたため上部へ描画されます。
Tools = makeSprite (90, 120, 0, "tools.png") -- Clown の下で
zlist:insert( Frogs )
zlist:insert( Tools )
zlist:insert( Clown ) -- 任意順にて挿入できます。
for _, sprite in zlist:iter() do
-- Z オーダーにてスプライトを描画します :-)
print( sprite.x, sprite.y, sprite.z, sprite.image )
end
出力:
90 120 0 tools.png
100 100 1 clown.png
100 110 1 frogs.png
Z 軸にあるアイテムの位置を変更したい場合は、削除を行ってから後方へ挿入します。
Tools.z = 2
zlist:delete(Tools)
zlist:insert(Tools) -- 現在 Tools は杭の上にあります。
for _,sprite in zlist:iter() do
print(sprite.x, sprite.y, sprite.z, sprite.image) -- 描画(スプライト)
end
ここでの出力:
100 100 1 clown.png
100 110 1 frogs.png
90 120 2 tools.png
makesprite の小規模実装:
do
local count = 0
function counter()
count = count + 1
return count
end
end
do
local lt = function(a,b)
if a.z < b.z then return true
elseif a.z==b.z and a.id < b.id then return true
else return false
end
end
local mt={
__lt=lt,
__le=lt
}
function makeSprite (x,y,z,image)
local s={x = x, y = y, z = z, image=image, id = counter()}
-- そうしなければ同一平面上にあるアイテムが問題を引き起こすため id フィールドは必要です。
return setmetatable(s,mt)
end
end
関連
- スキップリスト - Wikipedia
- Zオーダー - Wikipedia
- 直交座標系 - Wikipedia
- よくある質問と答え
- 要素の挿入、削除、ランダムアクセスが全部高速なリストを作った - kaisehのブログ
- Tile-based map and tile/sprite Z-order - LÖVE
- SkipListの勉強 - FPGA開発日記
- 離散数学