読み物 / 開発の話
県がくっつく仕組み — 物理演算の話を一般向けに
都道府県ゲームでは、落とした県が箱の中で転がり、ほかの県に乗ったり、すべり落ちたりします。そして、お隣の県と触れると、地図どおりの形にくっつきます。画面の中で起きているのは、「物理演算」と呼ばれる計算です。この記事では、県が落ちてからくっつくまでに、裏で何が起きているのかを順番に説明します。数式は使いません。
物理演算とは
物理演算は、物の動きを、重さや速さ、ぶつかったときの跳ね返りなどの決まりにしたがって、少しずつ計算していく方法です。ゲームでは、画面を 1 回描き直すたび(多くの画面では 1 秒に 60 回ほど)に、「それぞれの物が少しだけ進んだらどこにいるか」「ぶつかっている物はないか」を計算し、ぶつかっていれば押し返します。これを何度もくり返すと、物が落ちて、転がって、積み重なって見えます。
都道府県ゲームでは、この計算に Matter.js という、ブラウザで動く物理演算のライブラリを使っています。だれでも使える形(MIT ライセンス)で公開されているもので、ゲームのページの中に組み込んであります。
手順 1: 県の形を「へこみのない形」に分ける
物理演算で「ぶつかったかどうか」をすばやく調べるには、形がへこみのない形(凸多角形)であるほうが都合がよい、という事情があります。三角形や四角形のように、どこにもへこみがない形なら、2 つが重なっているかを短い計算で確かめられるからです。
ところが、県の形はへこみだらけです。そこで、1 つの県を、へこみのない小さな形にいくつかに切り分け、それらをくっつけて 1 つの物として扱います。この切り分けには、poly-decomp という別の小さなライブラリを使っています。Matter.js は、へこみのある形を渡されると、このライブラリがあれば自動で切り分けてくれます。
手順 2: 触れたら「どの県が」触れたかを調べる
物理演算は、2 つの物が触れたことを教えてくれます。そのあとに、ゲームの決まりの出番です。くっついたかたまりの中には何県も入っているので、触れているのはかたまりのどの県の部分かを調べ、その県どうしが地図でお隣かどうかを確かめます。お隣のときだけ、くっつけます。
手順 1 で県の形を小さな形に分けておいたことが、ここで役に立ちます。小さな形の 1 つ 1 つが、どの県の一部なのかを覚えておけば、触れた部分がどの県なのかがすぐにわかるからです。
もう 1 つ、遊んでいて気づいた問題がありました。県の形の外側には、見た目を整えるための輪郭の線を描いています。この線どうしは触れているように見えるのに、計算の上ではほんの少しすき間があって、くっつかないことがありました。そこで日本のステージでは、輪郭の線の外側からほんの少し(画面の上で 2 ピクセル)の近さまで、「触れた」とみなすようにしています。
手順 3: 地図どおりの形に並べ直す
くっつくと決まったら、2 つのかたまりを 1 つの新しい物に作り直します。このとき、それぞれの県を、実際の地図と同じ位置関係に並べ直します。東京都と神奈川県がくっつけば、地図の上の東京都と神奈川県の並びのまま、1 つの形になります。新しいかたまりの位置は、2 つのかたまりの重心を広さで重みづけした場所、向きは大きいほうのかたまりの傾きを引き継ぎます。
ここで困ったのは、並べ直した形が、まわりのほかのかたまりにめり込んでしまうことでした。もとの 2 つは触れ合っていただけでも、地図どおりに並べ直すと形が変わるので、近くのかたまりと重なってしまうのです。そこで、新しいかたまりを置く前に、重ならずに箱の内側に収まる場所を、もとの位置から近い順に探してから置くようにしています。少しずらす、片方の県をその場に残す、少しだけ回す、といった候補を順に試し、それでもどこにも置けないときは、かぶってしまった周りのピースのほうを空いている場所へどかします。動かした分は、画面の上では 0.25 秒かけてするっと動かして見せるので、瞬間移動のようには見えません。
手順 4: 積み重なっても落ち着かせる
たくさんの県が積み重なると、物理演算には別の難しさが出てきます。開発の途中では、次のような問題が起きました。
- 止まらずにピクピク動き続ける: 小さな形をたくさんくっつけた物は、回りにくさ(慣性モーメント)の計算が実際より小さくなり、積み重なると回る向きに揺れ続けることがありました。物を作るたびに、回りにくさを形に合わせて計算し直すことで止まるようにしました。
- 重みで少しずつめり込む: 1 回の計算で押し返す力だけでは、上に積まれた重みに負けて、少しずつめり込むことがありました。1 回の描き直しの間の計算を、何回かに分けて細かく行うようにしました(ブラウザ版では 3 回)。落ちる速さなどの見た目は変わりません。
- 深く噛み合って外れない: シャッフルで勢いよくぶつかると、へこみのある形どうしが深く噛み合い、物理の計算だけでは外れなくなることがありました。重なりが一定以上のまま 0.25 秒続いたら、小さいほうを近くの重ならない場所へ動かす「安全網」を入れています。
さらに、物理演算には、止まった物を「眠らせて」計算を省く仕組みがあります。たくさんの物を軽く動かすための大事な工夫ですが、眠っている物どうしの重なりは調べなくなるため、重なったまま眠ってしまうと、そのまま残ってしまいます。都道府県ゲームでは、重なりがあるうちは眠らせないようにしました。
くっつく気持ちよさのために
ここまでの仕組みは、遊ぶ人にはほとんど見えません。見えてほしいのは、「お隣の県が触れたら、ちゃんとくっつく」「くっついたら、地図どおりの形になる」という 2 つだけです。そのために、見えないところで、形を切り分け、触れた県を調べ、重ならない場所を探し、積み重なりを落ち着かせています。
物理演算は、本物らしい動きを手軽に作れる便利な道具です。でも、「本物らしさ」と「ゲームとしての気持ちよさ」はいつも同じではありません。ぴったりくっつく気持ちよさを守るために、物理の計算に少しずつ手を入れていく。それが、このゲームを作る作業のかなりの部分を占めていました。
出典
- Matter.js(へこみのある形を切り分けて扱う Bodies.fromVertices、止まった物を眠らせる Sleeping): Matter.js ドキュメント、Matter.js(GitHub、MIT ライセンス)
- poly-decomp: poly-decomp.js(GitHub、MIT ライセンス)
- 画面の描き直しの回数(多くの画面で 1 秒に 60 回): MDN Web Docs「Window: requestAnimationFrame() メソッド」
- 県の形の元データ: Natural Earth 1:10m 行政区画(パブリックドメイン)
- くっつく判定・置き直し・安全網などの作り: 都道府県ゲーム(ブラウザ版)の作りから