もどる TOP

直角に曲がる弾 (+インタープリターの作り方?)

 自機とY軸が重なると、自機のほうに直角に曲がってくる弾を書いてみた。どっかで見たことあるんだけど、どこで見たのか忘れちゃった。(はっぱカッター撃ってるのは気にしないで)

直角に曲がる弾

 敵は、真っすぐ下 (270度) の方向に1wayで弾を撃つ。すると弾はフレームごとに自機 (プレイヤー) の位置と自身の位置をチェックして、Y座標がプレイヤーの位置以下になったら、プレイヤーがいる方向 (左なら180度、右なら0度) に曲がる。曲がった瞬間に減速して、7フレームごとに7回まで加速しながら抜けていく……のだが

 中身が今こうなってます。1枚目が敵の撃ち方、2枚目が敵弾の動き方。

敵の撃ち方
敵の撃ち方
敵弾の動き方
敵弾の動き方

 うははは!!! 何これ?? 謎言語??

 もーーーー完全に自己満足なんだけど、JavaScript内でこの謎言語の文字列を超単純な構文解析して、こないだスクショ貼ってたやつに動的に変換して実行する仕掛けを作ったのだ。もう、あれ書くのも面倒くさくなったからだ。テンプレートリテラルを使ってるから、渡した変数も${delay}とかで組み込めるぞ。

 この呪文を改行で区切って1行ずつにバラし、行ごとに先頭の単語を命令として解釈して、残りの単語をパラメータとして解釈して、こないだの呪文の形にゴリゴリ変換したあと、最後にJavaScript内で文字列をコードとして実行できるeval()でドカーンだ。うあぁ。

 いや、こんなの介したらそれだけ処理は遅くなってしまうんだけど、実際にはステージ開始時の読み込みのタイミングで全部実行するはずだからゆるされる。メンテしやすさとトレードオフ (※『解釈済み』のコードを吐き出させてそれをコピペできる作りにできたらいいんだけど)。

インタープリターの作り方?

 それでは一昨年くらいの私にこういうのの超絶初歩を教えてやんよ。

 まず、こういう↓怪文書があるとする。ちなみにこれは特に何かの言語ではなくて、説明のための概念である。

怪文書1
nantoka 1
nantoka 2
nantoka 3

 ここでは、これを1行ずつ解釈して何かをするのが目的だ。なので「いま何行目?」を常に覚えておき、1行ぶんの処理を完了するたびにそれを1ずつ増やしていくのだ。その存在をここでは『行ポインタ』と呼ぶ。「行ポインタがある場所をどんどん実行していく」と表現するのが正しいかな。

 こんな単純なのは上から順番に実行していくだけだから、何も言うことない。nantokaが何だか知らないが、1行ずつ処理して、行ポインタが最後に到達したらそれで終わりだ。

 次にこういう怪文書があるとするぞ、

怪文書2
nantoka 1
if (x > 10) {
	nantoka 2
}
nantoka 3

 ifがきたぞ。この例において、ifは丸カッコ()内の条件がtrue (真) ではなかったとき、ぐにゃカッコ{}内の処理をスルーせねばならない。

 よって、x > 10が何であるかはともかく、その結果がtrueだった場合は、普段通りに行ポインタをひとつ進める。と、次の処理では3行目のnantoka 2が実行される。

 そしてfalse (偽) だった場合は、行ポインタをビューンと}の次の行まで進め、ぐにゃカッコ内を飛ばす。と、次の処理では5行目のnantoka 3が実行される。

 これだけならやはりそんなものだ。ただ、次の例の場合もある。

怪文書3
nantoka 1
if (x > 10) {
	nantoka 2
	if (y < 10) {
		nantoka 3
	}
	nantoka 4
}
nantoka 5

 ifがネスト (入れ子・ifの中にif) になってるぞい。これだと2行目のifがfalseだったときに、行ポインタを機械的に『次』に出現した}の次の行に進めてしまうと、行き先は7行目のnantoka 4。ちゃんとスキップできてないぞ!?

 実際にはネストが何重になるかもわからない。つまり、スキップ中に新たな{を通過した場合は、その数だけ}を無視しなければならない。スキップ中はネストの深さも覚えておくということだな。

 あとはループ処理だ!! 次の怪文書を見よ。

怪文書4
nantoka 1
for (5かい) {
	nantoka 2
}
nantoka 3

 ここではforのぐにゃカッコ{}内を5回繰り返すことになっている。つまりforがきたら、次に}が現れた時点でforの行まで戻る。そして「終わった?」かどうかを判定し、終わっていなければ行ポインタをひとつ進めて、再度ループ内に突入する。終わっていたら}の次の行まで行ポインタをビューンと進めて、ループを終わるのだ。

 もちろんforもネストするし、ifと一緒に出てくる場合もあるぞ。

怪文書5
nantoka 1
for (5かい) {
	nantoka 2
	for (100かい) {
		nantoka 3
		if (x > 999) {
			nantoka 4
		}
	}
	nantoka 5
}
nantoka 6

 ifと同じように、forを開始してからのネストの深さを覚えておき、同じ高さに戻れるように気をつけるのだ。

 ところでぱっと見、}ifのものであるかforのものであるかは分からないが、それは実際にはどうでもいいことだ。とにかく{が出てきたらネストが深くなるというのは変わらないからな。

 ほかにもifがfalseの場合に実行したいものをelseとして書きたいとか、ループを強制的に抜けるbreakをやりたいとか言いだすとルールが増えるが、基本的にはifforでやったことの応用なので大丈夫だと思う。

サイドバーを表示する
ブログ
ShortCircuit
ShortCircuit
花火大会
天使
去る512時間前、キリウ君は折れてない千歳飴を渡してきて、ぼくが折るよう仕向けた。1024時間前、彼はこの世のものではないハッシュアルゴリズムでひとりブロックチェーンを始めていた。