スクリーンショット_2019-03-01_19

PICO-8 でロックマン風ゲームVer.1完成

今日で3日目で、今日は5時間くらい時間を使った。一応タイトル画面からクリア画面、ゲームオーバー画面まで遷移するゲームになった。↓こちらに公開している。

こういったアクションゲームは初めて作ったかもしれない。

昔はポケコン(ポケットコンピュータ)という "fantasy" じゃないコンソールを持っていて、それを使ってゲームを作っていた。BASIC という言語で色々なゲームを作っていたのだが、アクション性の高いゲームは速度面で作ることができなくなり、次第に BASIC ではなくアセンブラで実装するようになった。ぼくの持っていたポケコンには Z80 の互換プロセッサが搭載されていた。そのうちゲームを作ることより CPU やハードウェアの面白さに気付き、パソコンでエミュレータを作ってみたりポケコンを解析するような事に時間を注いでいて、ゲームを作ることがなくなった。

ゲーム会社に就職してからは基本的には仕事がゲームづくりなのでゲームを作っているが、小さなゲームを作るとポケコンで遊んでいたときのことを懐かしく思う。

思い出話は置いておいて、このゲームは PICO-8 BBS で公開しているのでソースコードが閲覧できるので、どのように作っているかはご覧いただければよいかと思う。あまりクソコードにならないように気をつけたが、コンソールの制約的に厳しい部分は読みづらいところもあると思う。

PICO-8 で当たり判定

例えば、敵とプレイヤー、弾などの当たり判定のコード。とてもシンプルな実装として、距離を求めて一定距離以内なら衝突していると判断するコードを書いた。

位置ベクトル同士の距離を求める方法は三角形の定理を学習した方であればすぐにわかると思うが、図のように式はとても簡単だ。図の distance (距離)が2つの半径の合計 A.r + B.r より小さければ衝突しているということになる。

しかし、PICO-8 では面倒な問題がある。数値の最大値が整数だと 32767 ということだ。

このように 32767 + 1 はオーバーフローして -32768 となってしまう。そして先程の distance の式を見ていただきたいのだが二乗が存在する。二乗の計算がオーバーフローしない数値の範囲は -181 から 181 となる。つまり dx, dy がこの数値範囲内になければ計算が合わなくなる。これは PICO-8 の数値の仕様だ。

しかし、このようなアクションゲームでは座標が 181 を簡単に超えてしまう。今回はこれを回避するために判定する座標をすべて 1/100 して計算した。つまり circle_clas というクラスの実装はこうなっている。

circle_class = {}
function circle_class.new(x, y, r)
function collided(self, rhs)
 local ax = self.x / 100
 local ay = self.y / 100
 local ar = self.r / 100
 local bx = rhs.x / 100
 local by = rhs.y / 100
 local br = rhs.r / 100
 local dx = ax - bx
 local dy = ay - by
 local distance = dx * dx + dy * dy
 return distance < (ar + br) * (ar + br)
end
return {
 x = x, y = y, r = r,
 collided = collided,
}
end

PICO-8 の数値型は整数ではなく小数も扱えるので 100 で割ることができる。100で割ることで失われる小さな情報は距離比較では誤差なので問題がない。なお distance はルート(sqrt)を使わず半径の二乗と比較しているが、sqrt より掛け算のほうが(おそらく PICO-8 でも)処理が早いからだ。

このような数値の範囲の問題に躓いた方がいれば、値を小さくスケールして処理してみることを検討してみてはどうだろうか。

応援してくださると嬉しいです。よろしくお願いいたします!