[話者] 今回は
を学ぼう。
[合いの手] ふむふむ、
_INIT()関数で初期化。_UPDATE()関数は1/30秒おきに呼ばれる。_DRAW()関数は、_UPDATE()が1/30秒以内に完了した場合、その後に呼ばれる。1/30秒以内に完了しなかった場合、呼ばれない。
Sprite Editorでキャラクターも描いたぞ。

カーソルキーでキャラを動かせる。

このソースコード、入力したけど、意味がいまいち分かってない。
x=64 y=64 sprite=1 dir=1 itvl_frame=8 -- interval =1/30sec anim_frame=2 t=0 function input() local pressed=false if btn(0) then x-=1 dir=4 pressed=true end if btn(1) then x+=1 dir=3 pressed=true end if btn(2) then y-=1 dir=2 pressed=true end if btn(3) then y+=1 dir=1 pressed=true end if pressed then sprite=dir+flr((t%(anim_frame*itvl_frame))/itvl_frame+1)*16 else sprite=dir end end function _update() t+=1 input() end function _draw() rectfill(0,0,127,127,13) spr(sprite,x-4,y-4) end
[話者] このソースコードで大事なのはスプライト番号だね。
スプライト(sprite)とは、小さな絵の部品です。
PICO-8では、8×8ピクセルの正方形がスプライトの最小単位です。
スプライト番号は以下のようになっている。

画像一枚にすれば、こうなる。

[合いの手] ふんふん。
[話者]
ソースコードの変数の
sprite これが「スプライト番号」。
dir というのはdirection、つまり「体がどちらを向いているか」のこと。
| dir | 体の向き |
|---|---|
| 1 | ↓ |
| 2 | ↑ |
| 3 | → |
| 4 | ← |
という対応になっているのが画像と見比べると分かる。
if btn(0) then x-=1 dir=4 pressed=true end if btn(1) then x+=1 dir=3 pressed=true end if btn(2) then y-=1 dir=2 pressed=true end if btn(3) then y+=1 dir=1 pressed=true end
というソースコードで、btn(0) から btn(3) までは、カーソルキー ←, →, ↑, ↓ に対応する
| btn(キー) | dir(体の向き) |
|---|---|
| 0(←) | 4(←) |
| 1(→) | 3(→) |
| 2(↑) | 2(↑) |
| 3(↓) | 1(↓) |
というように、体の向きとカーソルキーを一致させるソースコードになっている。
このinput関数、1/30秒ごとに呼ばれて実行されるんだけど、
function input() local pressed=false
毎回 pressed 変数が false になる。
その後、キー入力を確認して、カーソルキーがどれか押されてれば pressed 変数は true になる。
local と付与すると、ブロック(endやelseで閉じられる領域)内だけで有効なローカル変数になる。localがないとグローバル変数になる。
sprite=dir+flr((t%(anim_frame*itvl_frame))/itvl_frame+1)*16
この行はややこしい。カッコの奥のほうから先に解釈されるから、奥のほうから見ていこう。
anim_frame*itvl_frame この変数はソースコードの上のほうで、こう定義されている。
itvl_frame=8 -- interval =1/30sec anim_frame=2
-- の後は、人に読ませるためのコメントで、機械は読まない部分。
フレームというのは、4コマ漫画でいうコマのこと。
PICO-8は1秒に30フレーム(30コマ)表示する。
anim_frame*itvl_frame の変数はソースコード中で変化しないので、要するに 16 と書いてあるのと同じ。
t%(anim_frame*itvl_frame) の
t はtimer変数で、1/30秒ごとに1ずつ増加する。
t%16 は、tを16で割った余り(剰余)を計算する。要するに1/30秒ごとに 0, 1, 2,.., 14, 15, 0, 1, 2,.. という数字のどれかになる。
(t%(anim_frame*itvl_frame))/itvl_frame は、0/8, 1/8, 2/8,.., 14/8, 15/8, 0/8, 1/8,.. という数字のどれかになる。小数で表すと、0, 0.125, 0.25, 0.375, 0.5,.., 1.75, 1.875, 0, 0.125,.. になる。
(t%(anim_frame*itvl_frame))/itvl_frame+1 は、上記の数字に +1、つまり小数だと 1, 1.125, 1.25,.., 2.75, 2.875, 1, 1.125,.. になる。
flr((t%(anim_frame*itvl_frame))/itvl_frame+1) のflrは floor つまり小数点以下を削除するので、つまり 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, .. というふうに 8回ごとに 1 か 2 が出てくる。
flr((t%(anim_frame*itvl_frame))/itvl_frame+1)*16 は上記の16倍、つまり 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16, .. というふうに8回ごとに 16 か 32 が出てくる。
dir+flr((t%(anim_frame*itvl_frame))/itvl_frame+1)*16 は、上記の数字に、体の向きが ↓だったときは +1 、↑だったときは +2、→のときは +3、←のときは +4。
これで、分かったかな?
[合いの手] よく分からないぞ。
[話者] つまりだな、
if pressed then sprite=dir+flr((t%(anim_frame*itvl_frame))/itvl_frame+1)*16 else sprite=dir end
のソースコードは、
カーソルキー押してるときは、
8/30秒ごとに、


カーソルキー押してないときは

ということだ。
[合いの手] はー。そういうことか。
でも、それって歩くとき2パターンしか使ってないってことだよね。
普通は 3パターンあるなら、3パターンを順繰りに表示しない?
[話者] それ、してみると、なんか歩いてる感じにならないんだよなぁ。
anim_frame=3 if pressed then --sprite=dir+flr((t%(anim_frame*itvl_frame))/itvl_frame+1)*16 sprite=dir+flr((t%(anim_frame*itvl_frame))/itvl_frame)*16 else sprite=dir end

[合いの手] うーん、確かにそんな感じも。キャラデザインがあまり良くないのかもなー。
[話者]
ソースコードの残りは簡単だな。
function _update() t+=1 input() end
このコードは、
1/30秒ごとに、
t を1増加させて、
input関数を呼び出している。
function _draw() rectfill(0,0,127,127,13) spr(sprite,x-4,y-4) end
このコードは、
rectfill で画面を全部塗りつぶして、前回描いたものを消している。
spr でスプライトを表示する。そのとき、スプライト番号と位置を指定してる。
[合いの手] うん、分かった。
