2023年11月3日金曜日

世界地図パズルを作った

Web 上で遊べる世界地図パズルを作ってみました。 普通の世界地図パズルと違って、なんと 12 レベルもあります。 レベル 9 くらいまでは子供向きで簡単ですが、レベル 10 になると大人でも難しいです。



どの SVG が良い?

世界地図の SVG はかなりたくさんあるので、一番良いものを選ぶのに苦労しました。 結論だけ言えば、以下のリンクの中で一番上にある File:BlankMap-World-Flattened.svg を利用しています。 世界地図は以下に注意して選びました。
  1. 球体状に歪んでいない
  2. 南極・北極はあったほうがいい
  3. なるべく特徴は残っているほうがいい
特に 3 についてですが、アフリカのヴィクトリア湖に着目して欲しいです。 ほとんどの地図では国境で四角に切ってしまっており特徴が失われていますが、国の特徴を学ぶ際には、湖の情報は残っていたほうが良いです。 またこのような特徴はなるべく残っているほうが、ゲームとしても面白いと思いです。

pan/zoom

大国と比較して小国はさすがにパズルで穴埋めしにくいです。 そのため pan/zoom できるゲームにしました。 HTML 要素の pan/zoom の実装はひさびさにものすごくハマったので、メモも残しておきました。

ちなみに pan/zoom だけでは 2本指での pinch zoom はできないので、これも自分で実装する必要があります。 fabric.js の実装は Pinch to Zoom all Canvas Objects #2658 が参考になります。 DOM の実装は、マルチタッチに注意するべきところはたくさんあるものの、 TouchEvent に 2本指の距離を測定する値 scale がある ので、 scale の変化を見ながら zoom すれば割と簡単に実装できます。 といってもマルチタッチを考慮すると色々考えることがあり、やはり大変でした。 あまりにつらかったので、もう pan/zoom, pinch zoom は実装したくない…。

バチカン市国?

いくら pan/zoom に対応しても、バチカン市国などは点サイズなので、パズルにするのは無理だよなあ、と思って色々な世界地図パズルを確かめてみました。 結論から言えば、やはり面積が小さすぎる国をパズルにしているゲームはなさそうです。 ちなみに File:BlankMap-World-Flattened.svg には面積の小さな国がアノテーションされているので数えてみたところ、 約 150 カ国以外は強調表示しないと地図上で確認しにくい大きさと定義されていました。 ちなみにくもんの世界地図パズルはさらに少なく 85ピースです。

どれくらいのピース数が良いのだろうと思い、国の面積順リスト と実際の地図を比べてみると、 キルギス (85位) は割と大きい国です。 85位までに限定すると韓国、北朝鮮、ネパール、ブルガリア、キューバなどがなくなってしまうことが気になりました。 特に韓国は面積が小さくても経済大国なので、消してしまうのは世界を認識するためのパズルとしてはちょっとよろしくないかも。 ただいくら頑張ってもシンガポールはどうしようもないので、限界はあります。 File:BlankMap-World-Flattened.svg の定義をそのまま使うのが良さそうです。 ちなみにデンマーク領のグリーンランドはピースとして利用し、フランス領のギアナはピースから除外しています。 40〜150 くらいの間で地域別にプレイできると良いかもと思って機能を追加しました。

GeoJson?

SVG で作っている時に、GeoJson ベースの実装はどうなのだろうと、ふと思いました。 たとえば geo-mapsworld-geojson などが使えます。 ただ GeoJson だと地図上にレンダリングするので、地図 API に実装が引きずられる問題があり、API によっては地図に解答が載る問題などを制御するのが難しい。 地図 API はどれも OpenGL などで実装されており、また一般的に商用で改良は難しいです。 サービス終了リスクなどもあるので、現状では SVG のほうが楽かなあ。

改めて思ったのは GeoJson をレンダリングするだけでサービスに依存しない静的なライブラリって、需要がないせいか見当たりませんね。 需要の割に難易度が高いのも理由の気がします。 SVG と panzoom あたりの機能を組み合わせれば、もっとオープンで静的な地図 API が作れる気もしました。 地球儀のような表現は Three.js でテクスチャとして読み込めばできそう。 Google Maps みたいな平面表示の infinite loop は、同じ SVG を横に 3つ並べて一定以上スクロールしたら座標を戻したりするのが良いのかなあ。 それともトーラスで後ろを表示しなければいいのか。いつか遊びで作ってみるかも知れません。 追記: ar-globe これ良いかも。 他にも MapLibre などでも 外部 API なしで作れそうですね。そのうち 3D もできるようになりそう。 ただ Map.addSource() した後に活用が難しそうだな…。

意外と色々な知識確認ができる

だいたい完成してから遊んでみると、色々と感じることがありました。 まずはどう考えても大きな国から並べていくほうが簡単で、自然と面積ランキングを覚えられます。 最初にピースをばら撒かずにプレイすると大きさ順とかを処理しにくいのが欠点かな。 上位 40件ほど埋めていくとだんだん難しくなってきます。 ヨーロッパの国々は意外と小さいので難しい。

そんな時は国名が書いてあると地域が予想できたりして、自分の知識を確認できそう。 難しい国がヨーロッパと北米・南米の中間・アフリカの西あたりに集中しているので、ピースはばら撒いても大丈夫な印象です。 大航海時代の影響を感じますね。 世界全体に難しい国があるとピースの移動が大変になる可能性があるのですが、そうではなかった。 80位くらいから面積が減ることにより、特徴が減ってきて難しくなるので、市販のピース数はなんとなく頷けます。 また最終盤になると、残っているのがどこかわからなくなることがあるので、国名や地域のヒントがあると良いかもと思い、機能を追加しました。

久々に実装を苦労したアプリです。

0 件のコメント: