LoginSignup
1
1

More than 5 years have passed since last update.

【TIC-80】上下左右ループのタイルマップ

Last updated at Posted at 2018-10-14

「TIC-80」のタイルマップ

TIC-80」には標準でタイルマップ機能があります。マップエディタ(GUI)でタイル(BG)を選択してクリックやドラッグで配置するほかmset(x,y,id)という命令でプログラムから配置することも可能です。

マップエディタでの配置はファミコンの「ロードランナー」や「ナッツ&ミルク(配置方法はこちらが近い)」みたいな感じです。
(若い人には伝わらないかも‥‥)えっと最近のゲームなら、そう、マリオメーカーみたいな感じです。

主な仕様は以下の通り

  • 1つのセルに対し8x8ドットの背景タイル(id:0~255)を設定する
  • ワールドマップは240x136セル (1920x1088 ピクセル)

タイルマップの表示は map 命令で行ないます。
map ([x=0, y=0], [w=30, h=17], [sx=0, sy=0], [colorkey=-1], [scale=1], [remap=nil])

  • x,y は描画を開始する(左上の)ワールドマップ上のセル座標
  • w,h は描画する範囲の横幅と高さ(マップのセル単位
  • sx,sy は(マップ左上の)描画座標(画面上のピクセル単位
  • colorkey は透明にしたい色番号(0~15,-1の場合透明なし)
  • scale は表示倍率(1以上の整数?)
  • remap は‥‥こおるばっく関数??(便利らしいのですがサンプルも見つけられず使い方が分かりませんでした)

タイルマップのループ

ワールドマップは上下左右がループしています。
マップエディタでWORLD MAP表示(タブキーか目玉アイコン(?)をクリック)
右下ワールドマップ.gif
右下.gif

上の画像では表示範囲を表す赤枠は右下にしかありませんが、下の画像ではワールドマップの四隅のタイルも表示されています。
エディタ上だけでなく map 命令で表示させた場合も 240x136セル範囲外のものは反対側に回り込んで表示してくれます。

ただしこれはワールドマップでの仕様なので、それより小さな範囲でループさせたい場合は、map 命令を複数回実行(もしくはマップデータを周辺にコピー)する必要があります(多分)。

で、以前は、ワールドマップの(0,0)に配置した32x32セル(固定)のエリアをループ表示させるために中心と上下左右斜め全てで合計9回 map 命令を呼んでいました。

96x96セル分描画してその内画面に表示されるのは全画面でも 32x17 セル分という。
その後、せめてもう少し減らそうということで常時5回に減らしたりしましたが
表示エリアの大きさ固定、全画面固定だったのでこの度、マップ表示部分を
書き直しました。

実装

loopmap.lua
function lmap(mapx,mapy,mw,mh,sx,sy,colkey,scale)
    local mx,my=mapx or 0,mapy or 0
    local lw,lh=mw or 30,mh or 17
    local xx,yy=sx or 0,sy or 0
    local ck,s=colkey or -1,scale or 1
    return function(x,y,w,h,ox,oy,noloop)
        local x,y=x%lw,y%lh
        local ww,hh=w or 30,h or 17
        local ox,oy=ox or 0,oy or 0
        map(mx+x,my+y,min(ww,lw-x),min(hh,lh-y),xx+ox,yy+oy,ck,s)
        if x+ww>lw and not noloop then
            map(mx,my+y,x+ww-lw,min(hh,lh-y),xx+(lw-x)*s*8+ox,yy+oy,ck,s)end
        if y+hh>lh and not  noloop then
            map(mx+x,my,min(ww,lw-x),y+hh-lh,xx+ox,yy+(lh-y)*s*8+oy,ck,s)end
        if x+ww>lw and y+hh>lh and not noloop then
            map(mx,my,x+ww-lw,y+hh-lh,xx+(lw-x)*s*8+ox,yy+(lh-y)*s*8+oy,ck,s)end end end

testinit=function()
    x,y=0,0
    lm=lmap(0,0,16,16,80,24)
end

testinit()

function TIC()
    if btnp(0,1,30)then y=y-1 end
    if btnp(1,1,30)then y=y+1 end
    if btnp(2,1,30)then x=x-1 end
    if btnp(3,1,30)then x=x+1 end
    lm(x,y,8,8)
end

こんな感じかな?

説明.png

説明のために図を書きましたが、最初からこれを書いてから実装した方が良かった気がします。
(数式部分はパッっと書けた訳ではなく、こうかな?どうかな?みたいな感じで
 違ったら少し変更して‥とかしていたので)

間違いがありましたら、ご指摘お願いします。

使い方としては
lmap(mapx,mapy,mw,mh,sx,sy,colkey,scale)

  • mapx,mapy (ワールドマップ座標)
  • mw,mh (制限幅)

で制限(ワールドマップから切り出すイメージ)して、返り値の命令にさらに
命令(x,y,w,h) で相対座標と表示範囲をパラメータとして与えて実行します。

実行例

以前に紹介したスプライトデータからテーブルに、テーブルから境界線付きマップデータに変換、
と合わせて実行するとこのような感じです。

kabu2.gif

TEIJIRO氏の「すわいん」を思い出しました(伝わる人がいたら嬉しい)

スプライトデータからマップデータを作成しているので、
スプライトをそのまま表示させると(右下)ミニマップになるのがポイント☆
最後に一応全リストを載せておきます。

lmap.lua
min=math.min
-- common function from TIC-80 wiki
function sget(x,y) -- get spritesheet pixel
    local addr=0x4000+(x//8+y//8*16)*32
    return peek4(addr*2+x%8+y%8*8) end

-- my common function
function spr2tbl(idx,w,h,x_offset,y_offset)
    local w,h=w or 8,h or 8
    local ox,oy=x_offset or 0,y_offset or 0
    local sprX,sprY=idx%16*8,idx//16*8
    local tbl={}
    for rown=1,h do
        tbl[rown]={}
        for coln=1,w do
            tbl[rown][coln]=sget((sprX+ox+coln-1)%128,sprY+oy+rown-1)end end
    return tbl end

function area2map(t,colsync,bgcol,ldcol,zerotid,tnum,x_offset,y_offset,dosync)
    local csync=colsync or false
    local ox,oy=x_offset or -1,y_offset or -1
    local bgc,ldc=bgcol or 13,ldcol or 4
    local ztid,tn=zerotid or 0,tnum or 4
    for rown,row in ipairs(t) do
        for coln,num in ipairs(row) do
            local stid
            if csync then
                stid=num*tn else
                stid=num==0 and bgc*tn or ldc*tn end
            local dLeft=(coln==1 or num==t[rown][coln-1])and 0 or 1
            local dUp=(rown==1 or num==t[rown-1][coln])and 0 or 2
            mset(coln+ox,rown+oy,ztid+stid+dLeft+dUp)end end
    if dosync then sync(4,0,true) end end

function lmap(mapx,mapy,mw,mh,sx,sy,colkey,scale)
    local mx,my=mapx or 0,mapy or 0
    local lw,lh=mw or 30,mh or 17
    local xx,yy=sx or 0,sy or 0
    local ck,s=colkey or -1,scale or 1
    return function(x,y,w,h,ox,oy,noloop)
        local x,y=x%lw,y%lh
        local ww,hh=w or 30,h or 17
        local ox,oy=ox or 0,oy or 0
        map(mx+x,my+y,min(ww,lw-x),min(hh,lh-y),xx+ox,yy+oy,ck,s)
        if x+ww>lw and not noloop then
            map(mx,my+y,x+ww-lw,min(hh,lh-y),xx+(lw-x)*s*8+ox,yy+oy,ck,s)end
        if y+hh>lh and not noloop then
            map(mx+x,my,min(ww,lw-x),y+hh-lh,xx+ox,yy+(lh-y)*s*8+oy,ck,s)end
        if x+ww>lw and y+hh>lh and not noloop then
            map(mx,my,x+ww-lw,y+hh-lh,xx+(lw-x)*s*8+ox,yy+(lh-y)*s*8+oy,ck,s)end end end

testinit=function()
    sidx=80
    x,y=0,0
    t=spr2tbl(sidx,16,16)
    area2map(t,true)
    lm=lmap(0,0,16,16,80,24)
end

testinit()

function TIC()
    if btnp(0,1,30)then y=y-1 end
    if btnp(1,1,30)then y=y+1 end
    if btnp(2,1,30)then x=x-1 end
    if btnp(3,1,30)then x=x+1 end
    lm(x,y,8,8)
    spr(sidx,200,100,-1,1,0,0,2,2)
end

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1