Tech カテゴリのイメージ

途中で追われる側になるブロック崩し「ブロック崩さない」を作った

ブロック崩しをしていると、ブロックの側はどう思っているんだろうと考えることがある。並んで待っているだけで、当たれば消える。それを反転させたゲームを作った。

ブロック崩さないを開く

前半と後半で立場が入れ替わる

前半はふつうのブロック崩しだ。画面右上の表示も「ブロック崩し」とだけ出ている。何も仕掛けは説明されない。

11個壊すか、26秒経つと転換が始まる。ボールが失速して止まり、残ったブロックが小刻みに震えだす。タイトルの表記が「ブロック崩さない」にグリッチして、ボールが砕ける。

後半は逃げる側になる。ブロックが列から剥がれてバーを追いかけてくる。下に抜けても上から戻ってくるし、時間とともに数が増えて速くなる。バーは細くなっていく。当たったら終わりで、生存時間がスコアになる。

追ってくるブロックは時々つぶやく。「まだ崩すの」「壁じゃなかったんだ」「そろそろでしょ」といった短い文で、経過時間に応じて出るものが変わる。ゲームオーバーのときにも一言が出る。

1次元では原理的に逃げられなかった

最初の実装では、後半もバーは画面下部を左右に動くだけにしていた。ブロック崩しのバーなのだから当然そうだろうと思っていた。

これが完全に失敗だった。回避操作をする自動プレイヤーで測ったところ、何度やっても6秒台で終わる。難易度カーブとして用意した「バーが細くなる」「増援が来る」「速くなる」が一度も効かないまま毎回終了していた。

原因は考えれば当たり前で、1本の線の上しか動けない相手に対して、2次元を自由に動ける追跡者が複数いると、線上のどこにも安全な場所がなくなる。追跡者が線に到達した時点で詰みになる。

追跡を速くして曲がりにくくすれば、行き過ぎて隙ができるはずだと考えて数値を振ってみた。結果は逆で、速度70で6.7秒だったものが、速度190では4.6秒とかえって短くなった。速いほど早く線に到達するだけだった。

そこで後半だけバーに上下移動を与えた。壁をやめたのだから床に張り付いている必要もない、という理屈で、演出の趣旨とも合っている。あわせて後半に入った瞬間にバーを112pxから72pxへ細くした。壁ではなくなったので細い、という説明がつくうえ、当たり判定が小さくなって逃げやすくなる。

自分の測定コードのほうが間違っていた

上下移動を入れても8秒台のままだった。おかしいと思って死ぬ直前の座標を記録したら、バーが右下の角に貼りついたまま数秒間まったく動いていなかった。

自動プレイヤーの作りが悪かった。最も近い追跡者から遠ざかる方向を毎フレーム選ぶ、という素朴な方式にしていたので、角に入ると「そこから動くとかえって近づく」という判断になって出られなくなる。局所最適に嵌っていただけで、ゲームの側の問題ではなかった。

盤面全体から逃げ場を探して、そこへ向かって進む方式に書き直したら11秒台になった。さらに増援の間隔と速度上昇を振り直して、中央値17.5秒(12秒から23秒の範囲)に落ち着いた。人が操作すればもう少し伸びると思う。

ゲームバランスを機械で測るときは、測定側の強さが天井になる。弱い自動プレイヤーで測ると、難しすぎるゲームと、測定が下手なだけのゲームの区別がつかない。今回はそれを2回やった。

実装の話

例によって外部ライブラリなしの単一HTMLで、描画はCanvasに直接書いている。

・追跡は、目標方向の速度ベクトルへ徐々に寄せる方式。寄せる速さを下げると行き過ぎるようになる ・個体ごとに速度の倍率を持たせて、全部が同時に到達しないようにしている ・後半の残像は、毎フレーム背景を塗りつぶす代わりに半透明で重ねることで出している ・ビネットはバーの位置を中心にした放射グラデーションで、時間とともに内側が狭くなる ・走査線は3pxおきの黒い横線、赤い脈動は全面に薄い赤を重ねているだけ

生成AIについて正直なところ

もともとは追跡ブロックのつぶやきとゲームオーバーの一言を、その場で生成する構想だった。ただこのサイトのアプリは外部通信をしない単一HTMLとして置いているので、APIキーを埋め込むと公開ページに認証情報を晒すことになる。そのため今回はあらかじめ書いた文章から、経過時間と結果に応じて選ぶ方式にした。

サーバー側に中継を置けば生成は可能になるが、遊ばれるたびに費用が発生する。アクセス解析の集計をあえて言語モデルなしで組んだのと同じ理由で、常時動くものにお金が流れ続ける構成は今回は選ばなかった。

まとめ

・前半はふつうのブロック崩し、後半はブロックに追われる側になるゲームを作った ・1次元のバーは2次元の追跡者から原理的に逃げられない。後半だけ上下移動を与えて解決した ・追跡を速くすると逆に簡単に捕まる。速さではなく到達までの猶予が効く ・自動プレイヤーが角に嵌って動かなくなっていたのを、ゲームが難しすぎると誤診した ・調整の結果、生存時間の中央値は17.5秒。ブロック崩さないから遊べる