君のいる場所
1 ココロの地図
ココロの地図は、アニメ ONE PIECE のオープニングテーマソングの曲名である。
有名なアニメなので知っている諸氏は多いと思う。主人公と仲間たちは海賊であり、航海しながら冒険の物語を紡ぐ。この物語に限らないが、登場人物がいる場所(位置)を押さえる事は、物語を
語る上で大きな要素となる。登場人物が自分のいる場所が分からなくなったとしても、客観視する作者にとっては明確に登場人物のいる場所を知っていなければならない。さもなければ、辻褄の
あわない場面が展開されるだろう。
ゲームにおいては、プレイヤーが客観視できる視点を提供しなければならない。将棋ゲームなら盤面と盤面上の駒、そして対戦者の双方の持ち駒を表現する必要がある。当文書が対象とする ゲームは、架空の惑星を世界としている。惑星を客観視するための視点を提供するには地図が適しているだろう。地図と言えば、google map が思いつく。これの実装がどのようになっているかを ちょっとだけ覗き見して、地図を表現する方法を探ってみようと思う。
覗き見するための地図の実験用ソースを作成した。body タグの中に div タグがあり id="map_block" としてある。
このブロックを指定して渋谷駅周辺地図を表示した。左側の図のような地図が表示される。var map = new google.maps.Map(document.getElementById("map_block"), myOptions); の呼び出しにより
id="map_block" に内包される地図を表示するためのエレメントが動的に生成される。下記のソースは firefox のデバッグ機能を利用して動的に生成された部分の一部を表している。
見やすくするために重要と思われない部分は中略としてある。またコメントを付加してある。加工前の map_block の
内包エレメント(初期表示)も参考にして欲しい。
地図をマウスで引きずると位置が移動される。z-index:1 と z-index:4 の div の位置が left: -324px; top: -287px; に変化した。右側の図が移動後を表している。おそらく z-index:1 の ブロックに地図画像を取り込んでいると推測した。そこで地図の実験用ソースでは info ボタンで gm-style の内包エレメントを追って z-index:1 の内包情報を表示させてみる。次節では、推測が 正しいのか検証してみよう。
ゲームにおいては、プレイヤーが客観視できる視点を提供しなければならない。将棋ゲームなら盤面と盤面上の駒、そして対戦者の双方の持ち駒を表現する必要がある。当文書が対象とする ゲームは、架空の惑星を世界としている。惑星を客観視するための視点を提供するには地図が適しているだろう。地図と言えば、google map が思いつく。これの実装がどのようになっているかを ちょっとだけ覗き見して、地図を表現する方法を探ってみようと思う。

地図をマウスで引きずると位置が移動される。z-index:1 と z-index:4 の div の位置が left: -324px; top: -287px; に変化した。右側の図が移動後を表している。おそらく z-index:1 の ブロックに地図画像を取り込んでいると推測した。そこで地図の実験用ソースでは info ボタンで gm-style の内包エレメントを追って z-index:1 の内包情報を表示させてみる。次節では、推測が 正しいのか検証してみよう。
<div id="map_block" style="width: 400px; height: 400px; position: relative; overflow: hidden;"> <!-- 1) map_block に内包される最初の div 要素 --> <div style="height: 100%; width: 100%; position: absolute; 中略> <!-- 2) class="gm-style" の div 要素 --> <div class="gm-style" style="position: absolute; 中略 z-index: 0;"> <!-- 3) 重なる div ブロックを内包する div 要素 --> <div style="position: absolute; left: 0px; top: 0px; height: 100%; width: 100%; 中略 > <!-- 4) 重なる div ブロック z-index:1 マウスで移動すると left と top が変化する --> <div style="position: absolute; left: 0px; top: 0px; z-index: 1; width: 100%;"> ~ 中略 ~ </div> <!-- 5) 重なる div ブロック z-index:2 --> <div style="position: absolute; left: 0px; top: 0px; z-index: 2; 中略></div> <!-- 6) 重なる div ブロック z-index:3 --> <div style="position: absolute; left: 0px; top: 0px; z-index: 3; 中略></div> <!-- 7) 重なる div ブロック z-index:4 マウスで移動すると left と top が変化する --> <div style="position: absolute; left: 0px; top: 0px; z-index: 4; width: 100%;"> ~ 中略 ~ </div> <iframe style="visibility: hidden; z-index: 0; position: absolute; 中略></iframe> </div> ~ 中略 ~ </div> </div> </div>
2 君は何処にいる?
前節の検証として地図画像のありかを探っていこう。前節の info ボタンで出力したz-index:1の内包エレメントを
掲載しておく。思った通り img タグが内包されている。
左図は、わかりやすくするために img タグに境界線を加えたものである。青い境界線は可視範囲にある部分で、赤い境界線は重ね合わせの画像である。どうやら 256px の正方形のタイルを張るように
しているようだ。ちなみに地図を移動すると、タイルが増える。この様子を示す事は割愛するが、赤い境界線部分のタイルが6枚になった。
何故に、この様な実装にしてあるのか?あいにく凡人の私には天才たちの考えはわからない。google map の javascript を解析する労力を10年もかければ、私にも天才たちの片鱗に触れる事は 可能かもしれないが、それは止めておく。だから推測の域での話になるが、地図の移動(スクロール)や拡大や縮小を行った時に、視覚的に利用者にストレスを感じさせないような、手法がとられている と思われる。青い境界線部分を窓とすると、窓を垂直に上に移動した(実際の操作は地図を下へひきずる)時に2枚のタイルが不足する。下側のタイルは既にあるので読み込む必要はない。常に不足分を 補えば良いと言う事だろう。
さて、少しだけ覗き見した google map の実装から分かった事は、窓を固定として、窓に映し出す背景を動かすと言う事だ。背景の位置は窓の左上からの相対座標とし、left, top の属性で指定する。 この手法は色々な場面で適用できるだろう。例えば、RPGゲームなら主人公が動き回る地形を背景にして、主人公の移動に合わせて地形をスクロールする等である。この考え方を踏襲する実装として、 必ずしも div ブロックや img タグを重ねる必要はない。div ブロックを窓として、そのブロックに background 系の属性を指定し background-position で相対位置を指定する事でも可能だ。
当文書が対象とするゲームは、仮想世界(惑星)である。google map のように実世界を表現するする必要はない。なるべく実装が楽なようにしたい。したがってタイルを張っていくような手法でなく background 系の属性で制御するものとする。この惑星では東経のみを用い基準は地図画像の左端とする。また北緯はなく南緯のみとし基準は地図画像の上端とする。さらに24分割制を用い、 東経何時何分何秒、南緯何時何分何秒として位置を表現する。データとしては地図画像の左上からの位置をピクセル単位で持つ。これで地図位置の仕様は決まった。次節では、この仕様を具現化する 為にどうするかを考えて見たい。

