背景タイルを指定すれば、それとの境界のみ描く機能追加
なかなかいい感じ。
境界線が細ければあまり変わらないかな?
それはともかく(主に自分のために)境界線描画方法の確認をしてみます。
タイルやセル間の境界線
タイルやセル(やエリア)間の境界線や縁取りを描画するにはどのような方法があるでしょうか。
内側に描画、外側に描画、どちらにもかかるように描画、そしてグリッド線のON、OFFによって描画する方法などがあると思います。
(どこかにまとめられたものがあったりしますでしょうか?)
最後のグリッド線のイメージはこのような感じです。
この方法なら「TIC-80」の(それ以外の)タイルマップでも比較的楽に実現できます。
二方向境界タイル
上記の境界線の再現ですが、2方向を考慮するだけでだいたい実現可能です。
例えば、上のようなタイルを用意して
- 左とタイル番号(エリア番号など)が異なれば「1」
- 上とタイル番号(エリア番号など)が異なれば「2」
- 左、上、どちらも異なれば「3」
- 左も上も同じなら「0」のまま
(青矢印:同じ、赤矢印:異なる)
このような法則でタイルを当てはめてみます。
はい、概ね再現出来ていますが所々(赤丸部分)少し不自然に境界が欠けています。
これが「だいたい」と表記した理由です。
2.25方向境界タイル
境界線が細ければ、角欠けはあまり気にならないのですが、幅を指定できるようにした場合、さすがに目立つので対処することにしました。
対処法は上記のような4つ目の境界タイルを用意して、
- 左、上が同じ、かつ左上のタイルと異なる場合に「4」
というルールを加えれば(たぶん)大丈夫です。
2方向ならば4通りのあるパターンのうち、1パターンのみ3方向目を考慮するので「2.25方向」と書きましたが‥‥これ、絶対一般的じゃないですよね?
これを4方向、8方向と発展させた先に、いわゆるオートタイルがあるのかなと思います。
境界タイルの自動生成
境界タイルですが、単色タイルならまだしも通常のタイルに対応するものを用意するのは結構大変なので自動生成するようにしました。
試行錯誤の結果、以下のようにしています。(タイルも縦に並べるように変更しました)
上記のように、境界か否かのフラグを左上から右上、左下、右下の順に並べて、元タイルからコピーする際に、境界色か元タイルの色かを選択していく感じです。
フラグの選択は(境界線の幅が3の場合)、xが3以上なら1を、yが3以上なら2を足したもの(Luaのリストは1-originなのでさらに1を足す)を添え字に指定します。
local orgc=sget(sx+xx,sy+yy)
local isb=PTN[nn][(xx<bw and 0 or 1)+(yy<bw and 0 or 2)+1]
sset(sx+xx,nn*8+sy+yy,isb and bc or orgc)
コードでいうと上記の部分です。
う、うーん、もっと効率的にもできる気がしますし、もっと分かりやすくできる気もします。
ただ、現在4つのエリアに分かれていますが、これを全部 for 文で回すと大変だった(実際に書いた)のでこれくらいがいいかなあと(今は)思っています。
例えば、4方向に対応したいと思って現在の4エリアを9エリアに増加させても、xで0,1,2、yで0,3,6足す、のような変更で対応できる(気がします)
他にいい方法がありましたら教えてください!
後、元々の目的である「国盗りす」に適応できるように「2種タイルのみモード」を追加しました。
(背景タイル以外は、タイル番号にかかわらず、もうひとつのタイルで表示。境界判定はそのまま)
最後にコードを載せておきます。
PTN={
{true,false,true,false},
{true,true,false,false},
{true,true,true,false},
{true,false,false,false}
}
-- common function from TIC-80 wiki
function sset(x,y,c)
local addr=0x4000+(x//8+y//8*16)*32
poke4(addr*2+x%8+y%8*8,c)end
function sget(x,y)
local addr=0x4000+(x//8+y//8*16)*32
return peek4(addr*2+x%8+y%8*8)end
-- my function
function bordertilef(fidx,nums,leftup,bcolor,bwidth,only2,bgtile,tilesync)
local id,n,pn=fidx or 0,nums or 16,leftup and 4 or 3
local bc,bw,bg=bcolor or 0,bwidth or 1,bgidx or 0
for i=id,id+n-1 do
local sx,sy=i%16*8,i//16*8
for nn=1,pn do
for yy=0,7 do
for xx=0,7 do
local orgc=sget(sx+xx,sy+yy)
local isb=PTN[nn][(xx<bw and 0 or 1)+(yy<bw and 0 or 2)+1]
sset(sx+xx,nn*8+sy+yy,isb and bc or orgc)end end end end
if tilesync then sync(1,0,true) end
return function(tile,x,y)
local Ltile=mget((x-1)%240,y%136)
local Utile=mget(x%240,(y-1)%136)
local LUtile=mget((x-1)%240,(y-1)%136)
local dLeft,dUp,dLU
if bgtile then
dLeft=((Ltile==bgtile or tile==bgtile) and tile~=Ltile)and 1 or 0
dUp=((Utile==bgtile or tile==bgtile) and tile~=Utile)and 2 or 0
dLU=(leftup and (dLeft==0 and dUp==0) and(LUtile==bgtile or tile==bgtile) and tile~=LUtile)and 4 or 0
else
dLeft=(tile~=Ltile)and 1 or 0
dUp=(tile~=Utile)and 2 or 0
dLU=(leftup and dLeft==0 and dUp==0 and tile~=LUtile)and 4 or 0 end
if only2 then tile=(tile==id)and id or id+1 end
return tile+(dLeft+dUp+dLU)*16 end end
testinit=function()
rm={
bordertilef(0,16,true,0,2),
bordertilef(0,2,true,0,2,true),
bordertilef(0,2,true,0,2,true,0) }
i=0
end
testinit()
function TIC()
map(0,-1,30,18,0,-4,-1,1,rm[i])
if btnp(0,1,30) then i=(i+1)%4 end
end
これだけ書いておけば、一ヶ月後の自分でも一応理解できる‥‥はず?
これが何の役に立つかと言うと‥‥そう、グーグル 8bitマップを境界線付きで見ることができた、かも?