INWAN'S LABO

PICO-8の付属デモの「api.p8」にはPICO-8の基本的な処理が使われています。これらを理解できるとゲーム開発がかなり楽になるので詳しく見ていきます。

デモプログラムを上から順番に解説していきます。

画面のクリア

cls(1)

cls()は画面に表示しているものをすべて消す処理です。

引数に色番号をつけるとその色で塗潰した状態になります。

カメラの操作

camera() 
if (btn(❎)) then
 camera(cos(t()/6)*20,0)
 clip(4,16,120,96)--x,y,w,h
end

camera(x, y)は表示エリアを操作します。

x, y座標を指定するとその位置が画面に表示されます。

引数を無しにするとリセット(0, 0)されます。

上の例ではボタンを押したときにカメラが横に揺れ動きます。

t()はtime()と同じでpico-8起動から経過時間を取得できます。経過時間を角度に使ってcosで揺らしています。

clip(x, y, w, h)は描画エリアを指定するようです。

マップの表示

map()

map( celx, cely, sx, sy, celw, celh, [layer] )はマップを描画します。

celx, celyは作成したマップのセル座標、sx, syは画面上の座標、celw, celhはマップの幅高さ(セルの数)、layerはスプライトにフラグをつけてるときに機能するようです(デフォルトは0)。

引数無しだとすべて表示になるようです。

塗潰しパターン

fillp(0b1000010000100001)
circfill(64,160,52,0x4c)
fillp()

fillp()を使うとcircfill()、rectfill()の塗りつぶしにパターンを使った塗りつぶしを指定できるようです。

4ドットの横線が4本重なって4×4のセルを作っているイメージで8進数または16進数で指定します。

circfill()、rectfill()の色は2色指定できて2色の場合は16進数で指定することができます。fillp()はこの16進数(例:0xa5)で指定した2色の上部分が1(色:a)、下部分が0(色:5) としてパターン模様を作ることができます。

fillp(0b0011001111001100.1)みたいに「.1」があると1の所は透過します(16進数では.8)。
fillp()の引数無しだとリセットされます。

文字の扱い

num=8
str="hello "
str..="from api.p"..num
str_len=#str
  
-- print: str,x,y,col
print(str, 64-str_len*2, 20, 7)

「..」ピリオド2つは前後の文字をつなぐ役目があります。

上の例ではstrに”hell “を入れて、そこに”from api.p”とnumの中身の「8」とをくっつけて一緒に入れてます(「hell from api.p8」になります)。

#strの「#」は配列の数を出すときに使います。

print(str, 64-str_len*2, 20, 7)はstrの中の文字列を中心(64)から文字の数×2ドット引いた位置(1文字4ドットなので文字の表示幅の半分を中心からずらした位置)に文字を表示しています。

テーブルの使い方

tbl={"a"} -- single element
  
add(tbl,"b") -- add to end
add(tbl,"d")
add(tbl,"c")
del(tbl,"d") --remove by value
  
-- iterate over the table
-- (draw letters bottom left)
cursor(2,104,5) -- x,y,col
foreach(tbl,print)
  
-- another way to iterate
cursor(123,104,5)
for i in all(tbl) do
 print(i)
end
  
-- iterate with a for loop
-- starts at index 1! (not 0)
tbl={"ヒ゜","コ","◆"}
  
for i=1,#tbl do
 print(tbl[i],2,  10+i*6,13)
 print(tbl[i],114,10+i*6,13)
end

最初の部分はテーブルtblを作ってadd()で追加、del()で削除しています。

cursor()はprint()で表示する場所を指定しています。

foreach()はテーブル用の繰り返しで、第一引数に指定されているテーブルの要素を一つ順番に取り出して、第二引数の関数を実行します。

その下の2つあるfor文はテーブルの要素の数だけ繰り返す別の書き方です。

透過色の変更

-- draw sprites
palt(2,true) --draw transparent
palt(0,false)--draw solid (eyes)
spr(2,48,32,4,4)

透過色とは重ねて画像を表示したときにその色だけ表示されずに下の画像が見える透明な色です。

PICO-8の透過色はデフォルトでは黒ですがpalt()で指定した色をtrueにすると透過色にすることができます。falseだと不透過になります。上の例では 深紫色(2)が透過色になって黒(0)が不透過になっています。

画像の伸縮・拡大・反転

w = cos(t()/2) * 32
  
-- draw back sides indigo
if (w < 0) pal(7,13)
  
--[[
sspr: stretch sprite
■ first 4 parameters specify
  the source rect (x,y,w,h)
■ last 4 params specify the
  rectangle to draw (x,y,w,h)
--]]
sspr(16,0,32,32,
    24-w/2,32,w,32)
-- re-use w to mean height
-- for vertical spinning
sspr(16,0,32,32,
    88,48-w/2,32,w)

pal()

画像表示域の幅・高さを変えることで画像の伸縮や反転を行えます。

変数wは幅(高さにも使ってる)が経過時間に合わせて計算されています。wがマイナスになったときpal(7, 13)で7番の色が13番の色に変更されています。

sspr()は最初の4つの引数がスプライトシートから取り出す座標と大きさです(スプライトの番号ではない)。そして次の4つが表示する場所と大きさです。表示する際の大きさが元の大きさと違った場合に自動で拡大・縮小されます。大きさがマイナスになった場合は反転されます。

pal()は引数無しだとパレットをリセットします。

2重ループと入力チェック

for pl=0,7 do
 for b=0,7 do
  sx=57+b*2
  sy=70+pl*2
  col=5
  if (btn(b,pl)) col=b+7
  pset(sx,sy,col)
 end
end

PICO-8は複数人でもプレイできるらしくその入力チェックができます。

変数plはプレイヤーでbはボタンを意味していて、プレイヤーごとに一列ずつボタンの状況を表示するようになっています(画面中央にある点々のとこ)。ボタンを押すと対応する場所の色が変わります。

30FPSか60FPS

function _update()

_update()は30FPSですが_update60()を使えば60FPSになるようです。

もう一つのボタンチェック関数

if (btnp(🅾️)) then
 sfx(0)
end

ボタンを押すと音を鳴らす処理です。ただしbtn()ではなくbtnp()が使われています。

btnp()は前のフレーム押されていないときだけtrueを返します。前のフレームに押されていたらfalseです。なので押しっぱなしで連射になることを防げます。

ただし、15フレーム以上押しっぱなしにすると4フレームごとにtrueになります。方向入力などで使いやすいのかもしれません。

音楽の再生

music(0)

指定した音楽を再生します。

メニューアイテムの追加

menuitem(1, "play ssfx", 
 function()
  sfx(3)
 end
)

Enterを押したときに表示されるメニューに新しいメニューを追加できます。

引数は表示させる場所(1~5。でも2番目にしか表示されないんだけど。。)、表示する文字列、コールバック(押したとき実行する処理)です。

 

★筆者がPICO-8で作ったゲームはこちらで遊べます。