何故に、この様な実装にしてあるのか?あいにく凡人の私には天才たちの考えはわからない。google map の javascript を解析する労力を10年もかければ、私にも天才たちの片鱗に触れる事は 可能かもしれないが、それは止めておく。だから推測の域での話になるが、地図の移動(スクロール)や拡大や縮小を行った時に、視覚的に利用者にストレスを感じさせないような、手法がとられている と思われる。青い境界線部分を窓とすると、窓を垂直に上に移動した(実際の操作は地図を下へひきずる)時に2枚のタイルが不足する。下側のタイルは既にあるので読み込む必要はない。常に不足分を 補えば良いと言う事だろう。
さて、少しだけ覗き見した google map の実装から分かった事は、窓を固定として、窓に映し出す背景を動かすと言う事だ。背景の位置は窓の左上からの相対座標とし、left, top の属性で指定する。 この手法は色々な場面で適用できるだろう。例えば、RPGゲームなら主人公が動き回る地形を背景にして、主人公の移動に合わせて地形をスクロールする等である。この考え方を踏襲する実装として、 必ずしも div ブロックや img タグを重ねる必要はない。div ブロックを窓として、そのブロックに background 系の属性を指定し background-position で相対位置を指定する事でも可能だ。
当文書が対象とするゲームは、仮想世界(惑星)である。google map のように実世界を表現するする必要はない。なるべく実装が楽なようにしたい。したがってタイルを張っていくような手法でなく background 系の属性で制御するものとする。この惑星では東経のみを用い基準は地図画像の左端とする。また北緯はなく南緯のみとし基準は地図画像の上端とする。さらに24分割制を用い、 東経何時何分何秒、南緯何時何分何秒として位置を表現する。データとしては地図画像の左上からの位置をピクセル単位で持つ。これで地図位置の仕様は決まった。次節では、この仕様を具現化する 為にどうするかを考えて見たい。
3 六角でございマス
1番目の図は当文書で扱うゲームの地図である。縮小表示してあるが、2496×1968 の大きさである。窓(div ブロック)の背景画像として設定する。この地図の上にプレイヤーの領土を割り当てる。
割り当てる手法として六角形のマスを用いる。長方形(正方形含む)だと見た目がイマイチ(^^)なのでね。
王道的な六角形のマスに挑戦しようじゃないか、って事です。しかし地図画像が長方形なので、六角形のマスも正六角形にはならない。私の身の回りを見渡すと正方形はハンカチと灰皿ぐらいだ。
正方形のディスプレイは見た事がないし、長方形は正方形を含むし、長方形を前提にしておけば正方形にも対応可能なので、長方形の方が都合が良いだろう。
地図移動を検証する為の実験ページを作成した。 実験ページのソースを掲載しておく。2番目の図は実験ページの一部を切り取ったものだ。このページに左右上下ボタンを 配置した。それではボタンによる、background-position の相対位置を指定する処理を考えて見よう。ボタンでの移動処理は算数の苦手な私でも簡単である(^^)。 2496 / 24 は1時間に相当する。これは大きすぎるので、さらに2で割って30分単位とする。よって幅は52となる。同様に高さを計算すると41になる。 水平移動量は 52 × 1.5、垂直移動量は 41 とし、左右上下の移動に応じて background-position を加減算するだけだ。background-position の相対位置は常に六角形マスの中心になる事を 前提(仕様)とする。
次にマウスでの移動を考えてみよう。地図上のマウス押下の位置が、どの六角形のマスの中にあるかを判定する必要がある。どうやら数学の出番のようだ。できるのか俺(^^!) 困った時はネットに 頼るのさ(__!) 参考にしたサイトを上げておく。線分交差判定を用いれば可能のようだ。
まず地図の上でマウス押下された位置をP点とする。次にP点の x / (52 / 2) と y / (41 / 2) の整数値を得る。これは四角形の行列を示す値になる。この行列から六角形のマスの中心点を探索する。 この中心点をC点とする。行列から座標に変換した点(行番号×(52 / 2), 列番号×(41 / 2))は4番目の図にある赤枠の四角形A~Fの左上を示す状態のいずれかになる。赤枠の四角形(A、B、C)の状態に なるのは行番号が偶数の時であり、赤枠の四角形(D、E、F)の状態になるのは行番号が奇数の時である。次に列番号に着目すると赤枠の四角形との関係が以下の数列になる。
1) A,Dの状態になる列番号:0, 3, 6, 9, 12, 15, 18, 21 => 列番号を3で割った余りが0
2) B,Eの状態になる列番号:1, 4, 7, 10, 13, 16, 19, 22 => 列番号を3で割った余りが1
3) C,Fの状態になる列番号:2, 5, 8, 11, 14, 17, 20, 23 => 列番号を3で割った余りが2
さらに赤枠の四角形A~Fに着目すると、赤枠の四角形BとEの検査するC点は一つ、以外は二つある事がわかるだろう。よって検査するC点は最大で2個になる。以上の条件から導き出したC点に ついて、P点とC点を結ぶ線分が六角形の各辺の直線と交差していないなら六角形のマスの中にあると判断する。 上記の考え方を具現化したソースが座標計算クラスだ。マウス押下時のC点とマウス移動時のC点の差が移動量となる。 background-position に移動量を加減算する事で、目出度く地図の移動ができた。
地図移動を検証する為の実験ページを作成した。 実験ページのソースを掲載しておく。2番目の図は実験ページの一部を切り取ったものだ。このページに左右上下ボタンを 配置した。それではボタンによる、background-position の相対位置を指定する処理を考えて見よう。ボタンでの移動処理は算数の苦手な私でも簡単である(^^)。 2496 / 24 は1時間に相当する。これは大きすぎるので、さらに2で割って30分単位とする。よって幅は52となる。同様に高さを計算すると41になる。 水平移動量は 52 × 1.5、垂直移動量は 41 とし、左右上下の移動に応じて background-position を加減算するだけだ。background-position の相対位置は常に六角形マスの中心になる事を 前提(仕様)とする。
次にマウスでの移動を考えてみよう。地図上のマウス押下の位置が、どの六角形のマスの中にあるかを判定する必要がある。どうやら数学の出番のようだ。できるのか俺(^^!) 困った時はネットに 頼るのさ(__!) 参考にしたサイトを上げておく。線分交差判定を用いれば可能のようだ。




