[話者] 今回は
を学ぼう。
[合いの手] ふむふむ、
_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秒ごとに、
か
を交互に表示する。体の向きにしたがって、横4つ並びのどれか1つのスプライトを表示するんだ。
カーソルキー押してないときは のうち、体の向きにしたがって、横4つ並びのどれか1つを表示する。
ということだ。
[合いの手] はー。そういうことか。
でも、それって歩くとき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
でスプライトを表示する。そのとき、スプライト番号と位置を指定してる。
[合いの手] うん、分かった。
[話者] 今回のソースコードはこちら。