まず地図の上でマウス押下された位置をP点とする。次にP点の x / (52 / 2) と y / (41 / 2) の整数値を得る。これは四角形の行列を示す値になる。この行列から六角形のマスの中心点を探索する。 この中心点をC点とする。行列から座標に変換した点(行番号×(52 / 2), 列番号×(41 / 2))は4番目の図にある赤枠の四角形A~Fの左上を示す状態のいずれかになる。赤枠の四角形(A、B、C)の状態に なるのは行番号が偶数の時であり、赤枠の四角形(D、E、F)の状態になるのは行番号が奇数の時である。次に列番号に着目すると赤枠の四角形との関係が以下の数列になる。
1) A,Dの状態になる列番号:0, 3, 6, 9, 12, 15, 18, 21 => 列番号を3で割った余りが0
2) B,Eの状態になる列番号:1, 4, 7, 10, 13, 16, 19, 22 => 列番号を3で割った余りが1
3) C,Fの状態になる列番号:2, 5, 8, 11, 14, 17, 20, 23 => 列番号を3で割った余りが2
さらに赤枠の四角形A~Fに着目すると、赤枠の四角形BとEの検査するC点は一つ、以外は二つある事がわかるだろう。よって検査するC点は最大で2個になる。以上の条件から導き出したC点に ついて、P点とC点を結ぶ線分が六角形の各辺の直線と交差していないなら六角形のマスの中にあると判断する。 上記の考え方を具現化したソースが座標計算クラスだ。マウス押下時のC点とマウス移動時のC点の差が移動量となる。 background-position に移動量を加減算する事で、目出度く地図の移動ができた。